资讯详情

资讯详情

Neon 扩展中的 Communicator 后台工作进程:PostgreSQL 与 Pageserver 通信架构解析

Neon 扩展中的 Communicator 后台工作进程PostgreSQL 与 Pageserver 通信架构解析【免费下载链接】neonNeon: Serverless Postgres. We separated storage and compute to offer autoscaling, code-like database branching, and scale to zero.项目地址: https://gitcode.com/GitHub_Trending/ne/neon导读Communicator全称 compute-pageserver communicator是 Neon Serverless Postgres 的 neon 扩展内部一个独立的后台工作进程background worker。它以 C 语言为骨架、Rust 为核心运行时目前承担着在计算节点compute上对外暴露 Prometheus 指标 HTTP 端点的职责并被设计为未来所有 compute 与 pageserver 之间通信的承载者。读完本文你将理解 Communicator 的进程模型、源码组织结构、启动与运行机制、指标端点的使用方式以及它是如何把 Rust 的异步运行时与 PostgreSQL 后台进程焊接在一起的。什么是 CommunicatorCommunicator 是运行在 PostgreSQL 服务器内部的一个独立后台工作进程属于 neon 扩展的一部分源代码位于 pgxn/neon/communicator/。根据其 README 的定义它是一个独立于普通后端连接的后台进程由 postmaster 负责拉起与重启当前阶段它只提供一个 HTTP 端点用于输出指标metrics未来它将会演进为处理与 pageserver 之间所有通信的单一入口。这一点在 C 入口文件的注释中得到印证communicator_process.c开头明确写道 Currently, the communicator process only functions as a metrics exporter. It provides an HTTP endpoint for polling a limited set of metrics. TODO: In the future, it will do much more, i.e. handle all the communications with the pageservers.见 communicator_process.c。源码结构一个进程两套语言Communicator 的代码采用 C 外壳 Rust 内核 的混合架构README 给出了两条主要的源码入口路径职责pgxn/neon/communicator_process.c启动 communicator 进程所需的 C 代码以及连接 PostgreSQL 与 Rust 代码的胶水层pgxn/neon/communicator/src/worker_process/Worker 进程的主循环与胶水代码Rust 侧src/worker_process/目录内部按职责拆分得很清晰mod.rs— 模块声明注释说明其职责是启动主循环、接收来自后端的 IO 请求并处理、把结果写回后端main_loop.rs— 创建 tokio 多线程运行时并启动控制套接字监听worker_interface.rs— 暴露给 C 代码调用的extern C函数communicator_worker_launchcontrol_socket.rs— 基于 axum 的 HTTP 指标服务lfc_metrics.rs— 本地文件缓存Local File Cache指标采集器logging.rs— 把 Rusttracing日志转发到 PostgreSQL 日志系统callbacks.rs— Rust 反向调用 C 的回调函数。顶层的 lib.rs 定义了一个关键常量控制套接字名NEON_COMMUNICATOR_SOCKET_NAME neon-communicator.socket它位于 PostgreSQL 数据目录之下。编译期产物libcommunicator.aREADME 明确指出编译时pgxn/neon/communicator/会产出一个静态库libcommunicator.a链接进neon.so扩展库。这一流程在 pgxn/neon/Makefile 中有完整实现communicator.o \ communicator_process.o \ ... $(NEON_CARGO_ARTIFACT_TARGET_DIR)/libcommunicator.a ... # libcommunicator.a is built by cargo from the Rust sources under communicator/ # subdirectory. cargo build also generates communicator_bindings.h. communicator_process.o: communicator/communicator_bindings.h ... $(NEON_CARGO_ARTIFACT_TARGET_DIR)/libcommunicator.a communicator/communicator_bindings.h : (cd $(srcdir)/communicator cargo build $(CARGO_BUILD_FLAGS) $(CARGO_PROFILE))也就是说构建顺序是先用 Cargo 编译 Rust 源码得到libcommunicator.a同时借助 cbindgen配置见 cbindgen.toml输出 C 语言头文件生成communicator_bindings.h随后 C 源码通过该头文件调用 Rust 侧导出符号。在 Cargo.toml 中可以看到crate-type [staticlib]的设置依赖包括 axumHTTP 框架、tokio异步运行时、tracing日志以及项目内部的measured指标库、utils、workspace_hack等 crate。进程生命周期从 neon 扩展到独立后台进程注册pg_init_communicator_processCommunicator 的启动入口是pg_init_communicator_process()它在 neon 扩展加载时被调用见 neon.c 的调用点。该函数运行在 postmaster 上下文中负责构造并注册一个 PostgreSQLBackgroundWorkerbgw_flags BGWORKER_SHMEM_ACCESS需要访问共享内存bgw_start_time BgWorkerStart_PostmasterStartpostmaster 一启动就拉起bgw_library_name neon、bgw_function_name communicator_new_bgworker_main指定入口函数所在扩展与函数名bgw_name/bgw_type Storage communicator process进程显示名称bgw_restart_time 5崩溃后 5 秒自动重启。以上见 communicator_process.c。这个 5 秒重启策略保证了指标端点的高可用性——即使 worker 异常退出postmaster 也会按 PostgreSQL 后台进程的标准机制把它重新拉起。进入 worker 主函数communicator_new_bgworker_main进程被 postmaster fork 出来后执行communicator_new_bgworker_main()其初始化序列非常讲究伪装成 WAL senderam_walsender true; MarkPostmasterChildWalSender();。注释说明这样做会改变关闭顺序——WAL sender 是最后一批被关闭的进程在最终 checkpoint 之后这正是 communicator 想要的communicator_process.c。安装信号处理器SIGUSR1procsignal、SIGUSR2postmaster 通知所有后端退出后自己也退出、SIGHUP配置重载、SIGTERM退出。提升日志级别SetConfigOption(log_min_messages, INFO, ...)让 Rust 侧发出的tracing::info!消息能够被打印communicator_process.c。配置日志转发通道调用 Rust 导出的communicator_worker_configure_logging()。启动 Rust 运行时调用communicator_worker_launch(neon_tenant, neon_timeline, errmsg)。neon_tenant/neon_timeline来自 neon 扩展的 GUC 参数如果为空字符串则传 NULL——对应 README 中所说的 非 Neon 模式本地存储主要用于单元测试。启动失败则elog(PANIC)。Rust 运行时启动communicator_worker_launch该函数的实现在 worker_interface.rs它以#[unsafe(no_mangle)] pub extern C形式导出签名与 C 侧声明严格对应。核心逻辑委托给main_loop::init()main_loop.rs校验tenant_id/timeline_id格式TenantId::from_str/TimelineId::from_str创建 tokio 多线程运行时线程名为communicator thread把持有运行时的结构体Box::leak到堆上——注释特别提醒绝不能 drop 运行时否则所有 tokio 任务都会随之销毁在运行时上block_on启动控制套接字监听器。主线程循环与 PostgreSQL 交互的唯一通道Rust 运行时启动后C 主线程进入一个for (;;)循环communicator_process.c职责非常克制ResetLatch(MyLatch)复位等待闩锁pump_logging(logging)把 Rust 线程产生的日志消息转发到 PostgreSQL 日志CHECK_FOR_INTERRUPTS()处理关闭、重载等中断若ConfigReloadPending则执行ProcessConfigFile(PGC_SIGHUP)测量中断处理耗时若超过 100ms 会打出 WARNING防止日志时间戳偏差过大WaitLatch(...)挂起等待直到 Rust 线程通过回调callback_set_my_latch_unsafe()唤醒它有新日志或 postmaster 死亡WL_EXIT_ON_PM_DEATH。注释中特别强调了一个隐患communicator_process.c该进程现在是多线程的。Rust 线程绝不调用任何 PostgreSQL 函数而主线程哪些 PG 函数安全可调也不完全清楚因此这里不能轻易添加非平凡逻辑——这是混合架构下典型的线程安全约束。HTTP 指标端点当前的唯一对外接口控制套接字与路由control_socket.rs用 axum 构建了一个监听在 Unix Domain Socket 上的 HTTP 服务套接字文件名为neon-communicator.socket位于 PostgreSQL 数据目录下。启动时会先尝试删除可能残留的旧套接字文件再UnixListener::bind最后tokio::spawn一个任务执行axum::servecontrol_socket.rs。当前注册了三个路由路由说明/metrics输出全部 Prometheus 指标当前即 LFC 相关指标/autoscaling_metrics输出指标的子集供自动扩缩容autoscalingagent 使用目前即 LFC 指标组/debug/panic调试用人为触发 handler 任务 panic用于验证进程崩溃-重启路径响应统一通过metrics_to_response()以 Prometheus 文本格式BufferedTextEncoder返回Content-Type为application/textcontrol_socket.rs。用 curl 访问指标README 与control_socket.rs的文档注释给出了标准的访问方式因为服务监听在 Unix Domain Socket 上需要 curl 的--unix-socket选项同时指定任意 HTTP Host如localhostcurl --unix-socket neon-communicator.socket http://localhost/metrics注意需要在 PostgreSQL 数据目录下执行因为套接字文件位于数据目录内。自动扩缩容侧的指标则对应curl --unix-socket neon-communicator.socket http://localhost/autoscaling_metrics指标内容本地文件缓存LFC指标/metrics与/autoscaling_metrics目前输出的都是 LFCLocal File Cache本地文件缓存指标采集器定义在 lfc_metrics.rs指标名含义lfc_cache_size_limitLFC 缓存大小上限字节lfc_hits缓存命中次数lfc_misses缓存未命中次数lfc_used已使用的缓存 chunk 数1 chunk 1MBlfc_writes缓存写入次数lfc_approximate_working_set_size_windows近似工作集大小以 8192 字节的页为单位按 60 个时间窗口每个窗口 1 分钟编码为duration_seconds标签取值 60、120、…、3600 秒分布其中lfc_approximate_working_set_size_windows是唯一带标签的指标MinuteAsSeconds实现了FixedCardinalityLabel基数 60把索引 0..60 映射为 60 到 3600 秒的时长标签。这些指标的值并非 Rust 侧自行维护而是通过 C 回调callback_get_lfc_metrics()从 PostgreSQL 侧的文件缓存file_cache.c实时拉取——即每次采集时通过callbacks.rs中声明的回调穿透到 C 代码读取计数器。日志桥接让 Rust 的 tracing 走进 PostgreSQL 日志多线程进程中最容易出问题的就是日志。Communicator 的设计是只有主线程能调用 PostgreSQL 的日志函数。日志流程在 logging.rs 中实现启动时用sync_channel(1000)创建容量为 1000 的有界同步通道Rust 各线程通过tracing的MakeWriter把格式化后的消息写入通道不阻塞队列满则丢弃并递增丢弃计数器DROPPED_EVENT_COUNT每次成功入队后调用callback_set_my_latch()唤醒主线程主线程在pump_logging()中通过communicator_worker_poll_logging()逐条取出消息把tracing::Level映射为 PostgreSQL 的elevelTRACE→DEBUG5、DEBUG→DEBUG1、INFO→INFO、WARN→WARNING、ERROR→ERROR再用ereport打印消息带[COMMUNICATOR]前缀队列满导致的丢弃消息会以 WARNING 汇总上报且放在循环外打印避免在日志系统拥塞时火上浇油。日志格式器SimpleFormatter特意不打印时间戳与级别——时间戳由主线程ereport()时统一打上避免了双时间戳来源的不一致。这套机制的完整闭环见 communicator_process.c。进程间协作C/Rust 双向 FFI 边界整个 Communicator 的运转依赖一组精心设计的跨语言接口可以从源码中归纳出三组契约C → Rust进程初始化与日志communicator_worker_configure_logging()、communicator_worker_poll_logging()、communicator_worker_launch(tenant_id, timeline_id, error_p)logging.rs、worker_interface.rs。错误信息以Box::leak的 C 字符串通过error_p返回。Rust → C回调callback_set_my_latch_unsafe()设置闩锁唤醒主线程、callback_get_lfc_metrics()读取 LFC 计数器。communicator_process.c末尾特别注明NOTE: These must be thread-safe!因为这些回调可能被任意 tokio 线程调用可用的 PostgreSQL 函数极其有限。类型契约所有跨边界函数都通过 cbindgen 生成的 communicator_bindings.h构建时自动生成见 Makefile 中的依赖规则在编译期保证签名一致。未来演进方向README 与多处源码注释反复强调 Communicator 的现状只是指标导出器其长期定位是compute 与 pageserver 之间所有通信的统一承载者lib.rs注释说该套接字serves the metrics, and other APIs in the futurecontrol_socket.rs注释说Currently, the control socket is used to provide information about the communicator process, file cache etc. as prometheus metrics. In the future, it can be used to expose more thingscommunicator_process.c的 TODO 明确了handle all the communications with the pageservers。从架构角度看把与 pageserver 的通信集中到一个独立后台进程天然具备以下收益与普通后端连接的查询生命周期解耦、可以独立维护长连接与重试状态、崩溃后由 postmaster 自动重启bgw_restart_time 5、并且通过统一指标端点便于可观测性建设。这与 Neon存储与计算分离的整体架构一脉相承可参考仓库根目录 README.md 对 autoscaling、scale to zero 等能力的定位。小结Communicator 是 Neon 计算节点内部一个典型的混合语言后台进程工程范本以 PostgreSQLBackgroundWorker为生命周期载体以 C 胶水层保证与 PG 内核交互的安全边界闩锁、信号、日志、回调以 Rust/tokio/axum 提供并发能力与 HTTP 服务能力。当前它稳定地输出 LFC 等 Prometheus 指标供监控与自动扩缩容使用其控制套接字、日志桥接与 FFI 边界都已为未来接管全部 pageserver 通信预留了清晰的扩展点。读者如需深入可继续阅读 communicator_process.c 的启动序列与 control_socket.rs 的路由实现并结合 Makefile 理解构建集成方式。【免费下载链接】neonNeon: Serverless Postgres. We separated storage and compute to offer autoscaling, code-like database branching, and scale to zero.项目地址: https://gitcode.com/GitHub_Trending/ne/neon创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →