说起PG的不合群, 最大的问题就是几乎所有的功能PG都可以通过插件来实现, 比如应用常用的搜索引擎需求、非结构化数据存储需求、向量类型和搜索需求、时序数据支持等. 通过tsvector, 内置JSON, pgvector, timescaledb等插件都能做.
PG是全能多模态数据库选手, 所以和其他产品的交集真的不多, 自然朋友圈就较小了, 不像MySQL的盆友圈那么大, 除了CRUD, 什么都要依赖其他产品.
不过你要对PG这个不合群做出改观了, 今天介绍一个将PG数据实时同步到 Elasticsearch / OpenSearch 搜索引擎的工具: pgsync
下面来详细了解一下 pgsync
https://github.com/toluaina/pgsync
PGSync 是一个中间件 (middleware),用于将 PostgreSQL 中的数据实时 (real-time) 同步到 Elasticsearch/OpenSearch 搜索集群中。它的核心目的是让 PostgreSQL 保持为事实来源 (source of truth)(用于事务 (transactions) 和持久化 (persistence)),而 Elasticsearch/OpenSearch 则作为只读的搜索层 (read-only search layer) 和非规范化文档 (denormalized documents) 的存储库。

PGSync 的工作流程依赖于 PostgreSQL 的两个关键功能和几个外部组件 :
组件 | 描述 |
|---|---|
PostgreSQL | 关系数据库 (relational database),是主数据源 (primary data source)。它利用 逻辑解码 (Logical Decoding) 捕获所有数据更改(WAL,即 Write-Ahead Log)。 |
Replication Slot/WAL | 逻辑解码 的输出流,包含 Insert、Update、Delete 等事件。PGSync Daemon 从此复制槽 (Replication Slot) 读取。 |
pg_notify (Triggers) | PGSync 在表上设置触发器 (Triggers),当发生数据更改时,通过 pg_notify 机制通知 PGSync Daemon 存在待处理的更改。 |
PGSync Daemon (SP) | 核心服务。它从 WAL 读取更改,或通过 pg_notify 接收通知。 |
Query Builder (QB) | PGSync 的查询引擎。它根据用户定义的 JSON Schema 动态生成复杂的 SQL 查询,以连接 (join) 相关表并将关系数据 (relational data) 转换为非规范化文档 (denormalized documents)。 |
JSON Documents (DOC) | Query Builder 执行 SQL 获得的结构化文档。 |
Elasticsearch/OpenSearch (ES) | 目标搜索引擎 (destination search engine)。JSON Documents 被批量索引到此。 |
Redis/Valkey (REDIS) | 用作消息代理 (message broker) 和检查点 (Checkpoint) 存储。它管理同步状态,确保故障容错 (Fault Tolerance)——即使服务崩溃也能从上次同步点恢复。 |
schema.json,定义 PostgreSQL 表如何映射和转换 (transform) 成 Elasticsearch/OpenSearch 文档结构。特性名称 | 作用 |
|---|---|
实时同步 (Real-Time Sync) | 利用 PostgreSQL 的逻辑解码,以最小延迟将更改反映到搜索索引中。 |
Schema-Based | 依靠 JSON 模式来定义复杂的数据映射 (mappings) 和转换 (transformations)。 |
嵌套关系 (Nested Relationships) | 能够处理复杂的 JOIN 操作,并将关系数据自动非规范化。 |
故障容错 (Fault Tolerance) | 通过 Redis/Valkey 存储检查点 (checkpoints),确保服务崩溃后能够优雅恢复并从上次同步点继续。 |
轻量级影响 (Lightweight Impact) | 对源数据库的负载最小,主要通过 WAL 读取,而非频繁查询。 |
PGSync 是一个中间件 (middleware),用于将数据从 Postgres 或 MySQL 或 MariaDB 轻松同步到 Elasticsearch/OpenSearch。
它允许您将 Postgres 或 MySQL 或 MariaDB 保持为您的事实来源 (source of truth),并在 Elasticsearch/OpenSearch 中公开结构化的非规范化文档 (structured denormalized documents)。
对嵌套实体 (nested entities) 的更改会被传播到 Elasticsearch/OpenSearch。
PGSync 的高级查询构建器会根据您的模式 (schema) 即时 (on the fly) 生成优化后的 SQL 查询 (optimized SQL queries)。 PGSync 的咨询模型 (advisory model) 允许您在保持关系完整性 (relational integrity) 的同时,快速移动和转换大量数据。
只需在 JSON 中描述您的文档结构 (document structure) 或模式 (schema),PGSync 就会持续捕获 (continuously capture) 您数据中的更改,并将其加载到 Elasticsearch/OpenSearch 中,无需编写任何代码。 PGSync 将您的关系数据 (relational data) 转换为结构化的文档格式 (structured document format)。
它允许您直接利用 Postgres 或 MySQL 或 MariaDB 的表现力 (expressive power) 和 Elasticsearch/OpenSearch 的可扩展性 (scalability)。 您不必编写复杂的查询和转换管道 (transformation pipelines)。 PGSync 轻量级、灵活且快速。
Elasticsearch/OpenSearch 更适合作为辅助的非规范化搜索引擎 (secondary denormalised search engine),以配合更传统的规范化数据存储 (normalized datastore)。 此外,您不应该将主数据 (primary data) 存储在 Elasticsearch/OpenSearch 中。
那么,您最初是如何将数据导入 Elasticsearch/OpenSearch 中的呢? 像 Logstash 和 Kafka 这样的工具可以协助完成这项任务,但它们仍然需要一些工程 (engineering) 和开发 (development) 工作。
抽取、转换、加载 (Extract Transform Load, ETL) 和变更数据捕获 (Change data capture, CDC) 工具可能很复杂,并且需要昂贵的工程投入。
PGSync 的其他优势包括:
从高层次上讲,您的数据位于 PostgreSQL/MySQL/MariaDB 数据库中,并且您希望将其镜像 (mirror) 到 Elasticsearch/OpenSearch 中。 这意味着您数据的每一个变化(Insert、Update、Delete 和 Truncate语句 (statements))都需要复制 (replicated) 到 Elasticsearch/OpenSearch。 起初,这看起来很容易,但随后就不容易了。只需添加一些代码,在更新数据库后将数据复制到 Elasticsearch/OpenSearch(即所谓的双写 (dual writes))。 编写跨越多个表 (spanning multiple tables) 并涉及多个关系 (multiple relationships) 的 SQL 查询很难。 检测嵌套文档 (Detecting changes within a nested document) 中的更改也可能相当困难。 当然,如果您的数据从未更改,那么您只需在时间点上拍摄快照 (take a snapshot in time) 并将其作为一次性操作加载到 Elasticsearch/OpenSearch 中即可。
如果出现以下情况,PGSync 适合您:
PGSync 由 Python 编写(支持 3.9 及更高版本),其堆栈 (stack) 由:Redis/Valkey、Elasticsearch/OpenSearch、Postgres/MySQL/MariaDB 和 SQLAlchemy 组成。
PGSync 利用 Postgres 的逻辑解码 (logical decoding) 功能(在 PostgreSQL 9.4 中引入)来捕获连续的更改事件流 (capture a continuous stream of change events)。
需要在您的 Postgres配置文件 (configuration file) 中通过设置 postgresql.conf 文件中的以下内容来启用 (enabled) 此功能:
wal_level = logical
您可以选择任何枢纽表 (pivot table) 作为您的文档的根 (root of your document)。
PGSync 的查询构建器 (query builder) 会针对您的模式 (schema) 动态 (dynamically) 构建高级查询 (advanced queries)。
PGSync 通过为数据库中的表创建触发器 (creating triggers for tables) 来处理通知事件 (notification events),从而在事件驱动模型 (event-driven model) 中运行。
这是 PGSync 唯一一次对您的数据库进行任何更改。
注意 (NOTE): 如果您更改了您的 PGSync 模式配置的结构,建议并且在大多数情况下有必要重建您的 Elasticsearch/OpenSearch 索引。
目前有计划支持零停机迁移 (zero-downtime migrations) 以简化此过程。
有几种安装和尝试 PGSync 的方法
在设置过程中填写以下内容:
ELASTICSEARCH_URL 例如:https://user:pass@os-host:443REDIS_URL 例如:rediss://default:pass@host:port/0使用 Docker 启动所有服务。
$ git checkout https://github.com/toluaina/pgsync
运行:
$ docker-compose up
显示 Elasticsearch/OpenSearch 中的内容
$ curl -X GET http://[Elasticsearch/OpenSearch host]:9201/reservations/_search?pretty=true
要使用 Docker 启动所有服务,请按照以下步骤操作:
$ docker pull toluaina1/pgsync:latest
docker run --rm -it \ -e REDIS_CHECKPOINT=true \ -e REDIS_HOST=<redis_host_address> \ -e PG_URL=postgres://<username>:<password>@<postgres_host>/<database> \ -e ELASTICSEARCH_URL=http://<elasticsearch_host>:9200 \ -v "
环境变量 (Environment variable) 占位符 (placeholders) - 完整列表 在此:
host.docker.internal)host.docker.internal)host.docker.internal)postgresql.conf 中设置至少两个参数 (parameters)wal_level = logical
max_replication_slots = 1
max_slot_wal_keep_size = 100GB
my.cnf 中设置以下参数 (parameters),然后重新启动数据库服务器 (restart the database server)。server-id = 1 # 任何非零的唯一 ID (unique ID)
log_bin = mysql-bin
binlog_row_image = FULL # 推荐;如果较旧的 MariaDB 不支持,则省略 (omit)
binlog_expire_logs_seconds = 604800 # 7 天sql CREATE USER 'replicator'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'replicator'@'%'; FLUSH PRIVILEGES;
pip 从 pypi安装 (Install) PGSync$ pip install pgsyncbootstrap --config schema.jsonpgsync --config schema.jsonpgsync --config schema.json -dPGSync 的关键特性是:
考虑这个图书库数据库 (Book library database) 的示例。
Book
isbn (PK) | title | description |
|---|---|---|
9785811243570 | Charlie and the chocolate factory | Willy Wonka’s famous chocolate factory is opening at last! |
9788374950978 | Kafka on the Shore | Kafka on the Shore is a 2002 novel by Japanese author Haruki Murakami. |
9781471331435 | 1984 | 1984 was George Orwell’s chilling prophecy about the dystopian future. |
Author
id (PK) | name |
|---|---|
1 | Roald Dahl |
2 | Haruki Murakami |
3 | Philip Gabriel |
4 | George Orwell |
BookAuthor
id (PK) | book_isbn | author_id |
|---|---|---|
1 | 9785811243570 | 1 |
2 | 9788374950978 | 2 |
3 | 9788374950978 | 3 |
4 | 9781471331435 | 4 |
使用 PGSync,我们可以简单地定义 (define) 这个 JSON模式 (schema),其中 book 表是枢纽 (pivot)。
枢纽表 (pivot table) 指示您的文档的根 (indicates the root of your document)。
{
"table": "book",
"columns": [
"isbn",
"title",
"description"
],
"children": [
{
"table": "author",
"columns": [
"name"
]
}
]
}
以获取 Elasticsearch/OpenSearch 中的此文档结构 (document structure):
[
{
"isbn": "9785811243570",
"title": "Charlie and the chocolate factory",
"description": "Willy Wonka’s famous chocolate factory is opening at last!",
"authors": ["Roald Dahl"]
},
{
"isbn": "9788374950978",
"title": "Kafka on the Shore",
"description": "Kafka on the Shore is a 2002 novel by Japanese author Haruki Murakami",
"authors": ["Haruki Murakami", "Philip Gabriel"]
},
{
"isbn": "9781471331435",
"title": "1984",
"description": "1984 was George Orwell’s chilling prophecy about the dystopian future",
"authors": ["George Orwell"]
}
]
在幕后,PGSync 正在为您生成高级查询 (generating advanced queries),例如。
SELECT
JSON_BUILD_OBJECT(
'isbn', book_1.isbn,
'title', book_1.title,
'description', book_1.description,
'authors', anon_1.authors
) AS"JSON_BUILD_OBJECT_1",
book_1.id
FROM book AS book_1
LEFTOUTERJOIN
(SELECT
JSON_AGG(anon_2.anon) ASauthors,
book_author_1.book_isbn AS book_isbn
FROM book_author AS book_author_1
LEFTOUTERJOIN
(SELECT
author_1.name AS anon,
author_1.id ASid
FROM author AS author_1) AS anon_2 ON anon_2.id = book_author_1.author_id
GROUPBY book_author_1.book_isbn) AS anon_1 ON anon_1.book_isbn = book_1.isbn
您还可以通过模式配置 (schema config) 配置 (configure) PGSync 来重命名属性 (rename attributes),例如
{
"isbn": "9781471331435",
"this_is_a_custom_title": "1984",
"desc": "1984 was George Orwell’s chilling prophecy about the dystopian future",
"contributors": ["George Orwell"]
}
PGSync 解决了常见的数据一致性挑战 (common data consistency challenges),例如:
PGSync 是一种简单、开箱即用 (simple, out-of-the-box) 的变更数据捕获 (change data capture) 解决方案,旨在最大限度地减少开发工作量 (minimize development effort) 并保持您的搜索索引同步 (keep your search indexes in sync)。