即使有大量数据,Timescaledb的内存消耗仍然非常低

时间:2019-04-04 10:05:19

标签: postgresql docker postgresql-11 timescaledb

我有一个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天的查询时,ram的使用也不会增加。

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

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

1 个答案:

答案 0 :(得分:0)

PostgreSQL的内存消耗主要与以下方面有关:

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

如果您有足够的内存可用于DB Server,则增加shared_buffers是有意义的,因此会在内存中保留更多数据。传统观点认为,可用RAM的25%是一个很好的起点。在使用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的默认设置(非常)保守,这使得它几乎可以在任何地方运行。但是,您似乎想认真使用数据库,因此需要进行一些调整。

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