【参赛作品2】openguass NUMA适配之线程绑核

1、多核NUMA结构

NUMA(Non-uniform memory access,非统一内存访问架构)出现前,CPU通过内存控制器访问内存,随着CPU核的增加,内存控制器成为评价。内存控制器一般拆分内存平均分配到各个node节点上,CPU访问本地内存速度快,跨片访问慢。NUMA距离定义为:NUMA node的处理器和内存块的物理距离。通过numactl工具可以查看到CPU访问的距离信息。

2、NUMA绑核优化思路

避免线程在运行中在不同核上漂移,从而引起访问NUMA远端内存。Openguass通过配置参数thread_pool_attr控制CPU绑核分配,该参数仅在enable_thread_pool打开后生效。参数分为3部分:’thread_num,group_num,cpubind_info’。

其中thread_num:线程池中线程总数,取值0-4096。0表示根据CPU核数量自动配置线程池中线程数。如果大于0,线程池中线程数等于该值

group_num:线程池中线程分组个数。0-64。0表示根据NUMA组个数自动配置线程池中分组个数,否正为group_num个数。

cpubind_info:线程池是否绑核的配置参数。可以配置:

1(nobind),线程不绑核

2(allbind),利用当前系统所有能查询到的CPU核做线程绑核;

3 (nodebind:1,2),利用NUMA组1,2中CPU核进行绑核;

4 (cpubind:0-30),利用0-30号CPU核进行绑核。

默认值‘16,2,(nobind)’

为充分利用CPU,线程数略大于核数。因为可能由线程等待,此时切换大其他线程进行。

3、源码解析

操作流程

  • 在PostmasterMain中开始设置线程绑定动作

  • 如果设置enable_thread_pool,才会调用SetThreadPoolInfo函数

    1. 首先InitCpuInfo将CPU信息结构m_cpuInfo初始化
    2. 判定是否已有CPU进行了绑定GetInstanceBind
    3. GetCpuAndNumaNum计算CPU个数及NUMA节点个数
    4. ParseAttr函数解析thread_pool_attr字符串
    5. GetSysCpuInfo函数获取CPU信息
    6. SetGroupAndTreadNum设定组个数及每个组中线程数
  • 在ServerLoop函数中接收用户端连接,并进行CPU绑定

    • 由函数g_threadPoolControler->Init完成
    • 完成线程创建及CPU绑定的函数是TreadPoolGroup::Init完成

GetCpuAndNumaNum

通过lscpu命令来计算CPU核、NUMA个数。

