
在当今数据驱动的时代,数据库作为核心基础设施,其性能、稳定性与可扩展性直接决定了上层业务的效率与边界。面对高并发交易、海量数据实时更新与复杂业务逻辑的挑战,一个更强大、更智能的数据库引擎成为技术选型的关键。本文将为您呈现一次对开源数据库新星 OpenTeleDB 的深度探索与实践。我们将从其核心架构与源码编译开始,深入评测其创新的 XStore 存储引擎在高频更新场景下的性能与空间控制能力,实战部署并验证 XProxy 连接池如何突破连接数瓶颈,最终在模拟的真实在线支付场景中,以 5000 并发量级的压力测试,全面检验其在极端条件下的数据一致性与事务处理效能。
我选择在CentOS 7.9环境下进行测试,这是目前企业环境中最常见的配置。
基础依赖安装:
# 安装Git和基础编译工具
sudo yum install -y git gcc gcc-c++ make
# 安装依赖
sudo yum install -y \
gcc gcc-c++ make \
readline-devel \
zlib-devel \
openssl-devel \
libxml2-devel \
perl-devel \
flex \
bison \
libicu-devel \
zstd-devel \
libzstd-devel \
lz4-devel
获取源码:
cd /opt
git clone https://gitee.com/teledb/openteledb.git
cd openteledb
第一次浏览代码目录结构时,我注意到几个关键目录:
contrib/xstore/ - 新型存储引擎contrib/xproxy/ - 连接池代理
这种模块化设计让我对代码质量有了初步信心。
./configure \
--prefix=/root/openteledb \
--with-openssl \
--with-xstore \
--with-zstd \
--with-lz4
# 编译安装
make -j4 && sudo make install
编译过程观察:
创建运行用户:
sudo useradd -m -s /bin/bash pguser
sudo mkdir -p /root/openteledb
chmod 755 /root
chmod -R 755 /root/openteledb
sudo chown -R pguser:pguser /root/openteledb
初始化数据库:
sudo su - pguser
/root/openteledb/bin/initdb -D /root/openteledb/data
核心配置调整:
这里修改/root/openteledb/data/postgresql.conf配置文件,max_connections最大并发连接数设置成500

shared_buffers共享内存缓冲区大小设置成4G

