当前位置: 首页 > 科技观察

我是如何一步步让公司的MySQL支持数十亿流量的?

时间:2023-03-16 10:43:59 科技观察

1主从读写分离互联网服务大多是读多写少,所以优先考虑DB如何支持更多的查询。首先,需要区分读写流量,方便读流量单独扩展,即Master-slave读写分离。如果前端流量突然增加导致从库负载过高,DBA会优先扩容从库,这样对DB的读流量就会落到多个从库上,并且每个从库的负载都会降低,然后开发再在DB层尽量阻断流量。缓存V.SMySQL读写分离由于开发和维护的难度,引入缓存会引入复杂性。必须考虑缓存数据一致性、穿透、防雪崩等问题,多维护一类组件。所以建议优先使用读写分离,实在忍不住再使用Cache。1.1核心主从读写分离一般将一个DB的数据复制一份或多份,写入其他DB服务器:原DB为主库,负责数据写入,复制目标DB为被复制的目标DB从数据库,负责数据查询所以,主从读写分离的关键:数据复制就是主从复制。屏蔽了主从分离带来的访问DB的变化,让开发者感觉还是在使用单一的DB2主从复制。MySQL的主从复制依赖于binlog。即记录MySQL上的所有变化,并以二进制形式保存在磁盘上,作为二进制日志文件。主从复制是将binlog中的数据从主库传输到从库,一般是异步的:主库操作不会等待binlog同步完成。2.1主从复制的过程当连接到主??节点时,从库会创建一个I/O线程请求主库更新的binlog,并将收到的binlog写入relaylog文件,主库还会创建一个logdump线程,将binlog发送到从库。从库也会创建SQL线程,读取relaylog,在从库回放,最终实现主从一致性。使用独立的logdump线程是异步的,避免影响主库的更新过程,而从库收到信息后并不将信息写入从库的存储中,而是写入一个relaylog。这是为了避免写入从库的实际存储。长的。主从异步复制过程的图是基于性能的考虑。主从写入过程不会等待主从同步完成才返回结果。极端情况下,比如master库上的binlog还没来得及放到磁盘上,磁盘坏了或者机器掉电了,导致binlog丢失,主从数据不一致。但是概率很低,可以接受。主库宕机后,由于binlog丢失导致的主从数据不一致,只能手动恢复。主从复制后,可以:写的时候只写主库,读数据的时候只从从库读,这样即使写请求会锁表或者锁记录,也不会影响到读请求的执行。高并发下,可以部署多个从库来分担读流量,即一主多从支持高并发读。从库也可以作为备库使用,避免主库故障导致数据丢失。从库的无限增加能否支持更高的并发?不!从库越多,从库连接的I/O线程越多,主库也必须创建相同数量的logdump线程来处理复制请求。对于主库的资源消耗比较高,同时受到主库网络带宽的限制,所以一般一个主库最多可以挂3到5个从库。2.2主从复制的副作用比如发朋友圈的操作,有数据:同步操作比如更新DB异步操作比如把朋友圈的内容同步到审计系统所以更新主库后,朋友圈ID会被写入MQ,Consumer根据ID从库中获取朋友圈信息,然后发送给评论系统。这时候如果主从DB有延迟,就无法从从库获取朋友圈信息,就会出现异常!主从延迟对业务的影响示意图2.3如何避免主从复制延迟?其实解决办法有很多。核心思想是尽量不要从数据库中查询数据。因此,针对以上情况,有如下解决方案:2.3.1数据冗余在发送MQ时,不仅发送朋友圈ID,还发送消费者需要的所有朋友圈信息,避免从客户端重新查询数据DB。推荐该方案,因为它足够简单,但可能会导致单条消息变大,从而增加消息发送的带宽和时间。2.3.2使用Cache将朋友圈数据写入Cache,同时同步写入DB。这样消费者在获取朋友圈信息时,会先查询Cache,这样也可以保证数据的一致性。该方案适用于新增数据的场景。在更新数据的场景下,先更新Cache可能会导致数据不一致。比如两个线程同时更新数据:线程A更新Cache数据为1,另一个线程B更新Cache数据为2,然后线程B更新DB数据为2,线程A再更新DB数据为1,最终的DB值(1)和Cache值(2)不一致!2.3.3查询主库在Consumer中可以查询主库而不是从库。使用时要谨慎,保证查询的量级不要太大,在主库可以接受的范围内,否则会对主库造成较大的压力。除非绝对必要,否则不要使用此解决方案。因为需要提供查询主库的接口,所以很难保证别人不会滥用这个方法。排查时主从同步延迟也很容易忽略。有时候你会遇到无法从DB获取信息的怪问题,你会怀疑代码中是不是有什么逻辑删除了之前写入的内容,但是你查询的时候发现又可以读取数据了一段时间后,这基本上是主从延迟问题。因此,从数据库的滞后时间一般作为DB的关键指标进行监控和告警。正常时间是ms级别,达到s级别就会报警。主从延迟时间预警,如何通过哪个数据库的哪个索引来判断?从库中,通过监控showslavestatus\G命令输出的Seconds_Behind_Master参数的值,判断是否存在主从延时。这个参数值就是这样一个差值,通过比较sql_thread执行的事件的时间戳和io_thread复制的事件的时间戳(简称ts)。但是,如果复制同步主库bin_log日志的io_thread线程负载过高,Seconds_Behind_Master会一直为0,即无法预警。通过Seconds_Behind_Master的值来判断延迟不够准确。其实也可以对比一下master和slave的binlog位置。3如何访问DB使用主从复制将数据复制到多个节点,也实现了DB的读写分离。这时候DB的使用也发生了变化:以前只用一个DB地址,现在需要一个主库地址,多个从库地址,并且需要区分写操作和查询操作,结合“分库分表”,复杂度大大提高。为了降低实现的复杂度,业界出现了很多DB中间件来解决DB的访问问题,大致可以分为:3.1应用内部,比如TDDL(淘宝分布式数据层),它以代码的形式嵌入到应用程序中运行。可以看作是一个数据源代理。它的配置管理多个数据源,每个数据源对应一个DB,可以是主库也可以是从库。当有DB请求时,中间件将SQL语句发送到指定的数据源,然后返回处理结果。优点是简单易用,部署成本低,因为嵌入到应用中,与程序一起运行,适合运维薄弱的小团队。缺点是缺乏多语言支持,都是用Java语言开发的,不能支持其他语言。版本升级也取决于用户的更新。3.2独立部署Mycat、Atlas、DBProxy等代理层方案。此类中间件部署在独立的服务器上。业务代码就像使用单个数据库。事实上,它在内部管理着许多数据源。当有DB请求时,会根据需要改写SQL语句,发送到指定的数据源。.优点一般采用标准的MySQL通信协议,支持多语言独立部署,便于维护升级,适合有运维能力的大中型团队。缺点所有的SQL语句都需要跨越两次网络:从应用程序到代理层和从代理层到数据源,在性能上会有一些损失。4小结主从复制可以扩展为在存储节点之间复制存储数据的技术,可以实现数据冗余实现备份,提高水平扩展能力。使用主从复制时,需要考虑:主从一致性和写入性能之间的平衡。如果保证所有slave节点都写成功,会影响写性能;可能会出现数据同步失败,导致master和slave不一致。对于互联网项目,性能一般优先于数据的强一致性。主从延迟会导致很多无法读取数据的奇怪问题。业界也有很多实际应用案例:Redis通过主从复制实现读写分离,索引分片也可以复制到多个节点写入HDFS,文件也会复制到多个DataNode。不同的组件对复制的一致性和延迟有不同的要求,采用不同的方案,但设计思路是相同的。如果FAQ中有大量订单,可以通过userIdhash发送到不同的数据库,有利于前端用户订单查询,但后台系统页面需要查看所有订单并进行排序,以及SQL执行很慢。我应该怎么办?由于后台系统无法直接查询分库分表的数据,考虑将数据同步到单独的后台库或者同步到ES。本文转载自微信公众号「JavaEdge」,可通过以下二维码关注。转载本文请联系JavaEdge公众号。