一、业务场景
一般在业务读多写少的场景,我们为了解决数据库IO瓶颈,可以考虑采用数据库读写分离,将写请求和读请求进行分开数据处理。
注意:主从不是主备。主从中的从服务器是要承担业务的,主备中备用服务器一般只做备份存在。
二、架构
一主多从的结构如下:
其中有个关键技术:主从复制。每次写入数据的时候,需要将主服务其数据复制到从服务器中,用以确保数据一致性。接下来以MySql为例:
slaver连接上master,启动复制,则会自身创建一个IO线程去向master拉取binlog的更新信息。
把拉取的binlog信息写到自己服务器的一个relay log日志文件中。
从数据库服务器创建一个SQL线程,是为了将relay log的所有日志信息,进行SQL回写到自己的数据库中,这样就和主库的数据同步了。
当master有数据更新的时候,比如新插入一条update数据,master会将这些数据更新到binlog二进制文件中,同时,master会创建一个binlog dump线程,这个线程将更新了binlog信息发送到slaver的IO线程。需注意,该过程是异步,如果等slaver接受完成,很慢,会影响性能。
小结:用主从后,slaver还可以作为备份数据库来使用,如果master突然故障了,可以防止数据丢失。但是不能一味的加slaver,过多的slaver会导致过多的IO线程,从而导致master承压,从而导致master写入数据慢,可能会卡死。一般生产环境一主三从就行了,最多不超过5个slaver。如果还不满足条件,可以采用其他方案,比如多级缓存。
三、主从延时
主从同步是有延迟的,一般都在ms级别,如果到了s级,可能影响业务,看是否能接受。如在支付系统创建订单后,风控系统会进入查询做出相应的风空操作,如果查不到就可能终止本次交易。
【优化】
可以在这些立马需要查的业务,直接查询主数据库。让它直接查主数据库,但该方案不推荐,因为量大怕会拖垮主数据。
当slaver读取不到数据,我们回去再读主数据,这样就可以读取到了。但是有风险,量大也会拖垮主库。
可以分重要性业务和非重要业务,将很核心的几个业务读写主数据库,其他非核心,读写分离。
使用缓存,将新增的数据同事添加一份缓存,然后查缓存数据,这种建议新增的数据使用缓存较好。
使用消息队列中间件进行消息冗余,将新的主数据库内容,通过消息中间件MQ冗余一份当前数据,然后发到需要查询的系统。
小结:在消息体不大的情况下,推荐使用第5种优化方案,需要消息中间件。其次考虑使用缓存,因为更新操作,需要更新缓存,也需要解决一致性问题,故新增数据,就首选缓存优化方案。最后,推荐重要性和非重要性隔离方案。最好不要使用都查主库操作。
四、优雅的使用读写分离
4.1、程序代码嵌入
代码嵌入,指通过我们在代码中开发出数据库访问中间层,由这个数据库访问中间层去访问不同的数据源,以实现读写分离和数据源的管理。参考淘宝开源TDDL(Taobao Distributed Data Layer),直接集成到代码,它自己管理读写分离和数据库配置。
特点:1、实现简单,可根据业务进行定制化开发。
2、语言不同,就得开发不同语言版本的数据库访问层。
4.2、部署独立代理层
部署代理层是指,在我们的业务服务器和数据库直接引入数据访问代理层,并不用自己写代码。现在为代表的开源中间件有阿里的MyCat、360的Atlas、美团的DBProxy等。这些都是使用标准的MySql通信协议。
特点:1、不用自己编写多余代码,使用方便。
2、sql语句会跨两层网络,性能稍微低一点。
4.3、小结
在自己公司没有比较成熟的中间件团队的话就用代码封装的方案,虽然写代码麻烦点,但是可以把控;要是公司有成熟的中间件团队,就可以考虑代理层部署的方案,因为需要有个团队要研究和长期维护这个代理层,才能确保业务正常发展,现在我们公司大部分都用的代理层方案,是有个专业团队来维护。