启动数据库:
# 启动数据库
/root/openteledb/bin/pg_ctl -D /root/openteledb/data -l /root/openteledb/logfile start
# 连接数据库
/root/openteledb/bin/psql -d postgres
# 停止数据库
/root/openteledb/bin/pg_ctl -D /root/openteledb/data stop
硬件配置:
测试目标:
验证XStore在高频更新场景下的空间控制能力和性能稳定性。
创建测试表:
-- 连接数据库
/root/openteledb/bin/psql -d postgres
-- 创建XStore扩展
CREATE EXTENSION IF NOT EXISTS xstore;
-- XStore表
CREATE TABLE user_balance_xstore (
user_id BIGINT PRIMARY KEY,
balance NUMERIC(15,2) NOT NULL,
last_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_count INT DEFAULT 0
) USING xstore;
-- 传统Heap表
CREATE TABLE user_balance_heap (
user_id BIGINT PRIMARY KEY,
balance NUMERIC(15,2) NOT NULL,
last_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_count INT DEFAULT 0
);
-- 创建索引
CREATE INDEX idx_xstore_balance ON user_balance_xstore USING xbtree(balance);
CREATE INDEX idx_heap_balance ON user_balance_heap(balance);
初始化测试数据:
user_balance_xstore 和user_balance_heap 表分别插入200万用户数据
-- 插入200万用户数据
INSERT INTO user_balance_xstore (user_id, balance)
SELECT
generate_series(1, 2000000),
(random() * 10000)::numeric(15,2);
INSERT INTO user_balance_heap (user_id, balance)
SELECT
generate_series(1, 2000000),
(random() * 10000)::numeric(15,2);
-- 分析表
ANALYZE user_balance_xstore;
ANALYZE user_balance_heap;
初始空间占用:
SELECT
'xstore' as type,
pg_size_pretty(pg_total_relation_size('user_balance_xstore')) as total,
pg_size_pretty(pg_relation_size('user_balance_xstore')) as table_size,
pg_size_pretty(pg_indexes_size('user_balance_xstore')) as index_size
UNION ALL
SELECT
'heap',
pg_size_pretty(pg_total_relation_size('user_balance_heap')),
pg_size_pretty(pg_relation_size('user_balance_heap')),
pg_size_pretty(pg_indexes_size('user_balance_heap'));
初始结果:
type | total | table_size | index_size |
|---|---|---|---|
xstore | 292 MB | 116 MB | 177 MB |
heap | 217 M6 | 115 MB | 101 MB |
创建更新脚本:
创建个更新脚本,用于随机更新用户余额,以便通过pgbench工具对比xstore和heap两种存储引擎的UPDATE性能。
# 直接在终端执行(复制粘贴即可)
cat > /tmp/update_balance.sql << 'EOF'
\set user_id random(1, 2000000)
\set amount random(-100, 100)
UPDATE user_balance_xstore
SET balance = balance + :amount,
last_update = CURRENT_TIMESTAMP,
update_count = update_count + 1
WHERE user_id = :user_id;
EOF
cat > /tmp/update_balance_heap.sql << 'EOF'
\set user_id random(1, 2000000)
\set amount random(-100, 100)
UPDATE user_balance_heap
SET balance = balance + :amount,
last_update = CURRENT_TIMESTAMP,
update_count = update_count + 1
WHERE user_id = :user_id;
EOF
cat > /root/run_benchmark_parallel.sh << 'EOF'
#!/bin/bash
# 同时启动两个压测(后台运行)
echo ">>> 开始并行压测 (5分钟)..."
echo ""
# XStore 压测
/root/openteledb/bin/pgbench \
-U pguser -n \
-c 100 -j 8 -T 300 -P 5 \
-f /tmp/update_balance.sql \
postgres > /root/xstore_result.txt 2>&1 &
XSTORE_PID=$!
# Heap 压测
/root/openteledb/bin/pgbench \
-U pguser -n \
-c 100 -j 8 -T 300 -P 5 \
-f /tmp/update_balance_heap.sql \
postgres > /root/heap_result.txt 2>&1 &
HEAP_PID=$!
echo "XStore 压测进程: $XSTORE_PID"
echo "Heap 压测进程: $HEAP_PID"
echo ""
# 等待两个进程完成
echo "等待测试完成..."
wait $XSTORE_PID
echo "✓ XStore 测试完成"
wait $HEAP_PID
echo "✓ Heap 测试完成"
echo ""
# 对比结果
echo "=========================================="
echo "TPS 性能对比"
echo "=========================================="
echo ""
echo "XStore 引擎:"
grep "tps =" /root/xstore_result.txt | tail -2
echo ""
echo "Heap 引擎:"
grep "tps =" /root/heap_result.txt | tail -2
echo ""
EOF
chmod +x /root/run_benchmark_parallel.sh执行压测(5分钟):
这里并发压测两种存储引擎5分钟(100并发×8线程),对比UPDATE性能
# 执行脚本
/root/run_benchmark_parallel.sh type | total | table_size | index_size
--------+--------+------------+------------
xstore | 306 MB | 116 MB | 190 MB
heap | 249 MB | 122 MB | 127 MB
时间点 | XStore总大小 | Heap总大小 |
|---|---|---|
初始 | 116 MB | 115 MB |
5分钟 | 116 MB | 122 MB |
最原始的XStore总大小是116MB,经过高频更新压测后,XStore总大小依旧是116MB。
最终可得出结论,XStore最终表大小无膨胀。这说明官方文档所说的"原位更新"机制确实生效了。
安装CMake:
sudo yum install -y cmake3
sudo ln -s /usr/bin/cmake3 /usr/bin/cmake
编译XProxy:
cd /opt/openteledb/contrib/xproxy
chmod +x ./ctg_build.sh
./ctg_build.sh
# 检查编译结果
cd xproxy
ls -lh bin/
创建配置目录:
sudo mkdir -p /etc/xproxy
sudo mkdir -p /var/log/xproxy
sudo mkdir -p /var/run/xproxy
sudo chown -R pguser:pguser /etc/xproxy /var/log/xproxy /var/run/xproxy
核心配置文件:
cd /opt/openteledb/contrib/xproxy/xproxy
# 停止可能存在的进程
pkill -f xproxy
# 重新创建配置文件(修正路径)
cat > etc/xproxy_test.conf << 'EOF'
# 服务相关配置
daemonize yes
unix_socket_dir "/tmp"
unix_socket_mode "0644"
locks_dir "/tmp/odyssey"
pid_file "/opt/openteledb/contrib/xproxy/xproxy/run/xproxy.pid"
# 日志相关的配置
log_file "/opt/openteledb/contrib/xproxy/xproxy/log/xproxy.log"
log_format "%p %t %l [%i %s] (%c) %m\n"
log_to_stdout no
log_syslog no
log_debug no
log_config yes
log_session yes
log_query no
log_stats yes
stats_interval 60
# 性能相关配置
workers 4
resolvers 1
readahead 8192
cache_coroutine 100112
coroutine_stack_size 4
# 全局限制
client_max 200000
server_login_retry 1
# 监听端口配置
listen {
host "*"
port 6432
backlog 4096
}
# 存储节点配置
storage "postgres_server" {
type "remote"
endpoints {
endpoint {
hostname "127.0.0.1"
port 5432
weight 1.0
application_name ""
}
}
target_session_attrs "read-write"
watchdog {
storage "postgres_server"
storage_db "postgres"
storage_user "pguser"
storage_password "pguser"
pool_routing "internal"
pool "transaction"
pool_size 10
pool_timeout 0
pool_ttl 0
log_debug no
replication_delay_threshold 0
catchup_timeout 15
}
}
# 数据库和用户配置
database default {
user "user_aq_internal_pooling" {
authentication "none"
storage "postgres_server"
pool "session"
storage_db "postgres"
storage_user "pguser"
storage_password "pguser"
log_debug no
log_query no
pool_size 10
pool_timeout 10000
pool_routing "internal"
enable_quantiles_state yes
catchup_timeout 4
}
user default {
authentication "scram-sha-256"
auth_query "SELECT usename, passwd FROM pg_shadow WHERE usename=$1"
auth_query_db "postgres"
auth_query_user "user_aq_internal_pooling"
target_server_attrs "auto"
client_max 100000
storage "postgres_server"
pool "transaction"
pool_size 112
pool_timeout 0
pool_ttl 1800
pool_cancel yes
pool_rollback yes
client_fwd_error yes
server_lifetime 3600
log_debug no
enable_quantiles_state yes
catchup_timeout 5
}
}
# 管控数据库配置
storage "local" {
type "local"
}
database "console" {
user default {
authentication "scram-sha-256"
auth_query "SELECT usename, passwd FROM pg_shadow WHERE usename=$1"
auth_query_db "postgres"
auth_query_user "user_aq_internal_pooling"
role "admin"
pool "session"
storage "local"
quantiles "0.95,0.5"
}
}
EOF
# 确保目录存在
mkdir -p log run /tmp/odyssey启动XProxy:
cd /opt/openteledb/contrib/xproxy/xproxy
./bin/xproxy-start.sh ./etc/xproxy_test.conf
# 检查启动状态
netstat -tlnp | grep 6432
# 切换到pguser用户
sudo su - pguser
# 初始化数据
/root/openteledb/bin/pgbench -i postgres场景1: 连接数压力测试
# 直连数据库(会失败)
/root/openteledb/bin/pgbench \
-h 127.0.0.1 -p 5432 \
-U pguser \
-c 2000 -j 16 -T 60 -S \
postgres
# 通过XProxy(成功)
/root/openteledb/bin/pgbench \
-h 127.0.0.1 -p 6432 \
-U pguser \
-c 2000 -j 16 -T 60 -S \
postgres直连结果:
这里出现了连接数超限错误,直连PostgreSQL时,2000个并发超过了max_connections限制

