openGauss源码解析(82)

openGauss源码解析:事务机制源码解析(13)

5.3.6 基于鲲鹏服务器的性能优化

本章着重介绍openGauss基于硬件结构的锁相关的函数及结构体的性能优化。

1. WAL Group inset优化

数据库redo日志缓存系统指的是数据库redo日志持久化的写缓存,数据库redo日志落盘之前会写入到日志缓存中再写到磁盘进行持久化。日志缓存的写入效率是决定数据库整体吞吐量的主要因素,而各个线程之间写日志时为了保证日志顺序写存在锁争抢,锁的争抢就成为了性能的主要瓶颈点。openGauss针对鲲鹏服务器ARM CPU的特点,通过group的方式进行日志的插入,减少锁的争抢,提升WAL日志的插入效率,从而提升整个数据库的吞吐性能。group的方式主要流程如图5-20所示。

图5-20 group的方式日志插入

(1) 不需要所有线程都竞争锁。
(2) 在同一时间窗口所有线程在争抢锁之前先加入到一个group中,第一个加入group的线程作为leader。通过CAS原子操作来实现队列的管理。
(3) leader线程代表整个group去争抢锁。group中的其他线程(follower)开始睡眠,等待leader唤醒。
(4) 争抢到锁后,leader线程将group里的所有线程想要插入的日志遍历一遍得到需要空间总大小。leader线程只执行一次reserve space操作。
(5) leader线程将group中所有线程想要写入的日志都写入到日志缓冲区中。
(6) 释放锁,唤醒所有follower线程。
(7) follower线程由于需要写入的日志已经被leader写入,不需要再争抢锁,直接进入后续流程。

关键函数代码如下:

static XLogRecPtr XLogInsertRecordGroup(XLogRecData* rdata, XLogRecPtr fpw_lsn)

{

…/* 初始化变量以及简单校验 */

START_CRIT_SECTION(); /* 开启临界区 */

proc->xlogGroupMember = true;

proc->xlogGroupDoPageWrites = &t_thrd.xlog_cxt.doPageWrites;

nextidx = pg_atomic_read_u32(&t_thrd.shemem_ptr_cxt.LocalGroupWALInsertLocks[groupnum].l.xlogGroupFirst);

while (true) {

pg_atomic_write_u32(&proc->xlogGroupNext, nextidx); /* 将上一个成员记录到proc结构体中 */

/* 防止ARM乱序:保证所有前面的写操作都可见 */

pg_write_barrier();

if (pg_atomic_compare_exchange_u32(&t_thrd.shemem_ptr_cxt.LocalGroupWALInsertLocks[groupnum].l.xlogGroupFirst,

&nextidx,

(uint32)proc->pgprocno)) {

break;

} /* 这一步原子操作获取上一个成员的proc no,如果是invalid,说明是leader。 */

}

/* 非leader成员不去获取WAL Insert锁,仅仅进行等待,直到被leader唤醒 */

if (nextidx != INVALID_PGPROCNO) {

int extraWaits = 0;

for (;;) {

/* 充当读屏障 */

PGSemaphoreLock(&proc->sem, false);

/* 充当读屏障 */

pg_memory_barrier();

if (!proc->xlogGroupMember) {

break;

}

extraWaits++;

}

while (extraWaits-- > 0) {

PGSemaphoreUnlock(&proc->sem);

}

END_CRIT_SECTION();

return proc->xlogGroupReturntRecPtr;

}

/* leader成员持有锁 */

WALInsertLockAcquire();

/* 计算每个成员线程的xlog record size */

/* leader线程将所有成员线程的xlog record插入到缓冲区 */

while (nextidx != INVALID_PGPROCNO) {

localProc = g_instance.proc_base_all_procs[nextidx];

if (unlikely(localProc->xlogGroupIsFPW)) {

nextidx = pg_atomic_read_u32(&localProc->xlogGroupNext);

localProc->xlogGroupIsFPW = false;

continue;

}

XLogInsertRecordNolock(localProc->xlogGrouprdata,

localProc,

XLogBytePosToRecPtr(StartBytePos),

XLogBytePosToEndRecPtr(

StartBytePos + MAXALIGN(((XLogRecord*)(localProc->xlogGrouprdata->data))->xl_tot_len)),

XLogBytePosToRecPtr(PrevBytePos));

PrevBytePos = StartBytePos;

StartBytePos += MAXALIGN(((XLogRecord*)(localProc->xlogGrouprdata->data))->xl_tot_len);

nextidx = pg_atomic_read_u32(&localProc->xlogGroupNext);

}

WALInsertLockRelease(); /* 完成工作放锁并唤醒所有成员线程 */

while (wakeidx != INVALID_PGPROCNO) {

PGPROC* proc = g_instance.proc_base_all_procs[wakeidx];

wakeidx = pg_atomic_read_u32(&proc->xlogGroupNext);

pg_atomic_write_u32(&proc->xlogGroupNext, INVALID_PGPROCNO);

proc->xlogGroupMember = false;

pg_memory_barrier();

if (proc != t_thrd.proc) {

PGSemaphoreUnlock(&proc->sem);

}

}

END_CRIT_SECTION();

return proc->xlogGroupReturntRecPtr;

}

posted @ 2024-04-30 10:09  openGauss-bot  阅读(9)  评论(0编辑  收藏  举报