Cantian 服务端进程架构深度解析
适用版本 : Cantian 当前主分支
阅读时间 : 约 35 分钟
难度等级: ⭐⭐⭐⭐(中高级)
目录
- 背景
- [一、cantiand 是什么](#一、cantiand 是什么)
- 二、整体架构与进程模型
- 三、启动流程详解
- 四、核心子系统剖析
- 五、实战:启动与状态查看
- 六、常见问题与排查
- 七、总结
作者介绍
数据库内核专家 | 分布式系统架构师
深耕数据库内核架构设计与开发十余年,主导研发多款高性能分布式数据库,攻克高并发、低延迟等核心技术难题。
现倾力打造《从零手写数据库》系列教程,首次系统性公开 数据库内核源码级实现细节,从存储引擎到分布式事务,手把手拆解核心模块。
无论你是数据库开发者、系统架构师,还是对底层技术充满好奇的极客,这里都有你想要的「硬核干货」!
系列文章
- 【手写数据库核心揭秘系列】
背景
cantiand 是 Cantian 引擎的主数据库服务器进程,类比于 PostgreSQL 的 postmaster 或 MySQL 的 mysqld。它负责整个数据库实例的生命周期管理:从命令行参数解析、实例初始化、共享内存分配、参数加载,到监听客户端连接、分配会话、调度工作线程,再到运行期监控、动态视图、故障诊断等。
理解 cantiand 的服务端进程架构,是掌握 Cantian 运行机理的第一道门槛。本文将从源码层面解析 cantiand 的启动流程、进程模型、Reactor 网络模型、会话管理机制以及关键子系统的交互关系。
文章亮点:
- ✅ 启动全景: nomount / mount / open 三阶段启动模型
- ✅ Reactor 模型: 监听线程与工作线程的职责分离
- ✅ 会话管理: session、agent、cursor 的层级关系
- ✅ 参数体系: 服务端参数加载、校验与动态生效
- ✅ 动态视图: 运行期诊断与性能监控入口
一、cantiand 是什么
1.1 核心定义
cantiand 是 Cantian 引擎的主服务器进程 ,由 pkg/src/server 目录编译生成,是数据库实例对外提供服务的总入口。它向上接收客户端(gsql / GSC / MySQL-CTC)的请求,向下协调内核存储引擎、集群通信层、集群管理层完成实际的数据访问。
1.2 核心职责
| 职责 | 说明 |
|---|---|
| 进程生命周期 | 解析启动参数、执行 nomount/mount/open 阶段、处理信号、优雅关闭 |
| 网络监听 | 通过 TCP/UDS/SSL 监听客户端连接,支持 Reactor 多线程模型 |
| 会话管理 | 创建/销毁 session,分配 agent 工作线程,维护会话状态 |
| 参数管理 | 加载 cantiand.ini 等配置文件,支持动态参数修改 |
| 资源管理 | 管理 SGA(系统全局区)、PGA(程序全局区)等内存资源 |
| 运行期监控 | 提供动态视图(dynamic view)、统计信息、黑匣子、告警 |
| 集群协调 | 与 CMS、MES、DTC 模块交互,参与集群状态维护 |
1.3 启动模式
cantiand 支持三种启动模式,对应 Oracle 风格的数据库启动阶段:
| 模式 | 含义 | 主要工作 |
|---|---|---|
| nomount | 不挂载数据库 | 启动实例,分配共享内存,加载参数,不打开控制文件 |
| mount | 挂载数据库 | 读取控制文件,识别数据文件,但不打开供用户访问 |
| open | 打开数据库 | 完全启动,接受用户连接,可进行读写操作(默认) |
二、整体架构与进程模型
2.1 运行态进程结构
┌─────────────────────────────────────────────────────────────────┐
│ cantiand 进程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ 主线程 │ │ 监听器线程 │ │ Reactor / Agent │ │
│ │ (main) │ │ (listener) │ │ 工作线程 │ │
│ └──────┬──────┘ └──────┬──────┘ └─────────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 共享内存 (SGA) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ 缓冲池 │ │ 锁表 │ │ 字典缓存 │ │ 统计信息 │ │ │
│ │ │ (KCB) │ │ (KGL) │ │ (DC) │ │ │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 内核存储引擎 │ │
│ │ (事务、日志、表、索引、集群通信...) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
2.2 线程/进程模型
Cantian 的 cantiand 采用单进程多线程模型(与 PostgreSQL 的多进程模型不同):
| 线程类型 | 代表文件 | 职责 |
|---|---|---|
| 主线程 | srv_main.c |
启动初始化、信号处理、进程生命周期 |
| 监听器线程 | srv_lsnr.c |
监听端口,接收新连接 |
| Reactor 线程 | srv_reactor.c |
网络 I/O 事件分发 |
| Agent 工作线程 | srv_agent.c |
执行具体 SQL/事务请求 |
| 后台工作线程 | srv_sga.c / 内核 daemon |
检查点、日志刷写、统计收集等 |
2.3 与周边组件的关系
客户端 (gsql / GSC / MySQL-CTC)
│
▼
┌─────────────────┐
│ cantiand │
│ (pkg/src/server)│
└────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
pkg/src/kernel pkg/src/mec pkg/src/cms
(存储引擎) (集群通信) (集群管理)
三、启动流程详解
3.1 命令行入口
cantiand 的入口位于 pkg/src/server/srv_main.c。命令行支持:
bash
cantiand [nomount|mount|open] [-D db_home_path]
cantiand [-h|-H] # 帮助
cantiand [-v|-V] # 版本
3.2 启动三阶段
功能说明: Cantian 数据库启动遵循 NOMOUNT → MOUNT → OPEN 三阶段模型。每个阶段完成不同的初始化任务,确保数据库从配置加载到对外服务的有序过渡。
#mermaid-svg-NZFKSDi5FSr8VW7q{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NZFKSDi5FSr8VW7q .error-icon{fill:#552222;}#mermaid-svg-NZFKSDi5FSr8VW7q .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NZFKSDi5FSr8VW7q .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NZFKSDi5FSr8VW7q .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NZFKSDi5FSr8VW7q .marker.cross{stroke:#333333;}#mermaid-svg-NZFKSDi5FSr8VW7q svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NZFKSDi5FSr8VW7q p{margin:0;}#mermaid-svg-NZFKSDi5FSr8VW7q .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NZFKSDi5FSr8VW7q .cluster-label text{fill:#333;}#mermaid-svg-NZFKSDi5FSr8VW7q .cluster-label span{color:#333;}#mermaid-svg-NZFKSDi5FSr8VW7q .cluster-label span p{background-color:transparent;}#mermaid-svg-NZFKSDi5FSr8VW7q .label text,#mermaid-svg-NZFKSDi5FSr8VW7q span{fill:#333;color:#333;}#mermaid-svg-NZFKSDi5FSr8VW7q .node rect,#mermaid-svg-NZFKSDi5FSr8VW7q .node circle,#mermaid-svg-NZFKSDi5FSr8VW7q .node ellipse,#mermaid-svg-NZFKSDi5FSr8VW7q .node polygon,#mermaid-svg-NZFKSDi5FSr8VW7q .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NZFKSDi5FSr8VW7q .rough-node .label text,#mermaid-svg-NZFKSDi5FSr8VW7q .node .label text,#mermaid-svg-NZFKSDi5FSr8VW7q .image-shape .label,#mermaid-svg-NZFKSDi5FSr8VW7q .icon-shape .label{text-anchor:middle;}#mermaid-svg-NZFKSDi5FSr8VW7q .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NZFKSDi5FSr8VW7q .rough-node .label,#mermaid-svg-NZFKSDi5FSr8VW7q .node .label,#mermaid-svg-NZFKSDi5FSr8VW7q .image-shape .label,#mermaid-svg-NZFKSDi5FSr8VW7q .icon-shape .label{text-align:center;}#mermaid-svg-NZFKSDi5FSr8VW7q .node.clickable{cursor:pointer;}#mermaid-svg-NZFKSDi5FSr8VW7q .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NZFKSDi5FSr8VW7q .arrowheadPath{fill:#333333;}#mermaid-svg-NZFKSDi5FSr8VW7q .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NZFKSDi5FSr8VW7q .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NZFKSDi5FSr8VW7q .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NZFKSDi5FSr8VW7q .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NZFKSDi5FSr8VW7q .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NZFKSDi5FSr8VW7q .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NZFKSDi5FSr8VW7q .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NZFKSDi5FSr8VW7q .cluster text{fill:#333;}#mermaid-svg-NZFKSDi5FSr8VW7q .cluster span{color:#333;}#mermaid-svg-NZFKSDi5FSr8VW7q div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NZFKSDi5FSr8VW7q .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NZFKSDi5FSr8VW7q rect.text{fill:none;stroke-width:0;}#mermaid-svg-NZFKSDi5FSr8VW7q .icon-shape,#mermaid-svg-NZFKSDi5FSr8VW7q .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NZFKSDi5FSr8VW7q .icon-shape p,#mermaid-svg-NZFKSDi5FSr8VW7q .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NZFKSDi5FSr8VW7q .icon-shape .label rect,#mermaid-svg-NZFKSDi5FSr8VW7q .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NZFKSDi5FSr8VW7q .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NZFKSDi5FSr8VW7q .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NZFKSDi5FSr8VW7q :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户执行 cantiand open -D /data/cantian
参数解析 解析模式/路径
创建/附加实例 srv_instance.c
加载配置参数 cantiand.ini
NOMOUNT阶段
分配SGA共享内存
初始化全局结构
MOUNT阶段
读取控制文件
识别数据文件
OPEN阶段
打开数据文件
启动后台线程
监听客户端连接
进入服务循环 接受请求
执行步骤说明:
- 参数解析: 解析命令行参数,确定启动模式(OPEN/MOUNT/NOMOUNT)和数据目录路径
- 创建实例 : 调用
srv_instance.c中的函数创建或附加到已有实例 - 加载配置 : 读取
cantiand.ini等配置文件,初始化参数 - NOMOUNT 阶段: 分配 SGA 共享内存,初始化全局数据结构,不访问数据文件
- MOUNT 阶段: 读取控制文件,识别数据文件和日志文件,加锁防止多实例同时挂载
- OPEN 阶段: 打开数据文件,启动后台线程(LGWR、DBWR、SMON 等),开始监听客户端连接
- 服务循环: 进入主循环,接受并处理客户端请求
3.3 关键启动函数
功能说明 : main 是 cantiand 进程的入口函数,负责解析命令行参数、启动实例、进入主服务循环。启动失败会触发关闭流程释放资源。
c
// src/server/srv_main.c
int main(int argc, char *argv[])
{
// 步骤1: 解析命令行参数(启动模式、数据目录、配置文件路径等)
srv_process_setup_args(argc, argv, &assist);
// 步骤2: 初始化实例(NOMOUNT → MOUNT → OPEN 三阶段启动)
srv_startup(assist.start_mode, ...);
// 步骤3: 进入主服务循环(接受连接、分发请求)
while (running) {
srv_process_loop();
}
// 步骤4: 关闭(释放资源、刷盘、关闭文件)
srv_shutdown();
}
3.4 实例初始化流程
srv_instance.c 中的核心函数负责:
- 读取参数文件 :
cantiand.ini等配置文件。 - 内存上下文初始化: 为 SGA、PGA 分配内存池。
- 错误处理与日志: 初始化日志系统、错误码映射。
- 数据库状态机: 从 NOMOUNT → MOUNT → OPEN 的状态转换。
- 集群组件初始化: 调用 MES、CMS、DTC 相关初始化函数。
四、核心子系统剖析
4.1 参数管理系统
pkg/src/server/params/ 目录包含参数加载、校验、设置相关代码:
| 文件 | 职责 |
|---|---|
srv_param.c |
参数总入口 |
srv_param_common.c |
通用参数处理 |
load_kernel.c / set_kernel.c |
内核参数加载/设置 |
load_server.c / set_server.c |
服务端参数加载/设置 |
load_others.c / set_others.c |
其他模块参数 |
参数类型包括:
- 内存参数(shared_buffers、large_pool_size 等)
- 连接参数(max_sessions、max_agents 等)
- 日志参数(log_level、log_file_size 等)
- 集群参数(cms_ip、node_id、cluster_id 等)
4.2 会话与会话管理
pkg/src/server/srv_session.c 负责 session 生命周期:
Session 结构层级:
┌─────────────────────────────────────┐
│ session_t │
│ (用户会话,含 knl_session、状态等) │
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ knl_session_t │
│ (内核会话,含事务、游标、锁等上下文) │
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ knl_cursor_t │
│ (内核游标,表/索引扫描状态) │
└─────────────────────────────────────┘
4.3 Agent 工作线程
pkg/src/server/srv_agent.c 实现工作线程池:
- 每个客户端连接绑定到一个 session。
- Agent 线程从 session 获取请求并执行。
- 支持专用 agent 和共享 agent 池两种模式。
4.4 监听器与 Reactor
pkg/src/server/srv_lsnr.c 和 srv_reactor.c 实现网络监听:
| 组件 | 文件 | 说明 |
|---|---|---|
| Listener | srv_lsnr.c |
绑定端口、accept 新连接 |
| Reactor | srv_reactor.c |
epoll/kqueue 事件循环,分发网络事件 |
| 协议层 | pkg/src/protocol |
TCP/UDS/SSL/RDMA 协议处理 |
4.5 动态视图与诊断
pkg/src/server/srv_view*.c 提供运行时诊断视图:
| 文件 | 视图类型 |
|---|---|
srv_view.c |
动态视图总入口 |
srv_view_sess.c |
会话相关视图 |
srv_view_lock.c |
锁相关视图 |
srv_view_sga.c |
内存/SGA 视图 |
srv_view_stat.c |
统计信息视图 |
srv_view_dtc_local.c |
DTC 集群本地视图 |
4.6 统计信息与黑匣子
pkg/src/server/srv_stat.c: 运行期统计信息收集。pkg/src/server/srv_blackbox.c: 崩溃时收集上下文,辅助问题定位。
五、实战:启动与状态查看
5.1 启动 cantiand
bash
# 默认 open 模式
/opt/cantian/app/cantiand/bin/cantiand -D /data/cantian
# 指定 mount 模式(维护场景)
/opt/cantian/app/cantiand/bin/cantiand mount -D /data/cantian
# 查看帮助
/opt/cantian/app/cantiand/bin/cantiand -h
5.2 查看进程状态
bash
ps -ef | grep cantiand
# 输出示例:
# ctdba 12345 1 0 10:00 ? 00:00:05 cantiand -D /data/cantian
5.3 查看动态视图(gsql)
sql
-- 查看会话
SELECT * FROM v$session;
-- 查看锁
SELECT * FROM v$lock;
-- 查看 SGA
SELECT * FROM v$sga;
-- 查看参数
SHOW PARAMETER max_sessions;
八、常见问题与排查
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| 启动失败,提示参数错误 | cantiand.ini 配置不正确 |
检查 srv_param.c 加载日志 |
| 端口被占用 | 已有 cantiand 实例运行 | lsof -i :端口 |
| 共享内存不足 | shmmax/shmall 过小 |
cat /proc/sys/kernel/shmmax |
| mount 成功但 open 失败 | 数据文件损坏或丢失 | 检查控制文件与数据文件路径 |
| 客户端连接被拒绝 | 监听器未启动或防火墙限制 | 检查 srv_lsnr.c 日志 |
九、总结
cantiand 作为 Cantian 引擎的服务端主进程,承担着实例生命周期管理、网络服务、会话调度、参数管理、运行监控等核心职责。其设计借鉴了经典数据库服务器的三层启动模型(nomount/mount/open),采用单进程多线程架构,通过 Listener + Reactor + Agent 的分层模型实现高并发网络处理。
掌握 cantiand 的架构与启动流程,是理解 Cantian 整体运行机制、进行故障排查和性能调优的关键基础。
声明: 本文基于 Cantian 开源项目源码分析,部分实现细节可能随版本变化。