编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

08 | 数据库优化方案(一):查询请求增加时,如何做主从分离?

wxchong 2024-11-23 23:35:15 开源技术 15 ℃ 0 评论


上节课,我们用池化技术解决了数据库连接复用的问题,这时,你的电商系统虽然整体架构上没有变化,但是和数据库的交互过程有了变化,在你的工程和数据库之间增加了连接池,减少了创建成本,现在的架构如下图:

此时你的数据库还是单机部署,根据一些云厂商提供数据,在4c8G的机器上运行MySQL5.7时,大概可以支撑500的tp和1000qps。这是公司打算参与双十一活动,这无疑回个查询带来巨大的流量,显然现有的架构是不能满足的。那么数据库层面怎么来做主从分离呢?

主从读写分离

其实大多数系统的访问模型是读多写少,读写请求量的差距可以达到几个数量级。

这很好理解,朋友圈的阅读量肯定比朋友圈的发表要多,淘宝上一个商品的浏览器也肯定要大于它的下单量,因此数据库优先考虑如何抵抗住更大的查询请求,那么首先要把读写分离开,这样可以针对单独的读请求进行扩容,这就是我们说的主从读写分离。

主从读写的两个技术关键点

一般来说主从读写分离机制中,我们将一个数据库的数据拷贝或者备份到其他数据库服务器中,原始的数据库我们称为主库,主要负责数据的写入,拷贝的数据库成为从库 负责数据的查询支持。可以看出 主从数据库技术上有两个关键点:

一个是数据的拷贝,我们成为主从复制。二是 主从分离如何屏蔽使用上的 差异。

主从复制我先以 MySQL 为例介绍一下主从复制。

MySQL的主从复制依赖binglog,就是记录MySQL所有数据变化的二进制文件,保存在磁盘上的。主从的复制就是把Biglog从主库同步到从库,这个过程一般是异步的。即主库不会等待同步的完成。

主从复制的过程大概这样:首先从库在链接到主库时候会创建一个IO线程,用以请求主库更新的Biglog,并且把接受的binglog信息写入一个叫做relay log 的日志文件中,而主库也会创建一个log dump 线程来发送日志给从库;同时从库还会创建一个sql线程读取relay Log中的内容,并且在从库中做回放,最终实现主从的一致性。这是常见的主从复制模式。

在这个方案中,主库的 Log dump 线程是异步的,可以避免对主库的整体流程产生影响;从库的binlog日志首先写入relay log 中,因为数据的实际存储比较耗时的过程,所以采取异步读取再写入,避免带来更大的延迟。

这里存在的问题就是,主库的日志是异步先落入本地磁盘的,如果这个过程出现问题,就会导致变更日志的丢失,从而导致主从数据的不一致。但是这个概率是很小的,互联网项目中可以接受。

做了主从复制之后,这样主库负责写入数据,从库负责读取数据,即使写操作出现锁表也不影响从库的读取操作。这样在流量比较大时,可以部署多个从库来提高系统的查询能力,这就是所为的一主多从。另外从库也可以当做备份使用,避免主库的宕机。

那么问题来了,我是不是可以无限制的增加从库呢?从而增加系统的并发查询能力呢?不是的,因为增加一个从库,主库需要增加一个Log dump 线程,对于主库的资源消耗比较高,同时受制于主库的网络带宽,实际使用中一般一个主库挂 3~5个从库为最佳。

当然主从同步,也会有一些缺陷,最大的问题就是主从同步的延迟。也是我们排查问题时候容易忽略的地方。一般我们会把主从数据的延迟做一些监控告警。正常的延迟应该在毫秒级别,超过这个数量级就应该告警了。

如何访问数据

数据已经通过主从复制到了多个节点,也实现了读写的分离,这时对数据库的使用方式就发生了变化。以前只需要使用一个数据库地址就好了,现在还需要使用一个主库,多个从库。并且需要区分写入操作和查询操作。为了降低业务的复杂度业界提供了很多数据库中间件来解决数据库的访问问题,这些中间件可以大致分为两类:

第一类以淘宝的 TDDL( Taobao Distributed Data Layer)为代表,以代码形式内嵌运行在应用程序内部。你可以把它看成是一种数据源的代理,它的配置管理着多个数据源,每个数据源对应一个数据库,可能是主库,可能是从库。当有一个数据库请求时,中间件将 SQL 语句发给某一个指定的数据源来处理,然后将处理结果返回。

这一类中间件的优点是简单易用,没有多余的部署成本,因为它是植入到应用程序内部,与应用程序一同运行的,所以比较适合运维能力较弱的小团队使用;缺点是缺乏多语言的支持,目前业界这一类的主流方案除了 TDDL,还有早期的网易 DDB,它们都是 Java 语言开发的,无法支持其他的语言。另外,版本升级也依赖使用方更新,比较困难。

另一类是单独部署的代理层方案,这一类方案代表比较多,如早期阿里巴巴开源的 Cobar,基于 Cobar 开发出来的 Mycat,360 开源的 Atlas,美团开源的基于 Atlas 开发的 DBProxy 等等。

这一类中间件部署在独立的服务器上,业务代码如同在使用单一数据库一样使用它,实际上它内部管理着很多的数据源,当有数据库请求时,它会对 SQL 语句做必要的改写,然后发往指定的数据源。

它一般使用标准的 MySQL 通信协议,所以可以很好地支持多语言。由于它是独立部署的,所以也比较方便进行维护升级,比较适合有一定运维能力的大中型团队使用。它的缺陷是所有的 SQL 语句都需要跨两次网络:从应用到代理层和从代理层到数据源,所以在性能上会有一些损耗。

其实,我们可以把主从复制引申为存储节点之间互相复制存储数据的技术,它可以实现数据的冗余,以达到备份和提升横向扩展能力的作用。在使用主从复制这个技术点时,你一般会考虑两个问题:

主从的一致性和写入性能的权衡,如果你要保证所有从节点都写入成功,那么写入性能一定会受影响;如果你只写入主节点就返回成功,那么从节点就有可能出现数据同步失败的情况,从而造成主从不一致,而在互联网的项目中,我们一般会优先考虑性能而不是数据的强一致性。

我们采用的很多组件都会使用到这个技术,比如,Redis 也是通过主从复制实现读写分离;Elasticsearch 中存储的索引分片也可以被复制到多个节点中;写入到 HDFS 中文件也会被复制到多个 DataNode 中。只是不同的组件对于复制的一致性、延迟要求不同,采用的方案也不同。但是这种设计的思想是通用的,是你需要了解的,这样你在学习其他存储组件的时候就能够触类旁通了。



Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表