高并发写优化理论
对于高并发的读QPS优化手段较多,最经济简单的方式是上缓存。但是对于高并发写TPS该如何提升?业界常用的有分库分表、异步写入等技术手段。但是分库分表对于业务的改造十分巨大,涉及迁移数据的麻烦工作,不会作为常用的优化手段。异步写入到时经常在实际工作中使用,但是也不适合所有场景,特别对于带有事务的写入请求,带事务的写入请求通常是需要同步告知用户处理结果,所以不适用异步处理。
我们都知道批处理会比单条处理快很多,只需要发起一次网络请求,在网络层面节省了N次TCP连接获取和发送数据的步骤。实际我测试过,通过shark抓包,发现建立一条TCP连接可能需要耗费10ms~50ms左右。如果是跨洲际的TCP连接更久,可能耗费几百毫秒。单是节省的多次TCP连接就能节省不少时间,其次还有程序代码的循环执行时间。所以将多个写请求聚合成一个合适大小的批量写请求,一次性将数据发送给服务器进行批量写入是最高效的。
MySQL的组提交原理
在MySQL层面,为了保证事务的可靠性和数据同步给备节点、从节点的可靠性。通常会开启双一设置。在双一设置开启后,就会在事务提交前将redo log、binlog落盘,事务才返回成功,这就是WAL机制。
sync_binlog=1
innodb_flush_log_at_trx_commit=1
我们知道由于WAL机制,写入请求在修改了数据页后不会立即刷回磁盘,而是通过记录rodo log和binlog保证事务的持久性和同步给从节点。写rodo log和binlog就是顺序写入的,涉及磁盘的顺序写机制。磁盘顺序写会比随机写快很多。MySQL为了进一步提升多个事务在高并发下写入binlog的性能,采用了“组提交”的概念。顾名思义就是将多个事务在单位时间内聚集起来,一起写入磁盘,就变成了多事务的批量顺序写入,性能高很多。
这里简单介绍组提交。首先MySQL有2个参数控制组提交的等待时间和组大小。
binlog_group_commit_sync_delay=N:在等待N μs后,开始事务刷盘(图中Sync binlog)
binlog_group_commit_sync_no_delay_count=N:如果队列中的事务数达到N个,就忽视binlog_group_commit_sync_delay的设置,直接开始刷盘
解释下这张图。首先在第一步就已经将redo log刷到磁盘了,接下来就是将多个事务聚合在一个组调用write函数写入OS的缓冲。第一个到达的事务就会开启一个新组,等待N个事务到达或者等待N微秒之后主动提交。假设事务T1到达并开启新组1,等待T2来到加入组1,等待时间满后T1主动调用write函数将T1、T2事务都