我是 Cassandra 的新手,正在寻找关于如何对具有以下一般结构的数据进行建模的最佳实践:
数据是基于“用户”的(每个客户),每个都提供大约 500K-2M 条目的大数据文件(每天定期更新几次 - 有时完全更新,有时只有增量)
每个数据文件都有某些强制性数据字段(约 20 个强制性),但可以自行决定添加其他列(最多约 100 个)。
不同用户的附加数据字段不一定相同(字段名称或这些字段的类型)
示例(csv 格式:)
user_id_1.csv
| column1 (unique key per user_id) | column2 | column3 | ... | column10 | additionalColumn1 | ...additionalColumn_n |
|-----------------------------------|-----------|----------|---------|------------|---------------------|------------------------|
| user_id_1_key_1 | value | value | value | value | ... | value |
| user_id_1_key_2 | .... | .... | .... | .... | ... | ... |
| .... | ... | ... | ... | ... | ... | ... |
| user_id_1_key_2Million | .... | .... | .... | .... | ... | ... |
user_id_XXX.csv (notice that the first 10 columns are identical to the other users but the additional columns are different - both the names and their types)
| column1 (unique key per user_id) | column2 | column3 | ... | column10 | additionalColumn1 (different types than user_id_1 and others) | ...additional_column_x |
|-----------------------------------------------------------|-----------|----------|---------|------------|-----------------------------------------------------------------|-------------------------|
| user_id_XXX_key_1 | value | value | value | value | ... | value |
| user_id_XXX_key_2 | .... | .... | .... | .... | ... | ... |
| .... | ... | ... | ... | ... | ... | ... |
| user_id_XXX_key_500_thousand (less rows than other user) | .... | .... | .... | .... | ... | ... |
我考虑过的几个选项:
选项1:
- 创建一个“全局”键空间
- 创建一个包含所有内容的大表“数据”
将 user_id 列连接到大表的所有其他列(包括非强制列)。主键变为 user_id + "column_1"(column_1 每个 user_id 都是唯一的)
Keyspace +--------------------------------------------------------------------------+ | | | | | Data_Table | | + +--------+-------+--------------------------+-----+ | | | | | | | | | | | +-------------------------------------------------+ | | | | | | | | | | many rows | +-------------------------------------------------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Many columns | | | | | | | +------------------------> | | | | | | | | | | | | | +-------------------------------------------------+ | | v +-------------------------------------------------+ | | | +--------------------------------------------------------------------------+
我马上注意到的几件事:
- user_id 重复的次数与每个用户的条目一样多
- 附加列(空值)的行非常稀疏,因为用户不一定共享它们
- 用户数量相对较少,因此附加列的数量并不多(最多 10K 列)
- 我可以将每个用户的附加列数据压缩为一个名为“元数据”的列,并为所有用户共享
选项 2:
为每个 User_id 创建 Keyspace
每个键空间创建表“数据”
+-----------------------------------------------------------------------------------+
| column_1 | column_2 | ... | column_n | additional_column_1 | additional_column_n |
+-----------------------------------------------------------------------------------+
keyspace_user1 keyspace_user2 keyspace_user_n
+----------------+ +---------------+ +---------------+
| | | | | |
| | | | | |
| +-+-+--+-+ | | +-+--+--+ | | +--+--+---+ |
| | | | | | | | | | | | | many keyspaces | | | | | |
| | | | | | | | | | | | | +-------------> | | | | | |
| | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | |
| +--------+ | | +-------+ | | +---------+ |
+----------------+ +---------------+ +---------------+
笔记:
- 许多键空间(每个用户的键空间)
- 避免为每行添加“user_id”值(我可以使用键空间名称作为用户 ID)
- 每个键空间的表很少(在此示例中,每个键空间只有 1 个表)
选项 3:
1)创建一个全局键空间 2)为每个 user_id 创建一个表(强制列以及每个表的附加列)
+---------------------------------------------------------------+
| Keyspace |
| |
| user_1 user_2 user_n |
| +--+---+--+ +--+--+--+ +--+--+--+ |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| +--+---+--+ +--+--+--+ +--+--+--+ |
| |
| |
+---------------------------------------------------------------+
笔记
- 全局键空间
- 每个 user_id 一个表(“许多”表)
- 避免每行重复用户 ID
选项4:(这有意义吗?)
创建多个键空间(例如“x”个键空间),每个键空间包含一系列表(每个用户的表)
keyspace_1 keyspace_x
+---------------------------------------------------------------+ +---------------------------------------------------------------+
| | | |
| | | |
| user_1 user_2 user_n/x | | user_n-x user_n-x+1 user_n |
| +--+---+--+ +--+--+--+ +--+--+--+ | | +--+------+ +--+--+--+ +--+--+--+ |
| | | | | | | | | | | | | | "X" keyspaces | | | | | | | | | | | | | |
| | | | | | | | | | | | | | +---------------------> | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| +--+---+--+ +--+--+--+ +--+--+--+ | | +--+---+--+ +--+--+--+ +--+--+--+ |
| | | |
| | | |
+---------------------------------------------------------------+ +---------------------------------------------------------------+
笔记:
- 多个键空间
- 每个用户多个表
- 需要“查找”来确定哪个键空间包含所需的表
选项 5:
将数据拆分到多个表和多个键空间
注意:1.在某些情况下需要从多个表中“加入”信息2.似乎更复杂
所有场景的一般说明:
- 写入比读取少一个数量级
- 每天数百万次阅读
- 每个 user_id 的流量波动 - 一些 user_id 的流量很大,而一些 user_id 的流量要少得多。需要根据这个指标进行调整
- 一些 user_id 的更新(写入)比其他的更频繁
- 我们在不同地区拥有多个数据中心,应该同步
- 每个主键都有一个长尾(一些键被多次访问,而另一些键很少被访问)