准备环境
pgloader PostgreSQL Grafana 初始化数据库
启动 PostgreSQL 和 Grafana
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
version : '3.8'
services :
postgres :
image : postgres:15
network_mode : host
environment :
POSTGRES_DB : grafana
POSTGRES_USER : grafana
POSTGRES_PASSWORD : grafana
volumes :
- postgres_data:/var/lib/postgresql/data
- ./postgresql.conf:/etc/postgresql/postgresql.conf
command : postgres -c config_file=/etc/postgresql/postgresql.conf
grafana :
image : grafana/grafana:12.0.2
container_name : grafana
network_mode : host
environment :
- GF_DATABASE_TYPE=postgres
- GF_DATABASE_HOST=localhost:5432
- GF_DATABASE_NAME=grafana
- GF_DATABASE_USER=grafana
- GF_DATABASE_PASSWORD=grafana
- GF_DATABASE_SSL_MODE=disable
depends_on :
- postgres
volumes :
postgres_data :
driver : local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# PostgreSQL 配置文件 - 针对 Grafana 高可用部署优化
# 连接设置
listen_addresses = '*'
port = 5432
max_connections = 200
superuser_reserved_connections = 3
# 内存设置
shared_buffers = 256MB
effective_cache_size = 1GB
maintenance_work_mem = 64MB
work_mem = 4MB
# WAL 设置(用于复制)
wal_level = replica
max_wal_senders = 3
max_replication_slots = 3
wal_keep_size = 1GB
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/archive/%f'
# 检查点设置
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min
max_wal_size = 2GB
min_wal_size = 80MB
# 日志设置
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1d
log_rotation_size = 100MB
log_min_duration_statement = 1000
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_statement = 'ddl'
log_temp_files = 0
# 性能优化
random_page_cost = 1.1
effective_io_concurrency = 200
default_statistics_target = 100
# 安全设置
ssl = off
# 复制设置
hot_standby = on
hot_standby_feedback = on
max_standby_streaming_delay = 30s
wal_receiver_timeout = 60s
# 自动清理
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 1min
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
# 时区设置
timezone = 'UTC'
log_timezone = 'UTC'
# 区域设置
lc_messages = 'en_US.UTF-8'
lc_monetary = 'en_US.UTF-8'
lc_numeric = 'en_US.UTF-8'
lc_time = 'en_US.UTF-8'
default_text_search_config = 'pg_catalog.english'
导出 grafana
表结构
1
2
docker compose up -d
docker exec -ti postgres pg_dump --schema-only -U grafana grafana > grafana-schema.sql
清理 postgres
数据库
停止 postgres
和 grafana
,并删除 postgres
数据库
1
2
docker compose down
docker volumes rm postgres-data
导入 grafana
表结构
启动PostgreSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version : '3.8'
services :
postgres :
image : postgres:15
network_mode : host
environment :
POSTGRES_DB : grafana
POSTGRES_USER : grafana
POSTGRES_PASSWORD : grafana
volumes :
- postgres_data:/var/lib/postgresql/data
- ./postgresql.conf:/etc/postgresql/postgresql.conf
command : postgres -c config_file=/etc/postgresql/postgresql.conf -c hba_file=/etc/postgresql/pg_hba.conf
volumes :
postgres_data :
driver : local
1
docker exec -i postgres psql -h localhost -p 5432 -U grafana -d grafana < grafana-schema.sql
迁移数据
pgloader 脚本
1
2
3
4
5
6
7
8
9
load database
from sqlite : /// data / services / grafana / grafana . db
into postgresql : // grafana : grafana @ 127 . 0 . 0 . 1 / grafana
with data only , reset sequences ,
batch rows = 1000 ,
batch size = 10 MB ,
prefetch rows = 100
set work_mem to '16MB' ,
maintenance_work_mem to '512MB' ;
运行 pgloader
1
docker run -m 2g --rm -it --network host -v ` pwd ` :/data/services/grafana ghcr.io/dimitri/pgloader:latest pgloader /data/services/grafana/main.load
pgloader内存耗尽问题解决指南
在使用pgloader工具将SQLite数据迁移到PostgreSQL时,遇到以下错误:
1
2
3
4
5
fatal error encountered in SBCL pid 1 tid 9:
Heap exhausted, game over.
Welcome to LDB, a low-level debugger for the Lisp runtime environment.
(GC in progress, oldspace=1, newspace=7)
问题分析
根本原因
内存不足 :pgloader基于SBCL(Steel Bank Common Lisp)运行时,默认堆内存限制较小数据量过大 :SQLite数据库文件可能包含大量数据,超出了默认内存限制容器资源限制 :Docker容器可能没有分配足够的内存资源技术背景
pgloader使用SBCL作为运行时环境 SBCL默认堆大小通常为几百MB 大型数据迁移需要更多内存来处理数据缓冲 解决方案
方案1:增加Docker容器内存限制
1
2
3
4
5
6
# 为容器分配更多内存(例如4GB)
docker run --rm -it --network host \
--memory= 4g \
-v ` pwd ` :/data/services/grafana \
ghcr.io/dimitri/pgloader:latest \
pgloader /data/services/grafana/main.load
方案2:优化pgloader配置
修改 main.load
文件,添加内存优化参数:
1
2
3
4
5
6
7
8
9
load database
from sqlite : /// data / services / grafana / grafana . db
into postgresql : // grafana : grafana @ 127 . 0 . 0 . 1 / grafana
with data only , reset sequences ,
batch rows = 1000 ,
batch size = 10 MB ,
prefetch rows = 100
set work_mem to '16MB' ,
maintenance_work_mem to '512MB' ;
验证步骤
1. 检查容器资源
1
2
# 查看容器内存使用情况
docker stats --no-stream
2. 验证数据迁移
1
2
3
# 连接PostgreSQL检查数据
psql -h localhost -U grafana -d grafana -c "\dt"
psql -h localhost -U grafana -d grafana -c "SELECT count(*) FROM table_name;"
3. 检查Grafana连接
1
2
3
4
5
# 重启Grafana服务
docker-compose restart grafana
# 检查Grafana日志
docker-compose logs grafana
常见问题
Q1: 为什么pgloader会出现内存耗尽?
A: pgloader基于SBCL运行时,默认堆内存较小。处理大型数据库时需要更多内存来缓冲数据。
Q2: 如何确定需要多少内存?
A: 一般建议分配数据库文件大小的2-3倍内存。例如,100MB的SQLite文件建议分配300MB以上内存。
Q3: 迁移失败后如何恢复?
A: 清空PostgreSQL目标表,检查并修复配置后重新运行迁移。
相关文档
总结
pgloader内存耗尽问题主要由SBCL运行时的默认内存限制引起。通过增加Docker容器内存、优化pgloader配置、或使用分批迁移策略可以有效解决此问题。建议在大型数据迁移前进行充分的资源规划和测试。