Tự động xâm lấn trên PostgreSQL


42

Tôi đang cố gắng để PostgreSQL tích cực tự động hút sạch cơ sở dữ liệu của tôi. Hiện tại tôi đã cấu hình chân không tự động như sau:

  • autovacuum_vacuum_cost_delay = 0 # Tắt chân không dựa trên chi phí
  • autovacuum_vacuum_cost_limit = 10000 #Max giá trị
  • autovacuum_vacuum_thr Ngưỡng = 50 # Giá trị lỗi
  • autovacuum_vacuum_scale_factor = 0,2 # Giá trị lỗi

Tôi nhận thấy rằng máy hút bụi tự động chỉ khởi động khi cơ sở dữ liệu không tải, vì vậy tôi gặp phải tình huống có nhiều bộ dữ liệu chết hơn so với bộ dữ liệu trực tiếp. Xem ảnh chụp màn hình đính kèm để biết ví dụ. Một trong số các bảng có 23 bộ dữ liệu trực tiếp nhưng 16845 bộ dữ liệu chết đang chờ chân không. Điều đó thật điên rồ!

Nhiều tuples chết

Máy hút bụi tự động khởi động khi quá trình chạy thử kết thúc và máy chủ cơ sở dữ liệu không hoạt động, đó không phải là điều tôi muốn vì tôi muốn máy hút bụi tự động khởi động bất cứ khi nào số lượng tuple chết vượt quá 20% bộ dữ liệu trực tiếp + 50, vì cơ sở dữ liệu đã được cấu hình. Tự động hút bụi khi máy chủ không hoạt động là vô dụng đối với tôi, vì máy chủ sản xuất dự kiến ​​sẽ đạt 1000 giây cập nhật / giây trong một thời gian duy trì, đó là lý do tại sao tôi cần máy hút bụi tự động để chạy ngay cả khi máy chủ đang tải.

Có điều gì tôi đang thiếu? Làm cách nào để buộc chân không tự động chạy trong khi máy chủ đang tải nặng?

Cập nhật

Đây có thể là một vấn đề khóa? Các bảng trong câu hỏi là các bảng tóm tắt được điền thông qua một trình kích hoạt chèn sau. Các bảng này được khóa trong chế độ CHIA SẺ ROW EXCLUSIVE để ngăn việc ghi đồng thời vào cùng một hàng.

Câu trả lời:


40

Eelke gần như chắc chắn chính xác rằng khóa của bạn đang chặn tự động. Autovacuum được thiết kế để nhường chỗ cho hoạt động của người dùng, có chủ ý. Nếu những bảng đó bị khóa, autovacuum không thể hút bụi chúng.

Tuy nhiên, đối với hậu thế, tôi muốn đưa ra một ví dụ về cài đặt cho chế độ tự động siêu tích cực, vì các cài đặt bạn đưa ra không thực hiện được. Lưu ý rằng làm cho autovacuum tích cực hơn không thể giải quyết vấn đề của bạn, tuy nhiên. Cũng lưu ý rằng cài đặt tự động mặc định dựa trên việc chạy hơn 200 lần chạy thử bằng DBT2, tìm kiếm sự kết hợp tối ưu của cài đặt, do đó, mặc định nên được coi là tốt trừ khi bạn có lý do chắc chắn để nghĩ khác, hoặc trừ khi cơ sở dữ liệu của bạn ở bên ngoài đáng kể dòng chính cho cơ sở dữ liệu OLTP (ví dụ: cơ sở dữ liệu nhỏ nhận được 10 nghìn cập nhật mỗi giây hoặc kho dữ liệu 3TB).

Trước tiên, hãy bật ghi nhật ký để bạn có thể kiểm tra xem liệu autovacuum có đang làm những gì bạn nghĩ không:

log_autovacuum_min_duration = 0

Sau đó, hãy tạo thêm nhân viên autovac và yêu cầu họ kiểm tra bảng thường xuyên hơn:

autovacuum_max_workers = 6
autovacuum_naptime = 15s

Hãy hạ thấp ngưỡng để tự động hút bụi và tự động phân tích để kích hoạt sớm hơn:

autovacuum_vacuum_threshold = 25
autovacuum_vacuum_scale_factor = 0.1

autovacuum_analyze_threshold = 10
autovacuum_analyze_scale_factor = 0.05 

Sau đó, hãy làm cho autovacuum ít bị gián đoạn hơn, để nó hoàn thành nhanh hơn, nhưng với chi phí có tác động lớn hơn đến hoạt động của người dùng đồng thời:

autovacuum_vacuum_cost_delay = 10ms
autovacuum_vacuum_cost_limit = 1000

Có chương trình đầy đủ của bạn cho tính năng tự động tích cực, có thể phù hợp với cơ sở dữ liệu nhỏ có tỷ lệ cập nhật rất cao, nhưng có thể ảnh hưởng quá lớn đến hoạt động của người dùng đồng thời.

Ngoài ra, lưu ý rằng các tham số autovacuum có thể được điều chỉnh trên mỗi bảng , đây hầu như luôn là câu trả lời tốt hơn cho việc cần điều chỉnh hành vi của autovacuum.

Tuy nhiên, một lần nữa, không thể giải quyết vấn đề thực sự của bạn.


36

