切分策略
切分维度的选择是决定分布式数据最重要的一个权衡性因素,需要审慎选择,一般而言,可以按照以下五个维度进行思考和权衡,包括数据均衡度考虑、事务边界因素、常用查询效率考虑、切片索引考虑、简单性策略。
容量和访问均衡
数据容量和访问均衡是我们考量的第一点,不均衡的数据分布和访问无法充分发挥数据拆分的能力,让访问体验变差,同时带来成本上的损耗。所以一般来说拆分字段区分度比较大,数据分布和访问相对会比较均衡,但是这点也需要考虑到某一个拆分值是否有热点的问题。
事务边界
事务边界越大(或者单个sql所执行的数据分片数),那么系统的锁冲突概率越高,系统越难以扩展,性能越低。因此,若想将系统做到很好的扩展性,那么一个最重要的原则就是想办法划小事务边界,并尽可能让事务的边界限制在单台机器内。缩小事务边界的方式。
常用查询
对于常用查询优化的核心要义,就是尽可能让您的一次前端请求,物理上直接发送到一台存储的机器上,尽可能避免那些需要将请求下发到多台机器的查询。下发到多台机器的查询,虽然每次查询的延迟不会出现问题,但这类查询会导致一次请求物理上必须被发送到很大一批存储的机器上,会额外占用过多下层数据节点的各类的资源,因此应该尽可能的予以避免。
切片索引
对常用的非分片键查询条件构建切片索引,提升非分片键查询(select语句)时的效率,避免广播查询。
保持简单
如果查询优化与均衡读写访问两个选项发生了冲突,那么请选择均衡读写访问作为优先考虑原则,因为查询的问题相对的更好解决,无论是加机器做全表扫描或做切片索引都是可以解决的。而写入或单机容量如果出现不均衡,处理起来难度就比较大。
尽管复杂的切分规则或取巧的程序代码能够带来短期系统性能或成本上的好处,但其后面所带来的系统运维复杂度上升将会吃掉之前您在系统中获得的大部分好处。因此,从系统架构上来说,以82法则,简单直接处理的方式往往是最有效的方式。
切分原则
分表分库虽然能解决大表对数据库系统的压力,但它并不是万能的,也有一些不利之处,因此首要问题为:分不分库,分哪些库,什么规则分,分多少分片。
原则一
分片数量尽量少,分片尽量均匀分布在多个DataHost 上,因为一个查询SQL 跨分片越多,则总体性能越差,虽然要好于所有数据在一个分片的结果,只在必要的时候进行扩容,增加分片数量。
原则二
能不分片就不分片,800万以内的表,不建议分片,通过合适的索引,读写分离等方式,可以很好的解决性能问题。
原则三
不到800 万但跟大表(超800 万的表)有关联查询的表也要拆分,在此称为大表关联表。大表关联表如何拆:小于100 万的使用全局表;大于100 万小于800 万跟大表使用同样的拆分策略;无法跟大表使用相同规则的,可以考虑从java 代码上分步骤查询,不用关联查询,或者破例使用全局表。
原则四
破例的全局表(例如item_sku 表250万行数据),跟大表关联了,又无法跟大表使用相同拆分策略,也做成了全局表。破例的全局表必须满足的条件:没有太激烈的并发update,如多线程同时update 同一条id=1 的记录。虽有多线程update,但不是操作同一行记录的不在此列。多线程update 全局表的同一行记录会死锁,批量insert 没问题。
原则五
拆分字段只能是一个字段,如果想按照两个字段拆分,必须新建一个冗余字段,冗余字段的值使用两个字段的值拼接而成(如大区+年月拼成zone_yyyymm 字段)。
原则六
分片规则需要慎重选择,分片规则的选择,需要考虑数据的增长模式,数据的访问模式,分片关联性问题,分片扩容问题以及数据热点问题。
原则七
分片规则的选择问题,如果某个表的数据有明显的时间特征,比如订单、交易记录等,则他们通常比较合适用时间范围分片,因为具有时效性的数据,我们往往关注其近期的数据,查询条件中往往带有时间字段进行过滤,比较好的方案是,当前活跃的数据,采用跨度比较短的时间段进行分片,而历史性的数据,则采用比较长的跨度存储。总体上来说,分片的选择是取决于最频繁查询SQL 的条件。