达梦数据库中的核心进程和线程(理论+实验)学习

目录

一、达梦数据库的核心进程及线程(理论学习)

1.1.达梦数据库中不可或缺的核心线程

[1.1.1.监听线程(Listener Thread)](#1.1.1.监听线程(Listener Thread))

[1.1.2.工作线程 (Worker Threads)](#1.1.2.工作线程 (Worker Threads))

1)任务工作线程

2)会话工作线程

[1.1.4.调度线程(Schedule Thread)](#1.1.4.调度线程(Schedule Thread))

[1.1.5.日志FLUSH线程(Log Flush Thread)](#1.1.5.日志FLUSH线程(Log Flush Thread))

[1.1.6.日志归档线程(Log Archive Thread)](#1.1.6.日志归档线程(Log Archive Thread))

[1.1.7.检查点线程(Checkpoint Thread)](#1.1.7.检查点线程(Checkpoint Thread))

1.1.8.Purge线程

1.1.9.MAL系统线程

二、动手设计实验深入学习

2.1.实验一:基础观察与验证(重点)

2.2.实验二:核心线程功能验证(思路)

2.3.实验三:参数调优实验(调优)

2.4.高级故障模拟(谨慎!)


一、达梦数据库的核心进程及线程(理论学习)

官网对其进程及线程体系的概述为:

DM 服务器使用"对称服务器构架"的单进程、多线程结构。这种对称服务器构架在有效地利用了系统资源的同时,又提供了较高的可伸缩性能,这里所指的线程即为操作系统的线程。服务器在运行时由各种内存数据结构和一系列的线程组成,线程分为多种类型,不同类型的线程完成不同的任务。线程通过一定的同步机制对数据结构进行并发访问和处理,以完成客户提交的各种任务。DM 数据库服务器是共享的服务器,允许多个用户连接到同一个服务器上,服务器进程称为共享服务器进程。

1.1.达梦数据库中不可或缺的核心线程

DM的核心进程是dmserver,该进程中又包括了监听线程、IO 线程、工作线程、调度线程、日志线程等。

一个正常运行的达梦数据库,这些"元老级"线程缺一不可:

1.1.1.监听线程(Listener Thread)

数据库的"前台" 。它主要的任务是在服务器指定端口(默认5236)循环监听 并接收来自客户端的连接请求。一旦有新连接,它会唤醒并为该会话分配一个"会话工作线程"来接手(会话申请任务)。加入工作线程的任务队列,等待工作线程来进行处理。

它在系统启动完成后才启动,并且在系统关闭时首先被关闭。为了保证在处理大量客户连接时系统具有较短的响应时间,监听线程比普通线程优先级更高。

DM 服务器 所有配置端口的范围为 1024-65534 。当客户端工具发起连接时,由操作系统为客户端工具自动分配一个端口用于与 DM 服务器进行通信。对于数据守护、DMDSC、DM MPP 和 DMDPC 等分布式数据库中各实例节点之间的通信,发起连接的节点也由操作系统自动分配端口,所以配置主备/DMDSC/DM MPP/DMDPC 时,除了各实例指定的端口外,发起连接的实例也会有操作系统自动分配的用于和其他实例进行通信的端口。

1.1.2.工作线程 (Worker Threads)

数据库的"业务员",真正的劳动主力。负责服务器各种类型任务的处理及所有实际的数据相关操作(SQL解析、执行以及数据操作等)。为了提高效率,达梦采用线程池技术,其初始数量由 WORKER_THREADS 参数控制。当连接数超过预设值时,后续请求会进入队列排队等待。

工作线程包括任务工作线程和会话工作线程等:

1)任务工作线程

负责处理服务器内部生成并加入对应任务队列的各项任务,如调度线程生成的清理缓存任务、异步执行的任务等,其初始个数由 INI 参数 TASK_THREADS 指定。任务工作线程空闲时从任务队列依次摘取任务并进行处理,当任务队列中的任务堆积时,系统会增加任务工作线程数量以减少任务堆积。

2)会话工作线程

负责处理会话的请求任务,分为非线程池模式线程池模式 ,由 INI 参数 STHD_FLAG 控制。非线程池模式下每一个会话对应一个会话工作线程,一个会话上的任务全部由同一个工作线程完成, 这样减少了线程切换的代价,提高了系统效率。线程池模式 初始工作线程个数由 INI 参数 WORKER_THREADS*STHD_THREAD_NUM 指定,由会话轮询线程接收所有用户请求,加入会话任务队列,会话工作线程从会话任务队列依次摘取请求任务进行处理。

1.1.3.IO线程(IO Threads)

在数据库活动中,IO操作历来是最为耗时的操作之一。IO线程正是解决磁盘I/O瓶颈的异步处理这方面专家。为了避免工作线程因等待缓慢的磁盘读写而被阻塞,IO线程专门负责从磁盘读取数据页到缓冲区,或将脏数据页写回磁盘。

**啥时候触发IO线程:**IO线程在启动后,通常都处于睡眠状态,当系统需要进行IO时,只需要发出一个IO请求,此时线程被唤醒以处理该请求,在完成该IO操作后进入睡眠状态。

如何控制IO线程的个数:可以通过设置dm.ini文件中IO_THR_GROUPS参数来设置控制IO线程组的数量,默认情况下,每个组通常包含2个线程。

通常情况下,DMServer需要进行IO操作的时机主要是以下三种:

1)需要处理的数据页不在缓冲区中,此时需要将相关数据页读入缓冲区;

2)缓冲区满或系统关闭时,此时需要将部分脏数据页写入磁盘;

3)检查点到来时,需要将所有脏数据页写入磁盘。

1.1.4.调度线程(Schedule Thread)

数据库的"管家",负责接管系统中所有需要定时调度的后台任务。它就像一个"闹钟",每秒轮询一次,负责触发检查点(Checkpoint)、清理SQL缓存、动态调整缓冲区大小、检测会话超时等内务工作。

1)检查系统级的时间触发器,如果满足触发条件则生成任务加到任务工作线程的任务队列由任务工作线程执行;

2)清理 SQL 缓存、计划缓存中失效的项,或者超出缓存限制后淘汰不常用的缓存项;

3)执行动态缓冲区检查。根据需要动态扩展或动态收缩系统缓冲池;

4)自动执行检查点。为了保证日志的及时刷盘,减少系统故障时恢复时间,根据 INI 参数设置的自动检查点执行间隔定期执行检查点操作;

5)会话超时检测。当客户连接设置了连接超时时,定期检测是否超时,如果超时则自动断开连接;

6)必要时执行数据更新页刷盘;

7)唤醒等待的工作线程。

1.1.5.日志FLUSH线程(Log Flush Thread)

**保证事务持久性的"记录官"。任何数据修改都会先产生REDO日志。**为了保障数据故障恢复的一致性,REDO日志的刷盘必须在数据页刷盘之前进行。事务运行时,会把生成的REDO日志保留再日志缓冲区中,当事务提交或则执行检查点时,,会通知FLUSH线程进行日志刷盘,严格遵守"日志先行"(WAL)原则。

**注意:**实际在生产的过程中,由于日志具备顺序写入的特点,所以它要比数据页的IO写入效率更高,并且考虑的日志写满溢出的情况,还需对日志信息进行归档处理。

1.1.6. 日志归档线程(Log Archive Thread)

数据安全的"档案管理员"。当数据库处于归档模式,且联机日志文件写满需要切换时,此线程负责将写满的日志文件复制到指定的归档目录下,为数据备份和恢复提供基础。

日志归档线程包含异步归档线程,负责远程异步归档任务。如果配置了非实时归档,由日志 FLUSH 线程产生的任务会分别加入日志归档线程,日志归档线程负责从任务队列中取出任务,按照归档类型做相应归档处理。

将日志 FLUSH 线程和日志归档线程分开的目的是为了减少不必要的效率损失,除了远程实时归档外,本地归档、远程异步归档都可以脱离 FLUSH 线程来做,如果放在 FLUSH 线程中一起做会严重影响系统性能。

1.1.7.检查点线程(Checkpoint Thread)

这个线程负责执行检查点(Checkpoint)操作,即将内存中的脏数据页统一刷回磁盘,并更新数据库的恢复起点,这对于缩短数据库崩溃后的恢复时间至关重要。

1.1.8.Purge线程

称之为回滚段清理PURGE线程,主要负责清理不再需要的Undo数据(回滚记录),有助于回收存储空间并维持数据库读一致性的高效运转。

1.1.9.MAL系统线程

MAL 系统是DM 内部高速通信系统 ,在集群、数据守护等分布式或高可用架构中负责实例间的内部高速通信。**基于 TCP/IP 协议实现。**服务器的很多重要功能都是通过 MAL 系统实现通信的,例如数据守护、MPP、远程日志归档等。MAL 系统内部包含一系列线程,有 MAL 监听线程、MAL 发送工作线程、MAL 接收工作线程等。

DM线程相关的动态视图:

名称 说明
V$THREADS 记录当前系统中活动线程的信息
V$PROCESS 记录服务器进程信息

二、动手设计实验深入学习

理论学习之后,更重要的是动手实践。这里为你设计了一套由浅入深的实验方案,帮助你直观地观察和验证这些线程的工作原理

实验环境准备

**软件:**安装一个达梦数据库(建议DM8),并准备好一个客户端工具(如disql)。

**工具:**确认操作系统自带的 ps、grep、top 等命令可用;可选装 gdb 调试工具用于进阶实验。

**思路:**达梦是单进程多线程架构,所有线程都"隐藏"在 dmserver 进程里,我们需要借助系统工具来让它们"现形"。

2.1.实验一:基础观察与验证(重点)

目标:直观验证"单进程多线程"架构,并掌握查看线程详情的方法。

步骤:

1)在服务器上执行ps -ef | grep dmserver,找到dmserver主进程的PID;

2)使用ps -T -p <PID>命令,列出该进程下所有的线程。观察线程名(如dm_lsnr_thd,dm_io_thd)和数量,并与达梦数据库中的v$THREADS视图中查询到的结果进行对比。

bash 复制代码
[dmdba@localhost bin]$ ps -ef |grep dmserver
dmdba      1296      1  0 17:48 ?        00:00:07 /home/dmdba/dmdbms/bin/dmserver path=/dmdata2/data/IMPORT_DB/dm.ini -noconsole
dmdba      1298      1  0 17:48 ?        00:00:07 /home/dmdba/dmdbms/bin/dmserver path=/dmdata/data/DMTEST/dm.ini -noconsole
dmdba     47356  36289  0 19:48 pts/0    00:00:00 grep --color=auto dmserver
[dmdba@localhost bin]$ ps -T -p 1296
   PID   SPID TTY          TIME CMD
  1296   1296 ?        00:00:01 dmserver
  1296   1465 ?        00:00:00 dm_sqllog_thd
  1296   1467 ?        00:00:00 dm_pthd_thd
  1296   1468 ?        00:00:00 dm_pthd_thd
  1296   1476 ?        00:00:00 dm_pthd_thd
  1296   1477 ?        00:00:00 dm_pthd_thd
  1296   1478 ?        00:00:00 dm_pthd_thd
  1296   1479 ?        00:00:00 dm_pthd_thd
  1296   1480 ?        00:00:00 dm_pthd_thd
  1296   1481 ?        00:00:00 dm_pthd_thd
  1296   1482 ?        00:00:00 dm_pthd_thd
  1296   1483 ?        00:00:00 dm_pthd_thd
  1296   1484 ?        00:00:00 dm_pthd_thd
  1296   1485 ?        00:00:00 dm_pthd_thd
  1296   1486 ?        00:00:00 dm_pthd_thd
  1296   1487 ?        00:00:00 dm_pthd_thd
  1296   1488 ?        00:00:00 dm_pthd_thd
  1296   1489 ?        00:00:00 dm_pthd_thd
  1296   1490 ?        00:00:00 dm_tskwrk_thd
  1296   1491 ?        00:00:00 dm_tskwrk_thd
  1296   1492 ?        00:00:00 dm_tskwrk_thd
  1296   1493 ?        00:00:00 dm_tskwrk_thd
  1296   1494 ?        00:00:00 dm_tskwrk_thd
  1296   1495 ?        00:00:00 dm_tskwrk_thd
  1296   1496 ?        00:00:00 dm_tskwrk_thd
  1296   1497 ?        00:00:00 dm_tskwrk_thd
  1296   1498 ?        00:00:00 dm_tskwrk_thd
  1296   1499 ?        00:00:00 dm_tskwrk_thd
  1296   1500 ?        00:00:00 dm_tskwrk_thd
  1296   1502 ?        00:00:00 dm_tskwrk_thd
  1296   1503 ?        00:00:00 dm_tskwrk_thd
  1296   1504 ?        00:00:00 dm_tskwrk_thd
  1296   1505 ?        00:00:00 dm_tskwrk_thd
  1296   1506 ?        00:00:00 dm_tskwrk_thd
  1296   1507 ?        00:00:00 dmserver
  1296   1508 ?        00:00:00 dmserver
  1296   1509 ?        00:00:00 dmserver
  1296   1519 ?        00:00:00 dmserver
  1296   1520 ?        00:00:00 dmserver
  1296   1521 ?        00:00:00 dmserver
  1296   1522 ?        00:00:00 dmserver
  1296   1523 ?        00:00:00 dmserver
  1296   1524 ?        00:00:00 dmserver
  1296   1525 ?        00:00:00 dmserver
  1296   1526 ?        00:00:00 dmserver
  1296   1527 ?        00:00:00 dmserver
  1296   1528 ?        00:00:00 dmserver
  1296   1529 ?        00:00:00 dmserver
  1296   1530 ?        00:00:00 dmserver
  1296   1545 ?        00:00:00 dmserver
  1296   1546 ?        00:00:00 dmserver
  1296   1547 ?        00:00:00 dmserver
  1296   1867 ?        00:00:00 dm_quit_thd
  1296   1869 ?        00:00:00 dm_osio_thd
  1296   1870 ?        00:00:00 dm_osio_thd
  1296   1871 ?        00:00:00 dm_osio_thd
  1296   1872 ?        00:00:00 dm_osio_thd
  1296   1873 ?        00:00:00 dm_osio_thd
  1296   1874 ?        00:00:00 dm_osio_thd
  1296   1875 ?        00:00:00 dm_osio_thd
  1296   1876 ?        00:00:00 dm_osio_thd
  1296   1877 ?        00:00:00 dm_osio_thd
  1296   1878 ?        00:00:00 dm_osio_thd
  1296   1879 ?        00:00:00 dm_osio_thd
  1296   1880 ?        00:00:00 dm_osio_thd
  1296   1881 ?        00:00:00 dm_osio_thd
  1296   1882 ?        00:00:00 dm_osio_thd
  1296   1883 ?        00:00:00 dm_osio_thd
  1296   1884 ?        00:00:00 dm_osio_thd
  1296   1902 ?        00:00:00 dm_pwr_thd
  1296   1923 ?        00:00:00 dm_rsyswrk_thd
  1296   1924 ?        00:00:00 dm_rsyswrk_thd
  1296   1938 ?        00:00:00 dm_hio_thd
  1296   1939 ?        00:00:00 dm_hio_thd
  1296   1940 ?        00:00:00 dm_hio_thd
  1296   1941 ?        00:00:00 dm_hio_thd
  1296   1991 ?        00:00:00 dm_chkpnt_thd
  1296   1992 ?        00:00:00 dm_redolog_thd
  1296   2003 ?        00:00:00 dm_sqllog_thd
  1296   2008 ?        00:00:00 dm_sql_aux_thd
  1296   2010 ?        00:00:00 dm_purge_thd
  1296   2022 ?        00:00:00 dm_lpq_thd
  1296   2023 ?        00:00:00 dm_lpq_thd
  1296   2024 ?        00:00:00 dm_lpq_thd
  1296   2025 ?        00:00:00 dm_lpq_thd
  1296   2026 ?        00:00:00 dm_lpq_thd
  1296   2027 ?        00:00:00 dm_lpq_thd
  1296   2028 ?        00:00:00 dm_lpq_thd
  1296   2029 ?        00:00:00 dm_lpq_thd
  1296   2030 ?        00:00:00 dm_lpq_thd
  1296   2031 ?        00:00:00 dm_lpq_thd
  1296   2032 ?        00:00:00 dm_trxbro_thd
  1296   2050 ?        00:00:00 dm_trctsk_thd
  1296   2051 ?        00:00:00 dm_wrkgrp_thd
  1296   2052 ?        00:00:00 dm_wrkgrp_thd
  1296   2053 ?        00:00:00 dm_wrkgrp_thd
  1296   2054 ?        00:00:00 dm_wrkgrp_thd
  1296   2055 ?        00:00:00 dm_wrkgrp_thd
  1296   2056 ?        00:00:00 dm_wrkgrp_thd
  1296   2057 ?        00:00:00 dm_wrkgrp_thd
  1296   2058 ?        00:00:00 dm_wrkgrp_thd
  1296   2059 ?        00:00:00 dm_wrkgrp_thd
  1296   2060 ?        00:00:00 dm_wrkgrp_thd
  1296   2061 ?        00:00:00 dm_wrkgrp_thd
  1296   2062 ?        00:00:00 dm_wrkgrp_thd
  1296   2063 ?        00:00:00 dm_wrkgrp_thd
  1296   2064 ?        00:00:00 dm_wrkgrp_thd
  1296   2065 ?        00:00:00 dm_wrkgrp_thd
  1296   2066 ?        00:00:00 dm_wrkgrp_thd
  1296   2069 ?        00:00:00 dm_audit_thd
  1296   2070 ?        00:00:00 dm_audit_thd
  1296   2079 ?        00:00:00 nlgn_task_threa
  1296   2080 ?        00:00:02 dm_sched_thd
  1296   2081 ?        00:00:00 dm_lsnr_thd
[dmdba@localhost bin]$

预期结果:你将亲眼看到成百上千的线程都归属于同一个PID。

2.2.实验二:核心线程功能验证(思路)

目标:过模拟特定操作,观察对应线程的活动。

步骤:

1)验证监听线程:在一个窗口用top -H -p <PID>实时监控线程列表。在另一个窗口,尝试用disql连接数据库。观察dm_lsnr_thd的CPU或状态变化。

这个:经测试,无明显的状态现象。

2)验证工作线程:在客户端执行一个复杂查询,如select count(*) from 一个大表;观察dm_wrkgrp_thd或dm_tskwrk_thd的活动。

3)验证IO线程:执行一个全表扫描,同时用iostat -x 1观察磁盘I/O。可以对比执行前后的IO线程状态。

4)验证日志FLUSH线程:在一个事务中执行INSERT/UPDATE操作并COMMIT。在提交瞬间,观察dm_redolog_thd是否又活动。

预期结果:你会清晰地看到:有连接进来时,监听线程"忙"一下;执行查询时,工作线程和IO线程"忙起来";提交事务时,日志FLUSH线程开始工作。

整体实验结果快,很多现象可能会观察不到。

2.3.实验三:参数调优实验(调优)

目标:通过修改线程相关参数,感受配置对性能的影响。