Chỉ để xem bảng nào đủ điều kiện cho autovacuum, truy vấn sau đây có thể được sử dụng (dựa trên http://www.postgresql.org/docs/civerse/static/routine-vacuuming.html ). Tuy nhiên, lưu ý rằng truy vấn không tìm kiếm các cài đặt cụ thể của bảng:

 SELECT psut.relname,
     to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') as last_vacuum,
     to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') as last_autovacuum,
     to_char(pg_class.reltuples, '9G999G999G999') AS n_tup,
     to_char(psut.n_dead_tup, '9G999G999G999') AS dead_tup,
     to_char(CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
         + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
            * pg_class.reltuples), '9G999G999G999') AS av_threshold,
     CASE
         WHEN CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
             + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
                * pg_class.reltuples) < psut.n_dead_tup
         THEN '*'
         ELSE ''
     END AS expect_av
 FROM pg_stat_user_tables psut
     JOIN pg_class on psut.relid = pg_class.oid
 ORDER BY 1;

11

Vâng, đó là một vấn đề khóa. Theo trang này (không đầy đủ) VACUUM cần CHIA SẺ CẬP NHẬT truy cập ĐỘC QUYỀN bị chặn bởi cấp độ khóa bạn đang sử dụng.

Bạn có chắc chắn bạn cần khóa này? PostgreQuery tuân thủ ACID nên hầu hết các trường hợp ghi đồng thời không phải là vấn đề vì PostgreQuery sẽ hủy bỏ một trong các giao dịch nếu xảy ra vi phạm tuần tự hóa.

Ngoài ra, bạn có thể khóa các hàng bằng cách sử dụng CHỌN CẬP NHẬT để khóa các hàng thay vì toàn bộ bảng.

Một cách khác mà không khóa sẽ là sử dụng mức cách ly giao dịch . Tuy nhiên, điều này có thể ảnh hưởng đến hiệu suất của các giao dịch khác và bạn nên chuẩn bị cho các lỗi tuần tự hóa nhiều hơn.


Điều này là do khóa các bảng tóm tắt, vì các bảng này bị khóa bằng CHẾ ĐỘ ĐỘC QUYỀN SHARE ROW. Viết đồng thời mà không có khóa có thể thành công, nhưng chúng chắc chắn sẽ kết thúc với các giá trị sai. Hãy tưởng tượng tôi đang duy trì số lượng N của các loại loại X. Nếu tôi đồng thời chèn 2 hàng loại X, không khóa, tôi sẽ kết thúc bằng N + 1 trong bảng tóm tắt của mình thay vì N + 2. Giải pháp tôi đã áp dụng là để có một công việc định kỳ hút bụi thủ công các bảng tóm tắt trong cơ sở dữ liệu của tôi. Nó hoạt động tốt và dường như là cách tiếp cận được đề xuất, nhưng nó cảm thấy quá giống như một hack đối với tôi.
CadentOrange

6

Tăng số lượng quy trình tự động và giảm thời gian ngủ trưa có thể sẽ giúp ích. Đây là cấu hình cho PostgreQuery 9.1 mà tôi sử dụng trên máy chủ lưu trữ thông tin sao lưu và kết quả là có rất nhiều hoạt động chèn.

http://www.postgresql.org/docs/civerse/static/r nb-config-autovacuum.html

autovacuum_max_workers = 6              # max number of autovacuum subprocesses
autovacuum_naptime = 10         # time between autovacuum runs
autovacuum_vacuum_cost_delay = 20ms     # default vacuum cost delay for

Tôi cũng sẽ cố gắng hạ thấp cost_delayđể làm cho việc hút bụi mạnh mẽ hơn.

Tôi cũng có thể kiểm tra tự động bằng cách sử dụng pgbench.

http://wiki.postgresql.org/wiki/Pgbenchtesting

Ví dụ ganh đua cao:

Tạo cơ sở dữ liệu băng ghế dự bị

pgbench -i -p 5433 bench_replication

Chạy pgbench

pgbench -U postgres -p 5432 -c 64 -j 4 -T 600 bench_replication

Kiểm tra trạng thái tự động

psql
>\connect bench_replicaiton
bench_replication=# select schemaname, relname, last_autovacuum from pg_stat_user_tables;
 schemaname |     relname      |        last_autovacuum        
------------+------------------+-------------------------------
 public     | pgbench_branches | 2012-07-18 18:15:34.494932+02
 public     | pgbench_history  | 
 public     | pgbench_tellers  | 2012-07-18 18:14:06.526437+02
 public     | pgbench_accounts | 

6

Tập lệnh "đủ điều kiện cho autovacuum" hiện tại rất hữu ích, nhưng (như đã nêu chính xác) đã thiếu các tùy chọn cụ thể của bảng. Đây là phiên bản sửa đổi của nó đưa các tùy chọn đó vào tài khoản:

WITH rel_set AS
(
    SELECT
        oid,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)::BIGINT
        END AS rel_av_vac_threshold,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)::NUMERIC
        END AS rel_av_vac_scale_factor
    FROM pg_class
) 
SELECT
    PSUT.relname,
    to_char(PSUT.last_vacuum, 'YYYY-MM-DD HH24:MI')     AS last_vacuum,
    to_char(PSUT.last_autovacuum, 'YYYY-MM-DD HH24:MI') AS last_autovacuum,
    to_char(C.reltuples, '9G999G999G999')               AS n_tup,
    to_char(PSUT.n_dead_tup, '9G999G999G999')           AS dead_tup,
    to_char(coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples, '9G999G999G999') AS av_threshold,
    CASE
        WHEN (coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples) < PSUT.n_dead_tup
        THEN '*'
    ELSE ''
    END AS expect_av
FROM
    pg_stat_user_tables PSUT
    JOIN pg_class C
        ON PSUT.relid = C.oid
    JOIN rel_set RS
        ON PSUT.relid = RS.oid
ORDER BY C.reltuples DESC;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.