照我风格,总是喜欢聊一下让人觉得废话连篇的前言语句, 但由于最近工作和家庭的事情实在太忙,tm身心疲惫,今后也尽量少嘚嘚,直接抛开话题。
话说我个人一直都想往架构方面转,认为自己运维、运维开发、底层开发、业务开发都做过,微观和大局观总是高人一等,但事实往往不是这样子。 贪多不烂, 艺多不精是我现在的问题。 没招,只能慢慢搬砖打磨自己。
现在每天都在花时间总结自己以往的经验及新的知识点的扩展学习,总之一直在学习在进步中。 前段时间在社区的朋友,让我讲讲 mysql分库分表及高可用集群方面的经验。 虽然我个人是有项目的分库分表经验,但业务类型会跟大家不一样的, 我尽量把场景覆盖的全面一些。
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新.
下面我们会一个个的分析实际mysql分库分表中遇到的一些场景问题。 可能有些论点显得有些不合时宜,请大家指点。
如果在业务上需要强一致性,就算有主从环境:
第一. 直接强一致性, 业务读写都在Master上.
优点, 开发简单. 缺点, 性能呀, slave只能做备机了.
第二. 主从不一致时,可以通过中间件时间窗口解决,比如某个 id 被改了, 我可以在中间层做个标记,应用从中间件访问时碰到id被修改了,那么走主。 ( 当然不单单可用 id 做标记)
多个冗余表入库场景:
( 多个冗余表的意思是,为了解决某个多维度分表的问题 )
第一 不加事物,单纯同步阻塞的方式写两个表.
缺点, 首先是性能的问题,其次是中间宕机, 那么其他的冗余表没法入库。
第二 使用分布式二次提交的方法 ( 2pc , 3pc) 保证入库.
缺点, 开发的逻辑有些麻烦,需要维护多个事物。
第三 消息写入,消息校验.
纯异步,性能没的说,靠不靠谱就要看消息队列的ha能力了。
除了那种支付金融业务,其余的场景, 这一二三都可以用的,那么缺数据怎么办? 我们可以写个定时服务脚本来修复多表的一致修复.
如果涉及到关键数据,推荐使用分布式事物2pc, 3pc, 更高端的消息系统事物的解决方法。 如果想多了解2pc的实现,可以翻找下我以前的博客。
业务数据缓存问题:
(还是数据不一样问题,这次跟上面主从类似,缓存数据不够新)
第一 当写请求处理时, 缓存可以同步或异步方法刷新. 也就是说,当数据改变时,才会去被动更新.
第二 缓存强制超时, 不会因为hit命中缓存而延续时间, 脏数据存在时间是有限制的.
第三 写密集时,可以适当用sorted set延迟5s 执行.
数据分表之后的分布式分页查询问题:
(因为热点及增删改过大的问题, 采用了hash分区. 但这样子之后,鬼知道数据跑哪里去了)
第一 如果是hash分的,业务上对于精度又不在乎,比如 limit 100 的需求, 我们可以分别在五个表进行 limit 20,各搜 20个.
第二 对于数据精准度较高标准做法是 跨库表查询,在中间层聚合重排序缓存。 当然这样消耗性能 ! !!
第三 除了第一次请求使用limit n,后面的请求都附带上次最大的id, 优化后的语句是 where id > last_id limit n .
对于经常分页查询的数据,还是尽量减少使用hash的方式. 互联网95%的流量都是读流量,过大的读请求可以使用从集群解决。 但对于上述的那种DML性能瓶颈问题, 咱们可以使用 分组+ 分片的方式进行, 我后面会好好的陈述下这种分表结构的优缺点。
分库分表之前的一些努力 ? 不白扯 !
第一, 结合explain和慢查询,优化你的sql和索引;
第二, 应用级别可以加缓存, redis,memcached,aerospike都可以;
第三, 如果查询的量级过大,就要做主从复制或主主复制,读写分离,可以在应用层或者mysql中间层实现;
第四, 垂直拆分,根据你的业务情况把热点的表拆出分库分表;
第五, 终极绝招,水平切分 ! 选定一个sharding key, 进行分库分表 !
中间其实可以在加一个步骤,就是hhd vs ssd的升级 !!!提升硬件的效果是相当喜人的,一个200 iops 和 几万的iops …
另外单表尽量控制到 一千万左右, 单库的表尽量控制在500左右.
mysql解决性能的路数一般都是按照这个步骤去演化的,成本也是由低到高; 除非你们觉得数据后期会暴增,那么可以一起进行 !!!
为什么我们要分库分表?
有种种的原因,希望大家为了良心,不让后人因为这瓶颈问题而被人嘴上伺候爹妈了. 一般来说原因不外乎就这么几种?
第一, 分库分实例后绝对好维护.
第二, 数据量大,时常会锁,检索数据慢,维护也是个坑
第三, 因抗拒数据不一致,流量都在master, 导致单master压力过大.
第四, 就是写大.
第五, 肯定还有…
这几个原因总结就一句话,不好维护,性能太渣.
如何选择分库分表的方案
第一种 , 范围分表.
这个范围你可以是id范围,也可以是时间等等。 他的优点是开发比较简单, 但缺点也能想到,就是数据的热点过于集中,相对别的区间数据是否均匀也是个问题. range分表总之各有利弊吧,主要还是看业务。
第二种, hash取模分表.
这一种相对公平的分表方式,md5(xxx) % 8 , 但他的缺点就是扩容是相当的麻烦的,要重新简单迁移数据。
第三种, range范围 + hash
可以想成raid10的磁盘阵列算法,他的优点是为了解决第一种方法中 单区间分表 热点的问题. 我们可以把某个区间进行再次hash到N个表.
第四种,一致性hash分表
这个适合的场景很多,但偏向于数据多的场景,想怎么扩展就怎么扩展。 sid = md5(xxx) % 5000 ; [{‘range’: (0,512), ‘master_db’: ‘xxx’}, {‘range’: (513: 1024)} … …]
对于那种论坛新闻性质的需求,他有新帖跟老帖之分的, 比如好几年的帖子很少有人关注了,你可以做一些归档处理,所谓的归档就是存起来就行了,不求性能. 像这类明显有新老破旧之分的分表需求,你可以使用range分区,或者range + hash.
对于那种量级大,又要保证读写性能的需求,可以使用hash取摸分表 和 一致性hash分表. hash mode是一定程度上的随机性. 那么量级大又怎么一回事? 看下面 !
其实跟dba的朋友聊了很多,对于不可估量的分库分表,一开始就要选择好后期可扩容的架构. 尤其对于那种不可控的业务暴增场景,一开始就要给他上多分库多分表.
以前在乐视的时候,经常有人跑到我工位周边的dba问”将来”扩容的问题,首席dba工程师都会强硬给你建立512个表,或者1024个表… 对于有mysql中间件的公司,不管分多少库表,跟你做业务的都没啥大关系….
这里额外提一句,在分库分表的场景下,尽量要用mysql的中间件 ! 我想当大家到了那种量级,自然也能搞的定。 那么我为什么会推荐大家使用mysql 中间件 ? 如果你是程序控制连接池,那么每次更新db config要反复上线。当然你可以说 用zookeeper做了配置管理,那么当你的应用得到zookeeper更新时,你该如何调整现有的连接池 ? 对于那种跨库join的sql语句,你需要同步模式一个个的遍历结果,然后聚合return ? 等等… 现在互联网公司在分库分表面前,大多会选择 mysql 代理的. 当然代理的性能瓶颈肯定是有的. 现在市面上还没有特别可靠的mysql proxy,只能找个模子二次开发了。
这里我做个广告,代理方面建议大家用下 陈非同学的kingshard. 这哥们当初360安全搞atlas proxy的时候,我就认识他了,靠谱小哥…. 有时间我会专门抽出几个章节来聊聊 mysql proxy那些事,不单单是成名的中间件,因为当初看过kingshard的源码,正好顺带讲点设计实现原理…
END … …
干货 介绍下mysql各种中间件吧