数据库还是单机部署,依据一些云厂商的 Benchmark 的结果,在 4 核 8G 的机器上运 MySQL 5.7 时,大概可以支撑 500 的 TPS 和 10000 的 QPS。这时,运营负责人说正在准备双十一活动,并且公司层面会继续投入资金在全渠道进行推广,这无疑会引发查询量骤然增加的问题。当查询请求增加时,我们应该如何做来解决问题?答案是主从读写分离。
大部分系统的访问模型是读多写少,读写请求量的差距可能达到几个数量级。比如购物网站上一个商品的浏览量也肯定远大于它的下单量。
数据库如何抗住更高的查询请求,那么首先你需要把读写流量区分开,因为这样才方便针对读流量做单独的扩展。它其实是个流量分离的问题,就好比道路交通管制一样,一个四车道的大马路划出三个车道给领导外宾通过,另外一个车道给我们使用,优先保证领导先行,就是这个道理。这个方法本身是一种常规的做法,即使在一个大的项目中,它也是一个应对数据库突发读流量的有效方法。
流量突增导致从库负载过高的问题,可以优先做几个从库扩容上去,这样对数据库的读流量就会落入到多个从库上,其他的从库的负载就降了下来。
主从读写分离有两个技术上的关键点:
首先从库在连接到主节点时会创建一个 IO 线程,把接收到的 binlog 信息写入一个叫做 relay log 的日志文件中,而主库也会创建一个 log dump 线程来发送 binlog 给从库;同时,从库还会创建一个 SQL 线程读取 relay log 中的内容,并且在从库中做回放,最终实现主从的一致性。
这里面涉及到三个线程:
基于性能的考虑,可以选择异步复制。数据不一致这种情况出现的概率很低,对于互联网的项目来说是可以容忍的。
是不是我无限制地增加从库的数量就可以抵抗大量的并发呢?
实际上并不是的。因为随着从库数量增加,从库连接上来的 IO 线程比较多,主库也需要创建同样多的log dump 线程来处理复制的请求,对于主库资源消耗比较高,同时受限于主库的网络带宽,所以在实际使用中,一般一个主库最多挂 3~5 个从库。
阿里云的集群从节点最多4个:集群版RDS实例的优势及应用场景_云数据库 RDS-阿里云帮助中心。
在发微博的过程中会有些同步的操作,像是更新数据库的操作,也有一些异步的操作,比如说将微博的信息同步给审核系统,所以我们在更新完主库之后,会将微博的 ID 写入消息队列,再由队列处理机依据 ID 在从库中获取微博信息再发送给审核系统。此时如果主从数据库存在延迟,会导致在从库中获取不到微博信息,整个流程会出现异常。
解决核心思想就是尽量不去从库中查询信息。
发送消息队列时不仅仅发送微博 ID,而是发送队列处理机需要的所有微博信息,借此避免从数据库中重新查询数据。
在同步写数据库的同时,也把微博的数据写入到redis缓存里面,这样队列处理机在获取微博信息的时候会优先查询缓存,这样也可以保证数据的一致性。
在队列处理机中不查询从库而改为查询主库。不过,这种方式使用起来要慎重,要明确查询的量级不会很大,是在主库的可承受范围之内,否则会对主库造成比较大的压力。
下面都是以问题为例提供解决方案,具体业务需要具体分析。方案推荐使用数据的冗余。
参考文章: