为什么快速 VPN 仍会拖慢同步 SQL 提交
提交会离开这栋建筑,落到同步副本上。从等待类型一路看到发送队列与 redo 队列,再判断异步是否是正确的取舍。
在主库上打开一个查询会话,看看一次普通的写入在等什么。如果数据库属于采用同步提交的可用性组,且辅助副本已连接,那么其中一部分等待会离开这栋建筑:日志记录传到副本,在那里完成硬化,硬化的消息在提交结束前返回。带宽并不会缩短这次往返。下面的过程从屏幕出发,一直跟到远端磁盘,再回到原处。
从主库上的等待类型入手
在远端副本上等待的写入会表现为与日志相关的等待,而不是 CPU 或锁等待;事务的持续时间跟着往返走,而不是跟着行数走。大量小提交会把这一点放大,因为每一次都要单独付一次往返的代价。一次批量操作则把同样的代价藏进一次更长的确认里。
在对链路下任何结论之前,先按提交频率给工作负载排序。
先读副本状态,再读网络。要紧的计数器是发送队列、redo 队列和同步状态,它们合起来说明辅助副本是在跟上还是在落后。发送队列增长指向传输,redo 队列增长则指向辅助副本自身的工作或存储。这是两种不同的修法,加带宽对哪一种都没有帮助。
跟随确认一路走到辅助副本
在同步提交下,主库要等到相关日志在辅助副本上完成硬化的确认,才会报告提交完成。硬化指的是在日志中持久,而不是重放到数据页里。正是这个区别,解释了一个同步辅助副本为何会在 redo 上落后,却仍在确认硬化。
按顺序走一遍路径,逐段计时,而不是只测总时间。日志记录经过传输,辅助副本写入并刷盘,确认再沿原路返回。传输时延、辅助副本的调度以及辅助副本日志磁盘的延迟,都计入总时长,而只有第一项属于网络负责人。若辅助副本的日志量被别的东西占满,即使链路闲着,每一次提交也会被拉长。
SELECT ag.name AS ag_name, drs.database_id, drs.synchronization_state_desc,
drs.log_send_queue_size, drs.redo_queue_size
FROM sys.dm_hadr_database_replica_states AS drs
JOIN sys.availability_groups AS ag ON ag.group_id = drs.group_id;在一笔有代表性的写入之前和之后各取一次这样的快照,而不是在安静的下午取一次。正是差值告诉你,提交等待期间是哪条队列在动。
测量路径,而不是链路
吞吐测试量的是两个并非你的副本的点之间的容量,负载也不是你的工作负载。请网络负责人在真实流量运行时,沿真实的副本路径测量双向的时延与丢包。这里丢包比容量更重要,因为丢一个段就要重传,而每一次提交都在等一个确认。下载测试里表现优异的链路,仍可能不适合话多的提交模式。
测量时保持数据库传输安全与访问控制原样不动。测量路径从来不是绕过它们的理由。
把时间与计数器对应起来,而不是凭直觉。如果发送队列一直是空的,而提交仍在等待,那么延迟在确认或辅助副本的刷盘上。如果发送队列持续增长,那么瓶颈是传输或容量。记下是哪条观察支持了这个结论,好让下一个人重复测量,而不是重复争论。
异步模式究竟改变了什么
异步提交去掉了等待辅助副本硬化确认这一步,所以写入变快,所以你的持久性位置也变了。主库在没有远端确认的情况下确认事务。辅助副本于是被允许落后,而这段落后就是暴露。
如果主库在日志到达可用的故障转移目标之前就丢失,强行把服务切到那个副本,会丢掉那些已经告知应用程序提交成功的事务。
这是恢复点决策,属于数据库负责人,而不属于性能评审。先设定可容忍的数据丢失窗口,再选择满足它的模式,然后在这个边界内优化。保留同步保护的做法包括:在应用允许处去掉可以避免的提交往返,修掉测出的传输或存储瓶颈,以及把副本挪近,让确认走更短的路。拿它们和你一开始的持久性要求权衡,而那个要求并没有变。