第一种:磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的IO,降低查询速度 -> 分库和垂直分表。
第二种:网络IO瓶颈,请求的数据太多,网络带宽不够 -> 分库。
第一种:SQL问题,如SQL中包含join,group by,order by,非索引字段条件查询等,增加CPU运算的操作 -> SQL优化,建立合适的索引,在业务Service层进行业务计算。
第二种:单表数据量太大,查询时扫描的行太多,SQL效率低,CPU率先出现瓶颈 -> 水平分表。
经测试在单表1000万条记录一下,写入读取性能是比较好的。再留点buffer,那么单表全是数据字型的保持在800万条记录以下, 有字符型的单表保持在500万以下。
如果按100库100表来规划,如用户业务:500万 x 100 x 100 = 5000000万 = 500亿记录。
(1)划分:以字段为依据,按照一定策略(hash、range等),将一个库/表中的数据拆分到多个库/表中。
(2)使用场景:库多了,io和cpu的压力自然可以成倍缓解;单表数据量少了,单次SQL执行效率高,减轻了CPU的负担。
划分:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。
使用场景:公用的配置表、字典表等越来越多,这时可以将这些表拆到单独的库中,甚至可以服务化。
划分:以字段为依据,按照字段的活跃性,将表中字段拆到不同的表(主表和扩展表)中。
使用场景:将热点数据(可能会冗余经常一起查询的数据)放在一起作为主表,非热点数据放在一起作为扩展表。减少了随机读IO;注意分表后,要想获得全部数据就需要关联两个表来取数据,记住千万别用join,因为join不仅会增加CPU负担并且会讲两个表耦合在一起(必须在一个数据库实例上)。关联数据,应该在业务Service层做文章,分别获取主表和扩展表数据然后用关联字段关联得到全部数据。
sharding-sphere:jar,前身是sharding-jdbc;
TDDL:jar,Taobao Distribute Data Layer;
Mycat:中间件。
根据容量(当前容量和增长量)评估分库或分表个数 -> 选key(均匀)-> 分表规则(hash或range等)-> 执行(一般双写)-> 扩容问题(尽量减少数据的移动)。
基于水平分库分表,拆分策略为常用的hash法。
(1)映射法
(2)基因法
注:写入时,基因法生成user_id,如图。关于xbit基因,例如要分8张表,23=8,故x取3,即3bit基因。根据user_id查询时可直接取模路由到对应的分库或分表。根据user_name查询时,先通过user_name_code生成函数生成user_name_code再对其取模路由到对应的分库或分表。id生成常用snowflake算法。
映射法
冗余法
注:按照order_id或buyer_id查询时路由到db_o_buyer库中,按照seller_id查询时路由到db_o_seller库中。
NoSQL法
冗余法
基于水平分库分表,拆分策略为常用的hash法。解决方法是用NoSQL法解决(ES等)。
基于水平分库分表,拆分策略为常用的hash法。
水平扩容库(升级从库法),注:扩容是成倍的。
水平扩容表(双写迁移法)
第一步:(同步双写)修改应用配置和代码,加上双写,部署;第二步:(同步双写)将老库中的老数据复制到新库中;第三步:(同步双写)以老库为准校对新库中的老数据;第四步:(同步双写)修改应用配置和代码,去掉双写,部署;注:双写是通用方案。
分库分表,首先得知道瓶颈在哪里,然后才能合理地拆分(分库还是分表?水平还是垂直?分几个?)。且不可为了分库分表而拆分。
选key很重要,既要考虑到拆分均匀,也要考虑到非partition key的查询。
只要能满足需求,拆分规则越简单越好。
分库分表的git示例
转自:分库分表方案