步骤:

1)修改前:使用性能测试工具(如dts自带的benchmark)对数据库进行压力测试,并记录下TPS/QPS及线程上下文切换次数(可用vmstat观察)。

2)修改参数:在dm.ini文件中,修改WORK_THTEADS(工作线程数)或IO_THR_GROUPS(I/O线程组数)。

3)重启生效:重启数据库使参数生效。

4)修改后:再次运行同样的压力测试。对比两次的测试结果和系统开销。

预期结果:你会发现,**线程数不是越多越好。配置过多反而会增加上下文切换的开销,降低性能。**这个实验能帮你直观理解参数配置的"黄金点"。

2.4.高级故障模拟(谨慎!)

目的:了解在极端情况下,如何定位问题线程

步骤

1)制造一个"长事务"或"锁等待"的场景。

2)通过v$threads找到疑似"卡住"的线程ID(TID)。

3)在操作系统层面,用top -H -p <PID>确认该线程是否处于D(不可中断睡眠)或R(运行)状态。

4)进阶:如果有GDB调试经验,可以gdb -p <PID>,然后thread <TID>切换到该线程,再用bt命令打印其堆栈信息,看它卡在哪个函数上。

预期结果:这个实验能让你初步掌握在生产环境中,当一个线程"假死"时,应该如何去定位和初步分析问题。

相关推荐
达梦产品与服务5 天前
稳扎稳打,持续迭代 | SQLark V3.10 更新,30+ 项优化与修复
mysql·oracle·达梦数据库·pg·sqlark百灵连接
p@nd@1 个月前
DM删除用户后的不完全恢复测试
数据库·达梦数据库·备份还原·备份恢复
treacle田1 个月前
达梦数据库-数据库审计02-记录总结
数据库·达梦数据库·数据库对象级审计
treacle田1 个月前
达梦数据库-数据库审计01-记录总结
数据库·达梦数据库·数据库审计
晴天¥1 个月前
达梦数据库共享存储集群搭建(DSC双节点+Openfiler-IP SAN存储)
linux·数据库·达梦数据库
晴天¥1 个月前
达梦数据库dexp 和 dimp 应用实例
数据库·达梦数据库
treacle田1 个月前
达梦数据库-单台机器上运行多个不同版本数据库-记录总结
达梦数据库
treacle田2 个月前
达梦数据库-数据库单机版本升级-记录总结
数据库·达梦数据库·数据库升级
treacle田2 个月前
达梦数据库-配置本地守护进程dmwatcher服务-记录总结
数据库·达梦数据库·达梦数据库local数据守护