黄东旭解析 TiDB 的核心优势
877
2023-04-03
分布式数据库集群介绍
自从谷歌提出分布式这个概念,这个玩意太火了,但是并不是所有的业务场景都适合用分布式的
什么场景适合用分布式架构?
其他业务都是有时间维度的,可能只需要存3个月的在线数据,算下来也就2kw,那为什么还要做分布式架构呢?
所以不要迷信分布式架构和分库分表
tips:单台服务器几千qps没必要分,两三万的话可以分
Ⅰ、分布式数据库特点
优点
可用性提高可扩展性提升(扯淡,MySQL现在4个节点扩8个节点怎么办?数据库不是redis,redis里面内存数据可以丢掉,甚至redis单线程的做这些都好弄,MySQL并不是,8扩12的话,原来的数据都要打散一遍,原来8个机器,hash8个,现在变12个,数据全部打散,如果8*500G,4T数据打散到12个节点,怎么打散,这么多表),MySQL可扩展性的提升是很难达到的,我们借助另外一些手段来做扩展性,为什么mongodb,redis,tidb扩展性是好的,因为他们的分片策略更好(也有缺点),是未来比较好的模式,但是在关系型数据库中很难实现,对MySQL内核和中间件的改造太大了某些情况下吞吐率提升显著 ---大大的问号,只有某些场景才会显著提升原来一台机器,拆成八台机器,那就性能提升八倍?这是不存在的
缺点
依赖中间件(不依赖中间件就要在业务层做),业界基本上找不到一个好的中间件,mycat可以用,但是生产上不建议SQL语句支持不足(中间件支持的sql非常有限,多表join,子查询,派生表这些估计玩不转,mongodb,redis,tidb不做这些)运维复杂度提高某些情况下性能下降巨大
Ⅱ、分布式数据库——shard
2.1 shard相关概念
A database shard is a horizontal partition(水平分区) of data in a database. Each individual partition is referred to as a shard or database shard. Each shard is held on a separete database server instance,to spread load.
sharding和分区的异同相同:打散数据不同:打散的数据可能不在同一实例上
总结:sharding的实现非常复杂
举个栗子orders表,根据日期做分区,每个月一张订单表,还是在一台MySQL上
做分片的话,把一张表,分到四台MySQL上去
在分区中:
partition by hash(id)
这个id叫做分区键
在shard中:把这个分区键叫作均衡字段把id 作hash,%4 来分到四个机器上,把date 作range也可以
如果根据order_key分了四个机器
select * from orders where order_key = ?
这样性能就提升了
怎么找到这个机器呢:
法1:业务层控制,根据分区规则搞,如果order_key是int类型,那就%4,根据结果下发到对应的Datanode(ip)法2:中间件,client不用关心后端的分库规则,均衡字段这些,client直接通过MySQL协议访问中间件,中间件自动帮你计算该访问哪个节点,sql的改写由中间件来做,像我们上面这个sql就不用改写,只要转一下ip就行
两个问题:
两种方法:哪个性能更好,为什么?法1更好,直接连数据库,法2多了一层,中间件的优势在于,开发人员更方便写代码,就和直接连数据库一样用,其他事情都交给中间件业务里面永远都是只有这么一个简单的需求嘛?如果根据其他字段查询呢?会有上面问题呢?那就所有的分片都要找一遍,你加N多个节点,这样还叫可扩展吗?节点越多,性能越差了都,和分区表的是一样的道理,orders_partition表中可以explain看下两种情况,走索引的话,1亿的数据量下,和1kw数据量下速度是一样的,你分十个片没什么意义
2.2 做shard的三个原则
尽可能大部分的业务逻辑都是根据均衡字段,至少百分之80%,更改分布式数据库中的均衡字段非常麻烦,必须一开始就规划号表的均衡字段如果不能选择有效的均衡字段,这张表就不要进行Shard,作为全局表如果业务选择不出有效率的均衡字段,那么进行分布式数据库的改造也将是徒劳的
tips:shard一般用hash打散,平均的,如果没有打散就是均衡字段没选好,可以选择用多个字段作均衡字段
2.3 看看别人的业务怎么选择均衡字段的
你平时怎么逛淘宝的?
点开淘宝,所有的查询都是买家查询,你能查你老婆买了哪些东西吗?所有的查询都是根据自己的id来查(登陆是通过用户中心来登陆的)
下单了,订单里有userid,订单明细中也有userid,登陆到淘宝,查最近一些订单信息,购买记录,也是根据userid来查的
所以电商的表结构设计,有张user表,用来存用户信息的,里面有个userid
又有一个orders表,订单表里面也有个userid
还有个orderline表,一个订单里下了多少个商品,里面也有个userid
可能还有个favorite表,里面也有一个userid
coupon表,还是有个userid
综上,所有买家的数据都有一个userid的字段,这时候 上面这些表就可以根据userid放到不同的shard中
这意味着什么呢?一个用户的所有信息是在一个分片上的,是不会跨分片的,不存在一个查询要查很多个分片的
所以淘宝的业务是非常容易做扩展的,只要加机器,把数据打散,就是可扩展的
所以对于电商的业务来说,有个非常好的维度叫买家维度,所有的查询基本上都是根据买家id
那网易云音乐的歌单又是怎么弄的呢?也是userid啊,哈哈,看自己的歌单,看别人的歌单,都是用的userid
快递行业用的是什么?运单号
上面所有的都要用中间件,一般用mycat
Ⅲ、分布式最大的问题——分布式事务
user<--->user<--->user 中间件 client
如果一台机器
begin;update user set money = money - 100 where userid = xxx;update user set money = money + 100 where userid = xxx;commit;
那走分布式事务的话,很有可能这两个userid不在同一个分片里面
这个事务就变成了分布式事务,首先,mycat不支持分布式事务,但是这么写是支持的
意味着着不是一个原子操作,变成了两个事务分到两个分片上去,做不到原子性,所以千万不要把mycat用在关键的业务,特别是跟钱打交道的
现在业界的中间件,除了淘宝和网易貌似还没有什么中间件支持分布式事务的,那怎么办呢?
分布式事务改为单个事务,之前提过的补偿机制,做一个message表,update的时候往message表中插入消息,另一张表,查看消息,然后update,最后把消息置为已接收
这时候还需要中间件吗?no!这也叫一种柔性事务
3.2 用户下单案例
orders表,三个分片,userid作均衡字段,还有个表,叫stock(库存)下单的逻辑就变得不一样了,看tpcc样例
begin;先锁定库存insert into ordersinsert into orderlineupdate stock set count = count - 1 where itemid = ?update...xxx...commit;
orders表分库分表了,stock表没有userid这东西,所以stock表叫全局表,我们该怎么放,可以放到单独的实例上,也可以放到其中的一个分片上,甚至可以根据skuid去做shard
每个MySQL是用来存分片的,但并不要求一个分布式集群中所有的表均衡字段是一样的,业务只要知道怎么存的就行,均衡字段是什么,怎么访问,自己知道就行,对于中间件来说有个元数据库来存这些均衡字段
这时候这个流程就是分布式的了,淘宝网易的中间件可以支持这个,如果stock做了分片就讨厌了,一个订单可以有很多件商品,很多个库存要修改,涉及的节点可能就多了,不像转账了,所以订单表放到消息队列(mq)中做了
要下单的话,先放到mq中,后面很多worker线程,拿到这个消息然后去消费
所以,现在打开京东,天猫这些,下一个单之后,状态显示为出库中,什么叫出库中?
出库中就表示,我现在这个下单,只是把业务逻辑丢到消息队列中,至于消息队列后面能不能成功并不知道,如果库存不够会告诉你出库失败,然后把你这个下单过程回滚掉
所以经常下单成功,出库失败,不是1111,一般都不会有问题,1111的时候就不一定了,实时库存代价太大了
3.3 小结
到现在为止,还用得着中间件嘛?不是可以不用,而是建议不用,因为用了中间件,你避免不了分布式事务,很多核心业务有风险的
根据userid来扩展,做查询没问题啊,但是对于数据库来说,分库分表最难的点在于事务化和持久化,而不是select,甚至select放到redis里都可以
分布式事务到最后都用了消息表和消息队列,业务逻辑都丢到消息里,后面消费线程慢慢消费,出错了,就回滚,关闭订单,订单表中有个状态字段,可见,不可见,成功,没成功,都是通过业务来控制的
用分布式事务的协调器来做的,淘宝最早提出tcc,现在基于这个封装了一堆东西了都
建议:如果分库分表,最好让业务控制,而不要用中间件,用了中间件这个活儿就是你的,说难听点,就是甩锅,以后出了问题就跟我没关系,第二点,核心业务,中间件不支持分布式事务,保证不了事务性和持久性,第三点,中间件性能真的不行,即使用了ddb,一个订单三个商品垮了好多个节点,双十一能接受吗?不要迷信中间件
但是,快递行业真的很适合中间件,因为快递行业没有很强的事务性要求,就是一个个运单,这个运单要周转几次,现在的中转状态,所以快递行业是中间件使用的最好的场景,如果互联网金融用了中间件,碰到了分布式事务就很也容易呵呵
Ⅳ、理解分库和分表呢
shard是一个标准的说法,但是分库分表根本没有完整的定义,很模糊
最早的时候:
分表:orders ---> orders00,orders01,,,,分库:db1,db2中都有orders00,orders01,当然也可以分到其他实例中的db中
这样表名改了,不好维护,网易的中间件就不支持分表,那就只分库吧,最好是同一个实例上建很多个不同的db,扩展起来不用打散数据
所以这里又有个淘宝的规范,一开始可能就会分1024个shard,不管多少个机器,一开始放在100个机器上,双十一放到1000个机器上,具体落到哪个shard还是用hash
不能2048个shard,MySQL数据库扩展是不做reshard的,重分布的代价太大,所以就拆,在一开始在同一个机器上做很多个shard
一开始就把shard就划好,扩展的时候不用每次都去打散数据,换句话说,这样做的是垂直扩展,虽然说分布式数据库可扩展,但是因为hash的扩展很麻烦,涉及到数据的重分布,所以尽量垂直扩展,数据打散水平打散,扩展的话垂直扩展
mongodb的扩展方便,是基于chunck的,先把所有的数据放到chunck里,如果超过32M会做split,拆成两个chunck,然后做一个balance的操作,把两个chunck放到两台服务器上,所以这个chunck是可以移动的,mysql的hash不可移动
mongodb的balance也有问题,牵涉到一台服务器的chunck拷贝到另一台服务器
各有优缺点,扩展方便,新加一台机器,可以把各个机器上的chunck移过来,不用hash那样整个集群的重分布,只拿一部分chunck过来,但是io会很大
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。