0

我有一个 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 的​​ RAM。
  • 块间​​隔设置为 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 天查询时,内存使用量也不会增加。

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

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

4

1 回答 1

2

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 的默认值(非常)保守,几乎可以在任何地方运行。但是,您似乎想认真使用数据库,因此需要进行一些调整。

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

于 2019-06-28T11:27:02.313 回答