一、高性能数据库简介
1.高性能数据库方式
读写分离:将访问压力分散到集群中的多个节点,没有分散存储压力
分库分表:既可以分散访问压力,又可以分散存储压力
2.为啥不用表分区
- 如果SQL不走分区键,很容易出现全表锁;
- 在分区表实施关联查询,就是一个灾难;
- 分库分表,自己掌控业务场景与访问模式,可控;分区表,工程师写了一个SQL,自己无法确定MySQL是怎么玩的,不可控;
二、读写分离——提升数据库读性能
可以缓解订单系统、账户系统、购物车系统等等功能mysql的并发压力
读写分离的基本原理是将数据库的读写操作分散到不同的节点
1.读写分离的基本实现
数据库服务器搭建主从集群,一主一从、或者一主多从,数据库主机负责读写操作,从机只负责读操作。数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据。业务服务器将写操作发给数据库主机,将读操作发给数据库从机。
需要注意的是,这里用的是“主从集群”,而不是“主备集群”。“从机”的“从”可以理解为“仆从”,仆从是要帮主人干活的,“从机”是需要提供读数据的功能的;而“备机”一般被认为仅仅提供备份功能,不提供访问功能。
2.读写分离引起的复杂性
(1)复制延迟
一般会把从库落后的时间作为一个重点的数据库指标做监控和报警,正常的时间是在毫秒级别,一旦落后的时间达到了秒级别就需要告警了。
以 MySQL 为例,主从复制延迟可能达到 1 秒,如果有大量数据同步,延迟 1 分钟也是有可能的。主从复制延迟会带来一个问题:如果业务服务器将数据写入到数据库主服务器后立刻(1 秒内)进行读取,此时读操作访问的是从机,主机还没有将数据复制过来,到从机读取数据是读不到最新数据的,业务上就可能出现问题。解决主从复制延迟有几种常见的方法:
- 写操作后的读操作指定发给数据库主服务器(缓存标记法)。例如,注册账号完成后,登录时读取账号的读操作也发给数据库主服务器。这种方式和业务强绑定,对业务的侵入和影响较大,如果哪个新来的程序员不知道这样写代码,就会导致一个 bug。可以利用一个缓存记录必须读主的数据。当写请求发生时:
-
- 写主库
- 将哪个库,哪个表,哪个主键三个信息拼装一个key设置到cache里,这条记录的超时时间,设置为“主从同步时延”
- 查询时:
-
-
- cache里有这个key,说明1s内刚发生过写请求,数据库主从同步可能还没有完成,此时就应该去主库查询
- cache里没有这个key,说明最近没有发生过写请求,此时就可以去从库查询
-
- 读从机失败后再读一次主机。这就是通常所说的“二次读取”,二次读取和业务无绑定,只需要对底层数据库访问的 API 进行封装即可,实现代价较小,不足之处在于如果有很多二次读取,将大大增加主机的读操作压力。
- 关键业务读写操作全部指向主机,非关键业务采用读写分离。例如,对于一个用户管理系统来说,注册 + 登录的业务读写操作全部访问主机,用户的介绍、爱好、等级等业务,可以采用读写分离,因为即使用户改了自己的自我介绍,在查询时却看到了自我介绍还是旧的,业务影响与不能登录相比就小很多,还可以忍受。
- 写操作完成后,跳转到无关页面,类似订单支付的“支付完成”页面,其实这个页面没有任何有效的信息,就是告诉你支付成功,然后再放一些广告什么的。你如果想再看刚刚支付完成的订单,需要手动点一下,这样就很好地规避了主从同步延迟的问题。
(2)分配机制
将读写操作区分开来,然后访问不同的数据库服务器,一般有两种方式:程序代码封装和中间件封装。由于数据库中间件的复杂度要比程序代码封装高出一个数量级,一般情况下建议采用程序语言封装的方式,或者使用成熟的开源数据库中间件。
- 程序代码封装。程序代码封装指在代码中抽象一个数据访问层,实现读写操作分离和数据库服务器连接的管理。
- 中间件封装。中间件封装指的是独立一套系统出来,实现读写操作分离和数据库服务器连接的管理。对于业务服务器来说,访问中间件和访问数据库没有区别。中间件需要支持多种编程语言,因为数据库中间件对业务服务器提供的是标准 SQL 接口。数据库中间件要支持完整的 SQL 语法和数据库服务器的协议(例如,MySQL 客户端和服务器的连接协议),实现比较复杂,细节特别多,很容易出现 bug,需要较长的时间才能稳定。数据库中间件自己不执行真正的读写操作,但所有的数据库操作请求都要经过中间件,中间件的性能要求也很高。
(3)区分连接池
- 数据库连接池需要区分:读连接池,写连接池
- 如果要保证读高可用,读连接池要实现故障自动转移
3.从库的数量
是不是无限制地增加从库的数量就可以抵抗大量的并发呢?实际上并不是的。因为随着从库数量增加,从库连接上来的 IO 线程比较多,主库也需要创建同样多的 log dump 线程来处理复制的请求,对于主库资源消耗比较高,同时受限于主库的网络带 宽,所以在实际使用中,一般一个主库最多挂 3~5 个从库。