暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

二探PgSQL18的异步IO

原创 闫宗帅 2025-10-10
201

二探PgSQL18的异步IO

本文介绍PgSQL18中使用worker的方式进行异步IO。主要通过PgAioWorkerSubmissionQueue队列管理异步IO请求。用户服务进程生产异步IO请求,将其放到上面的队列中,io_worker进程从队列中取异步IO请求进行消费。

1、计算可以预读的连续页数

上篇博文已介绍。PgSQL18的异步IO

2、将IO分批次

PgAioCtl* pgaio_ctl作为异步IO全局管理器,管理所有的异步IO请求,每个异步IO请求对应一个io_handles[]。尽管PgAioHandle* io_handles管理的一次异步IO请求处理的IO页都是连续的,但加载内存页对应的共享内存也需要连续。由于申请pin住的共享内存页内存并不是连续,所以需要将IO请求进一步拆分,以连续的内存页为单位,将其拆分成iovecs[i],每个iovecs[i]管理内存块起使地址及连续后的大小。

1)io_handles[i]的op标记本次请求是读请求还是写请求;

2)iovec_off作为本次io所属iovecs[]的起使槽位(一个IO中的iovecs[]槽位是连续申请的)。

3)PgAioOpData op_data对应本次IO读文件的元数据:以读为例,fd为文件句柄,iov_length为iovecs[]使用的槽位个数,offset为fd文件的偏移位置开始读。读的时候取到对应的iovecs[],从而得到iov_len读取长度。

4)op_data中offset读取偏移位置是由PgAioTargetData中的blockNum(本次IO的起使页号)计算得到的,如下图所示:

函数调用说明:

read_stream_start_pending_read->StartReadBuffers->StartReadBuffersImpl->AsyncReadBuffers->smgrstartreadv->mdstartreadv->FileStartReadV->pgaio_io_start_readv->pgaio_io_stage->     pgaio_my_backend->staged_ios[pgaio_my_backend->num_staged_ios++] = ioh;

1) AsyncReadBuffers函数中申请一个ioh句柄,在mdstartreadv函数中得到iovecs[]的起使槽iov,通过iovcnt = buffers_to_iovec(iov, buffers, nblocks_this_segment);将IO拆分成iovcnt个,并计算出读的起使偏移seekpos,然后调用下一步的函数进行填充

2) pgaio_io_start_readv填充ioh异步IO句柄的fd、offset和iovecs[]的槽个数(下一小阶介绍)

3) pgaio_io_stage将异步IO句柄放到staged_ios[]中

注:在AioShmemInit中可见每个ioh句柄对应io_max_combine_limit个iovecs[]槽,他的起使槽位是固定的。

该IO句柄怎么提交到异步队列呢?下文继续。

3、IOMETHOD_WORKER异步IO的管理结构

io_worker_control的idle_worker_mask可以认为是一个bitmap,标记workers[]已使用的所有槽,也就是将异步IO请求放到对应的槽位上(对应到异步IO worker进程)处理异步IO。

4、IOMETHOD_WORKER异步IO队列

PgAioBackend从pgaio_ctl->backend_state[MyProcNumber]取,作为本进程的异步IO请求的临时存放队列。异步IO请求,也就是io句柄PgAioHandle需要先放到这里,等及攒够32个后(尽量多的积攒)就会在pgaio_io_acquire_nb函数中调用pgaio_submit_staged提交。worker的异步IO方式下使用pgaio_worker_submit函数进行提交:

上述代码中可知,在队列锁内,将staged_ios[]数组记录积攒的异步io句柄的序号放到提交队列中。如果队列放满了,还有剩下异步IO请求,则将剩余的调用pgaio_io_perform_synchronously函数由本进程同步提交掉。至于放到提交队列的IO请求,则由pgaio_worker_choose_idle选择一个空闲的异步io worker进程,通过SetLatch该进程的latch通知对应io worker进程唤醒。通过kill命令向io worker进程发送SIGURG信号唤醒。

5、io worker进程的处理

该进程在WaitLatch处被唤醒后,在队列锁内取出一个io句柄进行同步IO的执行;可以看到它还会选择其他空闲的io worker进程将其唤醒。也就是做到多个IO worker并发消耗提交队列的IO请求进行IO

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论