我对Cassandra(2.1.11)和Spark(1.4.1)都很陌生,并且有兴趣知道是否有人使用Spark Streaming看到/开发了针对两个不同Cassandra表的原子写入的解决方案。
我目前有两个表,它们拥有相同的数据集,但具有不同的分区键。为简单起见,我将使用熟悉的User表示例来解释:
CREATE TABLE schema1.user_by_user_id
(
user_id uuid
,email_address text
,num int //a value that is frequently updated
,PRIMARY KEY (user_id)
);
CREATE TABLE schema1.user_by_email_address
(
email_address text
,user_id uuid
,num int //a value that is frequently updated
,PRIMARY KEY (email_address)
);
email_address
列将具有高基数(实际上它将在user_id
值的数量的50%到100%之间)。高基数使得二级索引表现不佳,因此需要第二个表。
我使用Spark Streaming处理num
列中的更改并更新这两个表。根据我的理解,saveToCassandra()
方法在UNLOGGED BATCH中为RDD中的每个项执行写入,从而执行原子写入(如"保存对象集合"部分{{3中所述) }})。但是,saveToCassandra()
只能用于保存到单个表。为了使schema1.user_by_user_id
和schema1.user_by_email_address
表保持同步,我必须发出两个单独的saveToCassandra()
个调用:
rdd.saveToCassandra("schema1","user_by_user_id",SomeColumns("user_id","email"address","num"))
rdd.saveToCassandra("schema1","user_by_email_address",SomeColumns("user_id","email"address","num"))
每次调用中的写入都是以原子方式完成的,但这两个调用并不是原子的。第二次调用中的某些错误会使两个表不同步。
显然我的数据集和实际的表结构比这更复杂,但我试图以尽可能简单的方式传达我的问题的要点。虽然我的问题是为了能够保存到两个表格,但我欢迎任何有关数据模型更改的替代建议,这将完全消除这种需求。
答案 0 :(得分:1)
首先要理解的是: UNLOGGED 批次不原子。见documentation。 UNLOGGED 批次的唯一功能就是能够使用相同的时间戳进行多次写入。
因此,如果您要对saveToCassandra
进行多次调用并让它们表现得就像是一次通话一样,只需specify the WRITETIME两次通话。完成所有操作后,所有修改后的数据都将具有相同的时间戳。
关于如何对多个表进行原子更新的问题......你不能这样做。卡桑德拉不支持它。
我能想到的最好的建议是创建自己的批量日志,您可以在崩溃后查询,以找出需要重新同步的内容。
想象一下这样的事情:
CREATE TABLE batch_log
(
id uuid,
updated_users set<uuid>,
PRIMARY KEY(id)
)
开始工作时,生成一个新的uuid,它将成为此工作的ID。然后,您发出3次保存:
rdd.saveToCassandra("schema1", "batch_log", SomeColumns("batch_id", "user_id" append)
rdd.saveToCassandra("schema1","user_by_user_id",SomeColumns("user_id","email"address","num"))
rdd.saveToCassandra("schema1","user_by_email_address",SomeColumns("user_id","email"address","num"))
如果您的批处理完成而没有任何崩溃,您只需删除已创建的batch_log
行。
但是,如果系统中途崩溃,那么一旦事情重新联机,您可以咨询batch_log
以获取已更新的用户列表。去查询这些用户的电子邮件地址,然后更新user_by_email_address
表。完成此修复后,您可以删除batch_log
。
实际上,您正在实施&#34;手工&#34;一个Cassandra LOGGED BATCH。