【问题标题】:Timescaledb memory consumption remains very low even when there is a lot of data即使有大量数据,Timescaledb 内存消耗仍然非常低
【发布时间】:2019-04-04 10:05:19
【问题描述】:

我有一个 timescaledb 设置,我定期转储数据(每 10 分钟左右)。它是使用 docker-compose 部署的。

数据包含一个 entity_id 和一个测量值以及一些其他的东西,例如区域等。

一个典型的查询是get per day minimum for last 30 days for an entity_id

    SELECT
        time_bucket_gapfill('1 day', time, date_trunc('day', now() - interval '30 days'), date_trunc('day', now())) AS one_day,
        country,
        type_id,
        min(measurement)
    FROM hypertable
    WHERE
        entity_id='XYZ' AND
        country='US' AND
        time > time_bucket('1 day', now() - interval '30 days') AND 
        time < time_bucket('1 day', now())
    GROUP BY one_day, country, type_id
  • 服务器有 8GB 内存。
  • 块间隔设置为 1 天。
  • 每个块的大小约为 4.5GB

                   chunk_table             | table_size | index_size | total_size
    ---------------------------------------|-------------------------|------------
    _timescaledb_internal._hyper_1_1_chunk |   696 MB   |  1675 MB   |   2370 MB
    _timescaledb_internal._hyper_1_2_chunk |  1318 MB   |  3223 MB   |   4540 MB
    _timescaledb_internal._hyper_1_3_chunk |  1318 MB   |  3222 MB   |   4539 MB
    _timescaledb_internal._hyper_1_4_chunk |  1318 MB   |  3223 MB   |   4540 MB
    

数据库目前大约有 24 个块(24 天的数据)。

我一直在使用wrk 进行一些基准测试和负载测试,发现大量查询需要几秒钟才能完成。 我看到的问题是 timescaledb 的 ram 使用量保持在 50MB 左右。并且在运行上述查询的负载测试期间达到约 100MB,而 CPU 使用率和磁盘 IO 显着上升。

我的期望是大约一大块(最近的)数据将在 RAM 中。 即使这个假设是错误的,当发出 30 天查询时,ram 使用量也不会增加。

我想了解这是预期行为还是设置有问题。

我尝试为 docker 容器设置内存预留和内存限制,但没有效果。

【问题讨论】:

标签: postgresql docker postgresql-11 timescaledb


【解决方案1】:

PostgreSQL的内存消耗主要与:

shared_buffers:整个 PostgreSQL 实例的恒定内存量,在所有会话之间共享。 work_mem 会话中可用于排序/散列操作的内存量。这可以在每个会话中多次使用。

如果您的数据库服务器上有空闲内存,增加shared_buffers 是有意义的,因此更多数据会保存在内存中。传统观点认为 25% 的可用 RAM 是一个很好的起点。当您使用 docker-compose 时,您可能与其他进程共享此服务器,因此您可能需要调整它以考虑到这一点。

您还可以/应该增加work_mem,以便更多的哈希/排序操作使用内存而不是磁盘。 work_mem 是一个可以在你的会话中设置的变量,所以你尝试了一些东西,比较下面的例子:

feike=# EXPLAIN (ANALYZE ON, BUFFERS ON) SELECT * FROM pg_class ORDER BY relfilenode;
                                                    QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Sort  (cost=230.82..234.95 rows=1652 width=782) (actual time=3.149..3.477 rows=1680 loops=1)
   Sort Key: relfilenode
   Sort Method: quicksort  Memory: 1246kB
   Buffers: shared hit=126
   ->  Seq Scan on pg_class  (cost=0.00..142.52 rows=1652 width=782) (actual time=0.015..0.627 rows=1680 loops=1)
         Buffers: shared hit=126
 Planning Time: 0.193 ms
 Execution Time: 3.908 ms
(8 rows)

feike=# set work_mem to '64kB';
SET
feike=# EXPLAIN (ANALYZE ON, BUFFERS ON) SELECT * FROM pg_class ORDER BY relfilenode;
                                                    QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Sort  (cost=1371.82..1375.95 rows=1652 width=782) (actual time=6.675..8.102 rows=1680 loops=1)
   Sort Key: relfilenode
   Sort Method: external merge  Disk: 832kB
   Buffers: shared hit=126, temp read=239 written=268
   ->  Seq Scan on pg_class  (cost=0.00..142.52 rows=1652 width=782) (actual time=0.015..0.654 rows=1680 loops=1)
         Buffers: shared hit=126
 Planning Time: 0.192 ms
 Execution Time: 8.993 ms
(8 rows)

计划的主要区别是:

   Sort Method: external merge  Disk: 832kB
   Sort Method: quicksort  Memory: 1246kB

了解work_mem 是否有用的最佳方法是:

EXPLAIN (ANALYZE ON, BUFFERS ON)
    SELECT
        time_bucket_gapfill('1 day', time, date_trunc('day', now() - interval '30 days'), date_trunc('day', now())) AS one_day,
        country,
        type_id,
        min(measurement)
    FROM hypertable
    WHERE
        entity_id='XYZ' AND
        country='US' AND
        time > time_bucket('1 day', now() - interval '30 days') AND 
        time < time_bucket('1 day', now())
    GROUP BY one_day, country, type_id

并寻找任何磁盘操作。

这条线看起来像这样:

Buffers: shared hit=96 read=44152

通知您您的 shared_buffers、它找到所需内容的次数 (hit) 以及从磁盘获取内容的频率 (read)。

答案有点长,但要点是您需要根据工作负载调整 PostgreSQL 实例的大小; PostgreSQL 的默认值(非常)保守,几乎可以在任何地方运行。但是,您似乎想认真使用数据库,因此需要进行一些调整。

一些工具可以帮助您做到这一点:

【讨论】:

  • 感谢飞客的详细解答。我能够调整参数以适应我的服务器。对于调优,还有pgtune.leopard.in.ua
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 2014-01-04
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多