1.6 异步提交

在事务提交时,需要保证该事务产生的WAL必须被刷入磁盘,虽然多个事务中的各种操作是交叉执行的,但WAL按照各种操作的顺序产生,这样做的好处是将事务的随机写转换成Append形式的顺序写,避免随机刷页面导致性能下降。通常需要在事务提交时调用XLogFlush函数来保证事务日志落盘,否则,无法保证事务的持久性,一些数据可能会丢失。

如果能够放宽事务持久性的要求,可以允许丢失一些数据,只要能够保证一致性即可,那么就可以尝试异步提交事务,不必等待事务日志完全落盘,这样可以提高事务提交的性能。

如果事务自己不保证将WAL落盘,那么由谁来保证呢?答案是WalWriter后台进程。这个进程会定时启动,将WAL刷入磁盘,图1-18展示了WalWriter与事务提交之间的关系。事务在提交时会通过XLogSetAsyncXactLSN函数设置本事务相关WAL的终点,只有当WalWriter将XLogSetAsyncXactLSN函数设置的LSN之前的WAL全部刷入磁盘,才能保证这个事务真正提交。

当对一个元组做可见性判断时,会为这个元组设置Hint Bits。例如,如果可见性检查发现产生这个元组的事务已经提交,那么就会在元组上设置HEAP_XMIN_COMMITTED标记。当下次访问这个元组时,就不用去clog中查看事务是否提交,而是直接通过HEAP_XMIN_COMMITTED标记来判断。

图1-18 WalWriter与事务提交之间的关系

但异步提交并不是真正的提交,在事务日志被刷入磁盘之前,这种标记位不应该被设置,而应该在clog中查看事务的提交状态。这就要求我们在设置Hint Bits时,判断这个事务的日志是否已经落盘,也就是说要记录这个事务的“最终LSN”。

PostgreSQL目前为每32个事务记录一个LSN,这个LSN是这32个事务中最新的LSN,这样就形成了一个针对最新LSN的LSN GROUP。

在事务做异步提交时,需要同时将事务的最终LSN作为参数传递进来,并且记录到事务对应的LSN group中。

在设置元组的Hint Bits时,需要检查最终LSN,如果还没有落盘,则不设置元组的Hint Bits。