FATAL: sorry, too many clients already
connection to database "postgres" failedXProxy结果:

2000个客户端全部连接成功,失败失误率为0
pgbench (17.6)
starting vacuum...end.
transaction type: <builtin: select only>
scaling factor: 1
query mode: simple
number of clients: 2000
number of threads: 16
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 6929942
number of failed transactions: 0 (0.000%)
latency average = 17.099 ms
initial connection time = 837.522 ms
tps = 116962.759893 (without initial connection time)业务背景:
模拟一个支付系统,需要处理:
数据模型设计:
-- 账户表(使用XStore)
CREATE TABLE accounts (
account_id BIGSERIAL PRIMARY KEY,
user_name VARCHAR(100) NOT NULL,
balance NUMERIC(15,2) NOT NULL CHECK (balance >= 0),
frozen_amount NUMERIC(15,2) DEFAULT 0,
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) USING xstore;
-- 交易流水表(使用XStore)
CREATE TABLE transactions (
txn_id BIGSERIAL PRIMARY KEY,
from_account BIGINT NOT NULL,
to_account BIGINT NOT NULL,
amount NUMERIC(15,2) NOT NULL,
txn_type VARCHAR(20) NOT NULL,
txn_status VARCHAR(20) DEFAULT 'pending',
txn_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
complete_time TIMESTAMP,
remark TEXT
) USING xstore;
-- 创建索引
CREATE INDEX idx_accounts_status ON accounts USING xbtree(status);
CREATE INDEX idx_txn_from ON transactions USING xbtree(from_account);
CREATE INDEX idx_txn_to ON transactions USING xbtree(to_account);
CREATE INDEX idx_txn_time ON transactions USING xbtree(txn_time);
初始化测试账户:
-- 创建100万个测试账户
INSERT INTO accounts (user_name, balance)
SELECT
'user_' || i,
(random() * 10000 + 1000)::numeric(15,2)
FROM generate_series(1, 1000000) i;
CREATE OR REPLACE FUNCTION transfer_money(
p_from_account BIGINT,
p_to_account BIGINT,
p_amount NUMERIC(15,2)
) RETURNS TABLE(
success BOOLEAN,
message TEXT,
txn_id BIGINT
) AS $$
DECLARE
v_from_balance NUMERIC(15,2);
v_txn_id BIGINT;
BEGIN
-- 参数校验
IF p_amount <= 0 THEN
RETURN QUERY SELECT FALSE, 'Invalid amount', NULL::BIGINT;
RETURN;
END IF;
IF p_from_account = p_to_account THEN
RETURN QUERY SELECT FALSE, 'Cannot transfer to self', NULL::BIGINT;
RETURN;
END IF;
-- 锁定转出账户并检查余额
SELECT balance INTO v_from_balance
FROM accounts
WHERE account_id = p_from_account
AND status = 'active'
FOR UPDATE;
IF NOT FOUND THEN
RETURN QUERY SELECT FALSE, 'From account not found or inactive', NULL::BIGINT;
RETURN;
END IF;
IF v_from_balance < p_amount THEN
RETURN QUERY SELECT FALSE, 'Insufficient balance', NULL::BIGINT;
RETURN;
END IF;
-- 锁定转入账户
PERFORM 1 FROM accounts
WHERE account_id = p_to_account
AND status = 'active'
FOR UPDATE;
IF NOT FOUND THEN
RETURN QUERY SELECT FALSE, 'To account not found or inactive', NULL::BIGINT;
RETURN;
END IF;
-- 创建交易记录
INSERT INTO transactions (
from_account, to_account, amount,
txn_type, txn_status
) VALUES (
p_from_account, p_to_account, p_amount,
'transfer', 'processing'
) RETURNING transactions.txn_id INTO v_txn_id;
-- 扣减转出账户余额
UPDATE accounts
SET balance = balance - p_amount,
updated_at = CURRENT_TIMESTAMP
WHERE account_id = p_from_account;
-- 增加转入账户余额
UPDATE accounts
SET balance = balance + p_amount,
updated_at = CURRENT_TIMESTAMP
WHERE account_id = p_to_account;
-- 更新交易状态
UPDATE transactions
SET txn_status = 'completed',
complete_time = CURRENT_TIMESTAMP
WHERE txn_id = v_txn_id;
RETURN QUERY SELECT TRUE, 'Transfer successful', v_txn_id;
EXCEPTION
WHEN OTHERS THEN
RETURN QUERY SELECT FALSE, 'System error: ' || SQLERRM, NULL::BIGINT;
END;
$$ LANGUAGE plpgsql;
创建压测脚本:
cat > /tmp/transfer_test.sql << 'EOF'
\set from_id random(1, 1000000)
\set to_id random(1, 1000000)
\set amount random(1, 100)
BEGIN;
WITH valid_accounts AS (
SELECT account_id FROM accounts WHERE status = 'active' LIMIT 2
)
SELECT * FROM transfer_money(
COALESCE((SELECT account_id FROM valid_accounts OFFSET 0 LIMIT 1), :from_id),
COALESCE((SELECT account_id FROM valid_accounts OFFSET 1 LIMIT 1), :to_id),
:amount
);
COMMIT;
EOF
执行压测:
/root/openteledb/bin/pgbench \
-h 127.0.0.1 -p 6432 \
-U pguser \
-c 5000 -j 16 -T 300 \
-P 1 \
-f /tmp/transfer_test.sql \
postgres 2>&1 | tee transfer_result.txt压测结果:
number of clients: 5000
number of threads: 16
maximum number of tries: 1
duration: 300 s
number of transactions actually processed: 1441317
number of failed transactions: 0 (0.000%)
latency average = 1038.233 ms
latency stddev = 17399.502 ms
initial connection time = 1783.423 ms
tps = 4798.146907 (without initial connection time)5000个并发客户端在5分钟内完成了144万笔转账交易,平均TPS达到4798,平均延迟1秒,无失败交易,XProxy连接池成功支撑了高并发场景。

检查账户总金额:
-- 压测前总金额
SELECT SUM(balance) as total_before FROM accounts;
-- 结果: 5999995732.20
-- 压测后总金额
SELECT SUM(balance) as total_after FROM accounts;
-- 结果: 5999995732.20
-- 金额守恒,无数据丢失!
OpenTeleDB 在 CentOS 7.9 环境中表现出卓越的性能与稳定性,其 XStore 存储引擎通过“原位更新”机制有效抑制了表膨胀,在高频更新场景下空间控制优势明显;XProxy 连接池成功支撑了 5000 级并发连接,解决了原生连接数限制的瓶颈;结合真实支付业务场景的 5000 并发压测,系统在 5 分钟内完成了 144 万笔转账,平均 TPS 达 4798 且零失败,证明了其在企业级高并发、高频更新业务中具备良好的数据一致性与高性能潜力。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。