本文记录的是京东某次大促前夕一次线上系统的问题,从问题入手,引发的对系统稳定性因素的思考及总结。“千里之堤毁于蚁穴“,如何发现系统中”蚁穴“是系统开发者不断追求的目标。
方法异常线上报警,定位日志,空指针异常,查询数据库结果为空,定位此业务线查询从库,数据库正常,查询结果正常,初步确定是主从延迟。问题在几秒钟恢复,影响次数个位数,接下来几个月数次出现此问题,直到11.11备战第一天延迟更加严重了。
定位是主从同步延迟的问题,查看从库的机器情况及慢日志。从库执行大量的删除某表记录操作,性能非常差。再看其执行语句,发现没有索引,再看下主库这张表上有这个索引。这种情况下为什么出现主从延迟高呢?
在这里简单介绍下MySQL主从同步原理。
MySQL主从复制需要三个线程,master(binlog dump thread)、slave(I/O thread 、SQL thread)。
1、master
binlog dump线程:当主库中有数据更新时,那么主库就会根据按照设置的binlog格式,将此次更新的事件类型写入到主库的binlog文件中,此时主库会创建log dump线程通知slave有数据更新,当I/O线程请求日志内容时,会将此时的binlog名称和当前更新的位置同时传给slave的I/O线程。
2、slave
I/O线程:该线程会连接到master,向log dump线程请求一份指定binlog文件位置的副本,并将请求回来的binlog存到本地的relay log中,relay log和binlog日志一样也是记录了数据更新的事件,它也是按照递增后缀名的方式,产生多个relay log( hostname-relay-bin.000001)文件,slave会使用一个index文件( hostname-relay-bin.index)来追踪当前正在使用的relay log文件。
SQL线程:该线程检测到relay log有更新后,会读取并在本地做redo操作,将发生在主库的事件在本地重新执行一遍,来保证主从数据同步。此外,如果一个relay log文件中的全部事件都执行完毕,那么SQL线程会自动将该relay log 文件删除掉。
下面是整个复制过程的原理图:
结合以上的MySQL主从同步原理,导致这次线上问题的原因已经出来了,其实慢SQL只是原因的表象,更加深层次的原因是从库 SQL thread顺序执行Relay log的事件。执行任意事件性能不好会带来主从的高延迟。
从库建立索引,降低主从延迟性,对线上业务影响无感知。
系统架构情况如下:
为了减少数据库主库的压力,每条业务线都有自己从库,目前京东数据库的情况是1主8从。如果主从延迟非常高,最明显的影响就是每条业务线的读延迟,依赖读的业务都会有问题。
主从延迟是影响系统稳定性的因素之一。如何降低主从延迟减少其对系统的影响?业界减少主从延迟方案有多种下面简单介绍几种:
- 服务的基础架构在业务和MySQL之间加入memcache或者Redis的cache层。降低MySQL的读压力
- 使用比主库更好的硬件设备作为slave
- sync_binlog在slave端设置为0
- –logs-slave-updates 从服务器从主服务器接收到的更新不记入它的二进制日志
- 禁用slave的binlog
作者:顾家慧,京东商城JAVA开发工程师。开源爱好者,对常用开源框架,热爱技术,有丰富的大型分布式系统、高并发、高可用系统的开发经验。