Потребление памяти Timescaledb остается очень низким даже при большом количестве данных - PullRequest
0 голосов
/ 04 апреля 2019

У меня есть настройка 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
  • Сервер имеет 8 ГБ ОЗУ.
  • Интервал порции установлен на 1 день.
  • Размер каждого куска составляет около 4,5 ГБ

                   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 остается на уровне около 50 МБ. И занимает около 100 МБ во время нагрузочного теста, выполняющего вышеуказанный запрос, в то время как загрузка ЦП и дисковый ввод-вывод значительно возрастают.

Я ожидал, что в оперативной памяти будет примерно один кусок (недавний) данных. Даже если это предположение неверно, использование оперативной памяти не увеличивается при выдаче 30-дневного запроса.

Я хочу понять, является ли это ожидаемым поведением или есть какие-то проблемы с настройкой.

Я попытался установить резервирование памяти и ограничения памяти для контейнера докера, но это не имело никакого эффекта.

1 Ответ

0 голосов
/ 28 июня 2019

Потребление памяти PostgreSQL в основном связано с:

shared_buffers : постоянный объем памяти для всего экземпляра PostgreSQL, общий для всех сеансов. work_mem Объем памяти, доступный для операций сортировки / хеширования в сеансе. Это может быть использовано несколько раз за сеанс.

Если у вас есть резервная память на вашем сервере БД, имеет смысл увеличить shared_buffers, чтобы в памяти оставалось больше данных. Традиционно считается, что 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 (очень) консервативны, что позволяет ему работать практически везде. Однако вы, похоже, хотите использовать базу данных всерьез, поэтому требуется некоторая настройка.

Некоторые инструменты, которые помогут вам сделать это:

...