51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 1308|回复: 0

[原创文章] mycat实战分享(1)-单表超百亿每秒千兆流量的数据库集群

[复制链接]
  • TA的每日心情
    开心
    2019-10-10 16:07
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]测试小兵

    发表于 2019-10-18 16:14:37 | 显示全部楼层 |阅读模式
    前言:本人有幸接手了一个大项目的运维工作,项目前期发展非常快,其中尤以数据库的发展最为困难,目前大的单表都是在几十亿,最大的达到百亿,高峰时数据流量超1000Mbps。这里还是要首先感谢mycat社区提供的开源中间件,让我能够实现一个如此庞大的数据库。这期间我们踩了无数坑,对数据库架构进行了多次调整,mysql、redis更是优化再优化(redis集群20万qps以上,这个以后有时间再写个分享),巴不得榨干机器的所有性能。整个过程大多数时候都是困难重重,压力山大,但现在回头去看,一路收获很多。现在整理出来一方面是给自己回顾总结,重新思考,另一方面也是给大家做一个案例参考。(以下的图都是自己画的,平时画的少,所以很多图标我也搞不清楚应该用哪种形状)

    我现在整理的是这个项目的mysql数据库架构的一点点演变改进过程,每一步的演变其实都会涉及很多工作,比如数据迁移,拆分,程序修改等等。

    一、最初的架构:主从结构

          我进项目组的时候,项目已经刚起步,用户只有几万,服务器也就10台左右,其中mysql数据库只有2台,使用了最简单的一主一从结构。在我来之前使用的memory引擎,据说有一次机房停电,两台服务器全挂,数据全丢,于是改成了innodb引擎。我觉得应该感谢这次及时的停电,因为还是在项目之初,损失还能承受,如果在后面那是不可想象的。

    我来的第一步是给数据库最备份,然后是搭建了监控系统nagios和cacti,后来又增加了zabbix。有了基础的监控,后面问题才能及时发现,有性能数据我们才能找到瓶颈,知道优化方向。二、引进mycat,数据横向拆分
           最初用户发展非常快,数据量只能用暴增来形容,每天的高峰期数据库经常抗不住,直接导致业务不可用。每天的业务高峰时间非常集中(这个是业务特性,我们没有办法去左右用户的行为),这种不可用的时间可能就10分钟,但对业务这足够致命了。于是我们决定对数据库进行拆分,这期间我们测试分析了几种中间件,最后选择了mycat。也是架构开始演变成这样:

    因为已经是上线的业务,所以数据库的拆分即紧急重要,又需要非常小心,这不是我一个人的事情,还需要牵扯到开发的修改。这里必须要感谢下自己的老板能够支持并授权给我去做,事实上推进的过程还是踩了一些坑。这里可以跟大家分享下重点内容和我们遇到的问题:
    1、数据拆分规则
    这很重要,直接关系到所有数据的存储结构,程序修改,以及然后的扩展。数据拆分主要还是要按照业务逻辑来做,比如我们是按照用户来分,同一个用户的所有数据都在同一个分片上,小的配置表做全局表,这样可以避免跨库关联的问题。分片规则我们采用的是先分组再取模的方式,这样的好处是每次分片满了之后可以不用拆分老数据,新分片分布在新老多台服务器上,也可以进行压力均衡。
    2、自增序列带来的问题
    mycat社区和文档说明中有多种方法实现自增序列的管理,我们选择的是数据库存储过程的那种(这个可以去参考mycat文档),看起来似乎很完美,但我们还是要小心。
    首先我们是在已有单库的系统中演变过来的,所以要考虑一下同样是自增序列在程序中是怎么被使用的,这个还真得看看开发是怎么写的。
    举个例子:我们的分片规则主要按照用户id来分(用户表的主键,数值型,自增,所有用户相关数据表的关联外键),而用户实际使用的是账号(字符型,给用户用来登陆的,所以这个建了唯一索引)。对于用户是新用户还是老用户,我们的开发同事是这么写的:insert ...on duplicate key update ... ,直接插入这个账号到用户表中,如果已存在的直接返回来的id,如果不存在的则插入新的数据并获得新的id。单库下一点问题都没有,在分库中之后就是大问题,因为mycat的过程是先给了一个新的id,然后带着这个id去插入到数据库中,分片是按照id来分的,他很有可能是分到其他的分库上,最后插入成功。于是这个账号就有条2个用户记录。就上线了一会儿,我们清洗数据花了一个晚上。
    解决的方案:用户的账号必须是要保持唯一性的,这点绝对不可能让步。于是有人说先查询一次再插入,这其实还是不行的。只要你不做互斥,就有可能产生两条相同的账号。
    于是我给的方案是生成两张用户表,一张是全量表account_s,用来存放用户的账号,同时再生成一张分片的account_s_shard.程序必须先项account_s中插入,插入成功的才算新用户,并获得一个id,然后再插入一次到account_s_shard。

    三、引入redis缓存
    随着用户增长,并发量越来越高,即使拆分数据,依然还有很多问题
    1、账号到id的转换问题
    用户使用的是账号,数据库基本上关联表都用的是id,包括分库的规则也是id。
    这里就需要每次用户来使用的时候就必须被转换一次,实际上每个组件程序中都至少要查询一次。
    用户表已经被我们做了两张表account_s和account_s_shard,最初我们使用的是account_s_shard这个表,但是因为账号不是分片键,所以他会到每一个分库中执行一次。这个其实是非常厉害的。比如我们一个mysql实例上分10个分库,那么每一次查询在这个mysql上就会被放大10倍,总共100多个片库,就会放大100多倍。可想而知这个量是非常惊人的。

    在业务低谷时,我们单个mysql实例上只抓了5分钟左右的时间,就能看到接近200万次的查询。即使他的速度很快,高峰时他占的资源还是非常大。
    假设我们全部移到account_s上,但这个是单库,压力也会很大。
    所以我们最后还是决定引入redis缓存,在缓存中解决这个问题。
    2、流量集中,需要redis缓存进行削锋填谷
    每种业务都自己的业务特征,所以我们谈架构不能离开业务场景特性。我们的业务不能使用读写分离,因为程序间数据传递时间非常短,数据一点延时据有可能出现问题。另一个特征是是业务高峰非常集中在2个时间点,一个是早上9:20到10:00,这段时间是写入的高峰,下午14:50到15:10 ,这段时间是读的高峰,高峰值会一下子拉高几倍甚至十倍。
    我们当然可以按照最高的峰值进行预算扩容,但是扩容数据库是非常昂贵的,所以我们也需要通过redis进行缓存,一是写缓存,数据延后写入,另外就是读缓存,缓存热点数据。
    我们现在的架构就变成了这样:

    这一步的工作量还是非常大的,主要还是涉及到开发的程序,因为有部分数据在redis中进行了缓存,就意味着我们必须是redis+mysql合并才是完整的数据。读写都需要修改。redis与数据库之间的数据同步也是一个非常重要的步骤。


    四、mycat集群
    从上面的架构可以看到,mycat只有一台,在服务上也是非常容易成为瓶颈的。
    我们发现当数据量非常的查询语句时(比如我们要计算用户的排名,一次查询会产生大量的数据,我们要避免这样的大sql,但总是很难做到完全的预防),这个时候mycat会非常容易出现挂起,这个主要还是需要占用太多的内存。于是我们需要搞一个守护进程,这样万一挂起了能自动解决。
    而单一的mycat,在高并发的情况下不仅会成为瓶颈,而且单点存在也是非常危险的。
    于是我们还需要搭建一套mycat的集群。于是就出现了下面这个mycat的集群结构。

    一开始我们使用的是haproxy,但是haproxy很快就出现了问题,因为haproxy需要流量转发,于是haproxy就会成为瓶颈。如下图所示,我们在高峰期流量会超过千兆,直接把我们的千兆网卡打爆:

    当然我们可以多用几个haproxy,但这样就不能使用vip了,对应用程序我们就需要部署不同的ip,而且这样失去了高可用方案。所以我们把他改成了LVS方式,这样就不会让代理节点(入口)的流量打爆。
    也许有一天单个LVS也会被打满,那时候也许不得不多开几个入口了。
    五、mysql高可用方案
    架构基本上就是这样,keepalived+lvs+mycat 基本上实现了mycat这一层的高可用和负载均衡。单从架构上我们还没有说明mysql的高可用。mycat后面连接的每一个mysql实例,我们都需要建立高可用的方案。方案当然很多,我们选择的是mha方式。

    每一个mysql都是一主一从(我很希望能有2从,不过受限于服务器资源,我们现在普遍的都是一主一从),然后再做一个日志服务器。为防止检测中出现误判,采用2台应用服务器作为旁路检测。
    在数据库这一层,我们没有通过vip方式,这是因为vip方式需要使用相同的端口号,而我们mysql实例很多,从库很多都在一台服务器上,所以端口是没有办法统一的,所以采用vip方式不能满足我们的需求。
    mha在切换的时候调用的是我们自己的python程序:修改mycat配置,然后分发到各台mycat,重启生效。

    以上是整个架构改变的一个过程,这中间还涉及到无数的mysql调优,扩容,版本升级,数据迁移、拆分等等,另外也还有redis集群的调优(现在20万qps以上)。这些真是一言难尽。
    所以mysql数量多了之后,我们如何去管理的问题被提上日程。后面我们再分享一下管理。


    讲师作品: MySQL实战校园业务数据库:http://www.atstudy.com/course/2001







    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-3-29 15:10 , Processed in 0.069560 second(s), 25 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表