void ThreadPoolControler::GetCpuAndNumaNum()
{
    char buf[BUFSIZE];
    FILE* fp = NULL;
    if ((fp = popen("lscpu", "r")) != NULL) {
        while (fgets(buf, sizeof(buf), fp) != NULL) {
            if (strncmp("CPU(s)", buf, strlen("CPU(s)")) == 0 &&
               strncmp("On-line CPU(s) list", buf, strlen("On-line CPU(s) list")) != 0 &&
                strncmp("NUMA node", buf, strlen("NUMA node")) != 0) {
                char* loc = strchr(buf, ':');
                m_cpuInfo.totalCpuNum = pg_strtoint32(loc + 1);
            } else if (strncmp("NUMA node(s)", buf, strlen("NUMA node(s)")) == 0) {
                char* loc = strchr(buf, ':');
                m_cpuInfo.totalNumaNum = pg_strtoint32(loc + 1);
            }
        }
        pclose(fp);
    } 

GetSysCpuInfo

  • 通过fp = popen(“lscpu -b -e=cpu,node”, “r”);执行lscpu命令获取cpuid和numaid
  • 通过CPU_ISSET判断CPU是否绑定,最后计算出活跃未绑定的CPU个数m_cpuInfo.activeNumaNum

SetGroupAndThreadNum

  • 进行线程绑定,默认情况下线程组个数2,每组里面线程个数16
  • ConstrainThreadNum限定线程池大小m_maxPoolSize为min(4096,max_connection,),线程个数m_threadNum = Min(m_threadNum, m_maxPoolSize);

ThreadPoolGroup::Init

m_listener->StartUp();//开启一个新线程
InitWorkerSentry();
|-- AddWorker
    |-- AttachThreadToNodeLevel:: pthread_setaffinity_np
CPU_SET(m_groupCpuArr[i], &m_nodeCpuSet);//循环将CPU加入CPU集合

NUMA优化相关函数

Opengauss中所有numa相关函数都可以通过宏定义ifdef __USE_NUMA找到其定义及调用的地方。

int numa_available(void):NUMA的API是否可以在平台上正常使用
int numa_max_node(void):当前系统上最大NUMA节点号
void * numa_alloc_onnode(size_t size,int node):在一个指定NUMA节点分配内存
void numa_free(void *start,size_t size):释放起始地址指定的内存
int numa_run_on_node(int node):运行当前任务在指定NUMA节点上
void numa_set_localalloc(void):设置当前的任务内存分配策略为本地化分配
void numa_set_preferred(int node):为当前任务设置偏好NUMA节点
void numa_set_interleave_mask(struct bitmask*nodemask):在一系列numa节点上分配交叉内存
int pthread_getaffinity_np(pthread_t thread,size_t cpusetsize,cpu_set_t *cpuset):设置线程在某个CPU上运行。
  1. sched_getaffinity和pthread_getaffinity_np都是绑核的函数。
  2. numa_set_preferred设置当前线程优先分配内的结点。内存分配器先尝试从这个结点上分配内存。如果这个结点没有足够的空间,它会尝试其他结点。
  3. numa_set_interleave_mask函数可以让当前线程以交错(interleaving)方式分配内存。未来所有的内存,将会从掩码给定的结点上轮询(round robing)分配。numa_all_nodes将内存分配交错(interleaving)在所有的node上。numa_no_nodes将会关闭交错分配内存。numa_get_interleave_mask函数返回当前的交错掩码。这可以将当前的内存分配策略保存到文件中,在策略修改后,再次恢复。

参考

}https://www.bilibili.com/video/BV1gD4y1o7qB?from=search&seid=11985947230954507904
在这里插入图片描述

Gauss松鼠会是汇集数据库爱好者和关注者的大本营,
大家共同学习、探索、分享数据库前沿知识和技术,
互助解决问题,共建数据库技术交流圈。
openGauss官网
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
在Oracle数据库中,可以通过以下步骤将定到NUMA节点: 1. 确定系统中的NUMA节点数量和分布情况。可以使用`numactl --hardware`命令查看NUMA节点的信息。 2. 设置合适的NUMA定策略。可以使用`numactl`命令设置NUMA定策略。例如,使用以下命令将进程定到特定的NUMA节点: ``` numactl --cpunodebind=<NUMA节点ID> --membind=<NUMA节点ID> <命令> ``` 其中,`<NUMA节点ID>`是要定到的NUMA节点的ID,`<命令>`是要运行的Oracle数据库相关命令。 3. 在Oracle数据库中设置合适的参数。可以通过修改Oracle数据库的参数文件(如`init.ora`或`spfile.ora`)来设置与NUMA相关的参数。以下是一些常用的参数: - `cpu_count`: 设置数据库实例使用的CPU心数。根据系统情况和需求,可以将其设置为NUMA节点上可用的CPU心数。 - `sga_max_size`和`sga_target`: 设置SGA(共享全局区)的最大大小和目标大小。根据系统情况和需求,可以将其设置为NUMA节点上可用内存的一部分。 - `pga_aggregate_target`: 设置PGA(程序全局区)的目标大小。同样,根据系统情况和需求,可以将其设置为NUMA节点上可用内存的一部分。 - 其他与CPU和内存相关的参数,如`sessions`、`open_cursors`等,也需要根据系统情况进行设置。 4. 重新启动Oracle数据库实例,使设置生效。 请注意,在进行NUMA定和相关参数设置之前,请确保对系统和数据库的影响有足够的了解,并在测试环境中进行验证。此外,具体的设置步骤可能因操作系统版本、Oracle数据库版本和特定系统配置而有所不同,请参考相关文档或咨询Oracle支持以获取更详细的信息和指导。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gauss松鼠会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值