基本设计规范
设计规范
规则1:不建议在数据库中存储图片、文件等大型数据。此类数据建议存储到对象存储服务(OBS)或其他专门的文件存储服务。
规则2:单行key和value数据大小最大不能超过64KB,平均大小不超过10KB。
规则3:任何表的设计都要考虑数据删除策略,避免数据无限累积。
规则4:设计分区键以均匀分发工作负载,避免出现数据倾斜问题。
表的主键的分区键部分确定存储表数据的逻辑分区,如果分区键分布不均衡,会导致节点与节点之间数据和负载不均衡,从而出现数据倾斜的问题。
如表1为一些常见分区键分布均匀性的效果对比。
| 分区键值 | 分区键分布均匀性 |
|---|---|
| 用户 ID,应用程序中有许多用户。 | 好 |
| 状态代码,只有几个可用的状态代码。 | 差 |
| 项目创建日期,四舍五入至最近的时间段 (例如,天、小时或分钟)。 | 差 |
| 设备 ID,每个设备以相对类似的间隔访问数据。 | 好 |
| 设备 ID,被跟踪的设备有很多,但到现在为止,其中某个设备比其他所有设备更加常用。 | 差 |
如下为常见均匀分布分区键的设计方案
- 使用随机后缀分区
跨分区键空间更均匀分发负载的一种策略是将随机数字添加到分区键值的末尾。
例如:对于表示当天日期的分区键,可能会选择介于1和200之间的随机数并将它作为后缀连接到该日期。这将生成分区键值 (如2014-07-09.1、2014-07-09.2,以此类推,直到 2014-07-09.200)。由于随机化分区键,因此将跨多个分区均匀分布每天对表的写入,这将提高并行度和总体吞吐量。
但是要读取指定日期的所有项目,必须针对所有后缀查询项目,然后合并结果。例如:将先针对分区键值Query发布2014-07-09.1请求,然后再针对Query发布另一个2014-07-09.2,以此类推,直到2014-07-09.200。最后应用程序必须合并所有Query请求的结果。
- 使用计算得出的后缀分区
随机化策略可以显著提高写入吞吐量,但难以读取特定项目,因为不知道在写入项目时使用的是什么后缀值。要使各个项目的读取变得简单,可使用其他策略。不是使用随机数在分区间分发项目,而是使用可根据查询内容计算出的数字。
请考虑上述示例,其中表在分区键中使用当天日期。现在假设每个项目都有可访问的OrderId属性,并且除了日期,还最常需要按订单ID查找项目。在应用程序将项目写入表之前,它可根据订单ID计算得出一个哈希后缀并将此后缀追加到分区键日期。此计算可能生成一个介于1和200之间、分发甚是均匀的数字 (类似于随机策略所生成的数字)。
简单的计算可能已足够,如订单ID中字符的UTF-8码位值的积,取模200,+1。则分区键值是与计算结果连接的日期。
通过此策略,写入将在分区键值之间均匀分布,从而在物理分区之间均匀分布。可以轻松针对特殊项目和日期执行GetItem操作,因为可通过特定OrderId值计算出分区键值。
要读取指定日期的所有项目,仍必须Query每个2014-07-09.N键(其中,N为1~200),应用程序之后必须合并所有结果。好处是避免了一个“热点”分区键值占用所有工作负载。
规则5:合理设计分区key,均匀访问数据,避免出现大key或者热key问题。
- 大key问题:大key的产生,最主要的原因是主键设计不合理,使得单个分区的记录数或数据量过大。一旦某一个分区出现极大时,对该分区的访问,会造成分区所在服务器的负载变高,甚至造成节点内存溢出(即OOM)等。
- 热key问题:在业务场景中,经常会发生各种热门事件,如热点新闻的高频访问、热门商品促销、网红直播等场景,会在短时间内对同一个key产生大量访问请求,导致该key所在节点的CPU和负载升高,进而影响该节点负责的其他请求的成功率。
如何处理大key和热key问题请参见如何检测和解决大key与热key问题。
另外,对GeminiDB Cassandra数据库的读能力有更高要求的,读多写少的场景,可以考虑把热点数据缓存到GeminiDB Redis接口。
规则6:单个分区键的行数不能超过10万,单个分区磁盘空间不超过100MB。
- 单个分区键的行数不能超过10万。
- 单个分区键下记录大小不能超过100MB。
规则7:所有写入GeminiDB Cassandra的数据,提供数据副本强一致性,但是不支持事务。
| 一致性类型 | 是否支持一致性 | 说明 |
|---|---|---|
| 并发写一致性 | 支持 | GeminiDB Cassandra不支持事务,数据写入强一致。 |
| 表之间一致性 | 支持 | GeminiDB Cassandra不支持事务,数据写入强一致。 |
| 数据迁移一致性 | 最终一致性 | 采用DRS迁移提供数据抽样对比验证能力。业务自己完成迁移时,需要业务自行完成迁移前后数据校验。 |
规则8:大规模存储要重点考虑数据库拆分。
GeminiDB Cassandra整个集群的节点数建议控制在50以内,超过50节点要考虑拆分。拆分方式:
- 垂直拆分:按功能模块拆分(如订单库、商品库、用户库),适用于不同业务模块数据隔离的场景。
- 水平拆分:将同一表的数据分块保存到不同数据库,适用于单表数据量过大的场景。
规则9:设计上避免大面积删除导致的墓碑问题。
- 尽量使用TTL代替Delete操作。
- 不要出现大面积删除数据,尽量通过主键删除。
- 单个分区键内一次范围删除所包含行数不超过1000。
- 范围查询避免查询已删除数据。
- 不推荐在单个分区内频繁做范围删除。
设计建议
建议1:合理控制数据库规模和数量。
- 建议单表数据量不超过500亿。
- 建议单库不超过100个表。
- 建议单表字段数上限控制在20~50个。
建议2:提前进行资源估算。资源估算需要考虑以下因素:
- 数据总量:未来可预知的的数据增长
- QPS峰值:预估高峰期内读写请求总数
建议在评估基础上冗余N/2个节点,保证故障场景下性能一致。正常业务压力下每个节点CPU使用率建议控制在50%以下。
建议3:大规模GeminiDB Cassandra存储要考虑基于业务场景做数据库性能测试。
对于请求量、数据量比较大的业务场景,需要提前做性能摸底,原因是业务读写比例和随机访问模式以及不同的规格实例,性能差异较大。
建议4:数据库集群拆分粒度要合适。
- 分布式场景,考虑节约资源费用和维护成本,一个服务内部各个微服务可以共用一个GeminiDB Cassandra集群。
- 服务内部,根据数据重要程度、表数量和单表记录数,可进一步拆分成不同集群。
建议5:避免单条数据部分字段频繁更新。
建议6:List、Map、Set等嵌套类型,当元素超过一定数量,会影响读取性能,建议当元素过多时,采用转换成JSON字符串的形式进行存储。