PostgreSQL đi kèm với rất nhiều tùy chọn cấu hình, nhưng việc thay đổi cài đặt mặc định của một số tùy chọn này sẽ cải thiện đáng kể khả năng quan sát của máy chủ PostgreSQL của bạn. Bạn sẽ muốn thiết lập và định cấu hình các tùy chọn này trước khi phát hành trong quá trình sản xuất, vì chúng có thể cung cấp thông tin cần thiết để hiểu và giải quyết những vấn đề đó.
Đọc tiếp để tìm hiểu thêm về các cài đặt và tiện ích mở rộng hiển thị các chỉ số và thông tin về hoạt động bên trong máy chủ PostgreSQL của bạn.
Tiền tố dòng nhật ký
log_line_prefix tùy chọn cấu hình xác định những gì PostgreSQL ghi ở đầu mỗi dòng nhật ký. Giá trị mặc định tùy thuộc vào giải pháp Linuxdistribution hoặc được quản lý cụ thể mà bạn đang sử dụng, nhưng thường xuyên hơn là không bao gồm một số mục có thể tỏ ra rất hữu ích trong việc theo dõi các ứng dụng khách đang hoạt động kém. Hãy thử log_line_prefix này :
log_line_prefix = '%m [%p] %a %u %d %h '
Nó bao gồm dấu thời gian (% m ), PID của quy trình phụ trợ (% p ), tên ứng dụng (% a ) của khách hàng, tên người dùng mà khách hàng đã kết nối với (% u ), cơ sở dữ liệu mà khách hàng đã kết nối với (% d ) và tên máy chủ hoặc IP nơi kết nối đến từ (% h ). Điều này dẫn đến các dòng log như sau:
2021-01-30 05:06:03.675 UTC [73] psql postgres bench 172.17.0.1 ERROR: relation "pgbench_akkounts" does not exist at character 15
2021-01-30 05:06:03.675 UTC [73] psql postgres bench 172.17.0.1 STATEMENT: select * from pgbench_akkounts;
hữu ích hơn nhiều so với mặc định. Bạn có thể thấy rằng một ứng dụng khách đã kết nối từ 172.17.0.1 với tư cách là người dùng postgres đến cơ sở dữ liệu băng ghế dự bị và ứng dụng là psql . Chắc chắn là một cải tiến so với tùy chọn mặc định, chỉ cho thấy điều này:
2021-01-30 05:13:22.630 UTC [63] ERROR: relation "pgbench_akkounts" does not exist at character 15
2021-01-30 05:13:22.630 UTC [63] STATEMENT: select * from pgbench_akkounts;
Ghi nhật ký Truy vấn Chậm
PostgreSQL có thể được định cấu hình để ghi các truy vấn cần nhiều hơn một khoảng thời gian nhất định để thực thi. Chúng đi vào cùng một tệp nhật ký; không có tệp nhật ký truy vấn phân tách nhỏ như trong MySQL.
Để ghi nhật ký các câu lệnh mất hơn 1 giây để thực thi, hãy sử dụng log_min_duration_statement tùy chọn như thế này:
log_min_duration_statement = 1s
Lưu ý rằng log_min_duration_statement sẽ xem xét tất cả các câu lệnh (bao gồm ví dụ:các câu lệnh quản trị dài hạn như REINDEX TABLE ) và không chỉ truy vấn ( CHỌN ). Dưới đây là một số mục nhật ký được tạo bởi tùy chọn này:
2021-01-30 08:42:57.473 UTC [62] psql postgres postgres 172.17.0.1 LOG: duration: 1016.283 ms statement: select pg_sleep(1);
2021-01-30 08:52:00.541 UTC [62] psql postgres postgres 172.17.0.1 LOG: duration: 1118.277 ms statement: select pg_sleep(1.1);
Nếu điều này dẫn đến quá nhiều nhật ký có các câu lệnh tương tự, bạn chỉ có thể cho Postgres biết một phần trăm nhật ký của nó bằng cách sử dụng:
log_min_duration_statement = -1
log_min_duration_sample = 1s
log_statement_sample_rate = 0.25
Điều này chỉ ghi lại 25% các câu lệnh đủ điều kiện để ghi nhật ký (câu lệnh mất hơn 1 giây để thực thi). Đầu ra nhật ký vẫn giống như trước đây. Không có cách nào để biết có bao nhiêu câu lệnh đủ điều kiện chưa được ghi lại.
Để ghi lại tất cả các câu lệnh, cùng với thời gian thực thi chúng, hãy sử dụng log_statement thay vào đó:
log_statement = mod
log_duration = on
Tùy chọn ‘mod’ yêu cầu Postgres ghi lại các DDL và các câu lệnh sửa đổi dữ liệu. Điều này dẫn đến các bản ghi như sau:
2021-01-30 08:35:08.985 UTC [64] pgbench postgres bench 172.17.0.1 LOG: statement: insert into pgbench_tellers(tid,bid,tbalance) values (10,1,0)
2021-01-30 08:35:08.985 UTC [64] pgbench postgres bench 172.17.0.1 LOG: duration: 0.241 ms
Hãy cảnh báo rằng nó không có thể để ghi nhật ký câu lệnh mẫu được bật theo cách này, tất cả các câu lệnh sẽ được ghi lại và bạn sẽ có rất nhiều mục nhập nhật ký.
Khóa ghi nhật ký và bế tắc
Các truy vấn có thể đợi quá lâu để có được khóa. Thông thường, giới hạn trên về thời gian chờ được đặt bằng tùy chọn lock_timeout , thường là ở phía máy khách. Nếu một truy vấn đã đợi quá lâu để có được khóa, Postgres sẽ hủy thực thi truy vấn này và ghi lại lỗi:
2021-01-30 09:35:52.415 UTC [67] psql postgres testdb 172.17.0.1 ERROR: canceling statement due to lock timeout
2021-01-30 09:35:52.415 UTC [67] psql postgres testdb 172.17.0.1 STATEMENT: cluster t;
Giả sử bạn muốn đặt thời gian chờ khóa là 1 phút, nhưng các truy vấn ghi nhật ký chờ khóa lâu hơn, chẳng hạn như 30 giây. Bạn có thể thực hiện việc này bằng cách sử dụng:
log_lock_waits = on
deadlock_timeout = 30s
Thao tác này sẽ tạo các nhật ký như sau:
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 LOG: process 70 still waiting for ShareLock on transaction 493 after 30009.004 ms
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 DETAIL: Process holding the lock: 68. Wait queue: 70.
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 CONTEXT: while locking tuple (0,3) in relation "t"
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 STATEMENT: select * from t for update;
Việc sử dụng deadlock_timeout không phải là lỗi đánh máy:nó là giá trị mà cơ chế chờ khóa sử dụng. Lý tưởng nhất, nên có một cái gì đó giống như log_min_duration_lock_wait , nhưng thật không may, đó không phải là trường hợp.
Trong trường hợp bế tắc thực sự, Postgres sẽ hủy bỏ các giao dịch bị tắc nghẽn sau deadlock_timeout thời hạn, và sẽ ghi lại các báo cáo vi phạm. Cấu hình rõ ràng là cần thiết.
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 LOG: process 68 detected deadlock while waiting for ShareLock on transaction 496 after 30007.633 ms
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 DETAIL: Process holding the lock: 70. Wait queue: .
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 CONTEXT: while locking tuple (0,3) in relation "t"
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 STATEMENT: select * from t where a=4 for update;
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 ERROR: deadlock detected
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 DETAIL: Process 68 waits for ShareLock on transaction 496; blocked by process 70.
Process 70 waits for ShareLock on transaction 495; blocked by process 68.
Process 68: select * from t where a=4 for update;
Process 70: select * from t where a=0 for update;
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 HINT: See server log for query details.
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 CONTEXT: while locking tuple (0,3) in relation "t"
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 STATEMENT: select * from t where a=4 for update;
Tự động ghi nhật ký
Quá trình autovacuum bắt đầu khi Postgres xác định dữ liệu trong bảng đã thay đổi đủ để đảm bảo chân không và phân tích. Để theo dõi quá trình này, hãy bật ghi nhật ký các lần chạy autovacuum:
log_autovacuum_min_duration = 250ms
Đây là một mục nhập mẫu do thay đổi quá nhiều đối với một bảng:
2021-01-30 10:23:33.201 UTC [63] LOG: automatic vacuum of table "postgres.public.t": index scans: 0
pages: 0 removed, 95 remain, 0 skipped due to pins, 0 skipped frozen
tuples: 8991 removed, 10000 remain, 0 are dead but not yet removable, oldest xmin: 492
buffer usage: 215 hits, 4 misses, 4 dirtied
avg read rate: 1.885 MB/s, avg write rate: 1.885 MB/s
system usage: CPU: user: 0.01 s, system: 0.00 s, elapsed: 0.01 s
WAL usage: 244 records, 1 full page images, 67984 bytes
2021-01-30 10:23:33.222 UTC [63] LOG: automatic analyze of table "postgres.public.t" system usage: CPU: user: 0.01 s, system: 0.00 s, elapsed: 0.01 s
Lưu ý rằng autovacuum thường sẽ kích hoạt phân tích sau khi hút chân không và quá trình này cũng sẽ được ghi lại.
Các nhật ký này sẽ giúp bạn tìm ra cách tốt nhất để điều chỉnh các thông số autovacuum và sẽ giúp điều tra xem và khi nào autovacuum không hoạt động hiệu quả như bạn nghĩ.
Các điểm kiểm tra ghi nhật ký
Checkpointing là quá trình đẩy các thay đổi được ghi trong WAL vào các bảng quay lại của filesthat thực tế. Lý tưởng nhất là các điểm kiểm tra nên diễn ra theo chu kỳ thường xuyên và không quá thường xuyên, vì đây là một quá trình chuyên sâu về CPU và ổ đĩa. Vì nhiều lý do khác nhau, các điểm kiểm tra cũng buộc phải thực hiện trước thời gian lập lịch tiếp theo và điều này dẫn đến giảm hiệu suất truy vấn.
Để theo dõi tần suất và hiệu quả của điểm kiểm tra, hãy bật ghi nhật ký các điểm kiểm tra:
log_checkpoints = on
Điều này yêu cầu PostgreSQL ghi lại những điều sau đây bất cứ khi nào một điểm kiểm tra xảy ra:
2021-01-30 10:05:57.085 UTC [56] LOG: checkpoint starting: immediate force wait
2021-01-30 10:05:57.159 UTC [56] LOG: checkpoint complete: wrote 0 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.000 s, total=0.074 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=0 kB
Dòng đầu tiên chứa các cờ mà chương trình phụ trợ được chuyển đến bộ kiểm tra. Bạn có thể thấy rằng "lực lượng" đã gây ra một trạm kiểm soát mặc dù không có thay đổi nào đang chờ xử lý cho điểm kiểm tra. Nếu "ngay lập tức" không được chỉ định, thì điểm kiểm tra sẽ có điểm kiểm tra lên đến checkpoint_completion_target .
Cài đặt phía máy chủ khác
Có một số cài đặt khác mà bạn có thể bật trong cấu hình PostgreSQL của mình sẽ giúp chẩn đoán sự cố:
- track_io_timing - đặt cài đặt này thành bật cho phép bạn xem thời gian bỏ qua I / O cho mỗi truy vấn (kết hợp với pg_stat_statements mở rộng được mô tả bên dưới). Xem tài liệu về một cảnh báo khi bật tính năng này, nhưng phải an toàn trên hầu hết mọi loại ModernLinux. Không thể xem chi phí I / O đĩa của một truy vấn nếu không bật tính năng này.
- track_commit_timestamp - đặt cài đặt này thành bật có thể hữu ích trong việc gỡ lỗi độ trễ sao chép và các vấn đề khác liên quan đến sao chép.
Thống kê Truy vấn qua pg_stat_statements
Phần mở rộng pg_stat_statements là một phụ kiện cần thiết cho bất kỳ PostgreSQLdeployment nào. Nó thu thập và ghi lại số liệu thống kê cho mỗi truy vấn được thực thi và biểu diễn chúng dưới dạng một dạng xem được gọi là “pg_stat_statements”. Đây là một tiện ích mở rộng, có nghĩa là bạn phải cài đặt nó một cách rõ ràng trong từng cơ sở dữ liệu mà bạn muốn có dữ liệu, bằng cách sử dụng lệnh:
CREATE EXTENSION pg_stat_statements;
Vì tiện ích mở rộng dựa trên một .so , bạn sẽ cần tải nó bằng shared_preload_libraries :
shared_preload_libraries = 'pg_stat_statements'
Thật không may, điều này yêu cầu khởi động lại máy chủ PostgreSQL; vì vậy hãy đảm bảo bạn làm điều này trước khi phát trực tiếp.
Nếu bạn đã nâng cấp từ phiên bản trước của PostgreSQL, hãy nhớ nâng cấp phần mở rộng pg_stat_statement của bạn bằng cách sử dụng:
ALTER EXTENSION pg_stat_statements UPDATE;
Phần mở rộng pg_stat_statements không ghi lại bất kỳ thứ gì, nó được sử dụng thông qua truy vấn chế độ xem cùng tên. Để biết thêm chi tiết, hãy xem tài liệu chính thức.
Kế hoạch thực thi truy vấn qua auto_explain
auto_explain là một phần mở rộng khác có trong PostgreSQL cốt lõi. Nó có thể ghi lại các kế hoạch thực thi của các truy vấn chậm. Nó chỉ cần được thêm vào shared_preload_libraries và không cần cài đặt dưới dạng tiện ích mở rộng. Nó cũng có một số tùy chọn khác thường cần được đặt thành giá trị không mặc định:
shared_preload_libraries = 'pg_stat_statements,auto_explain'
auto_explain.log_min_duration = 1s
auto_explain.log_analyze = on
auto_explain.log_buffers = on
auto_explain.log_triggers = on
auto_explain.log_timing = on
auto_explain.log_verbose = on
auto_explain.log_format = json
Ở trên ghi lại kế hoạch thực thi cho bất kỳ truy vấn nào mất hơn 1 giây để hoàn thành. Đây là kết quả mẫu:
2021-01-30 11:28:25.977 UTC [64] psql postgres postgres 172.17.0.1 LOG: duration: 1.305 ms plan:
{
"Query Text": "SELECT n.nspname as \"Schema\",\n c.relname as \"Name\",\n CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' TH
EN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'table' WHEN 'I' THEN 'index' END as \"Type\",\n pg_catalog.pg_get_userbyid(c.relowner) as \"Owner\"\nFROM pg_catalog.pg_class c
\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\nWHERE c.relkind IN ('r','p','v','m','S','f','')\n AND n.nspname <> 'pg_catalog'\n AND n.nspname <> 'information_schema'\n AND
n.nspname !~ '^pg_toast'\n AND pg_catalog.pg_table_is_visible(c.oid)\nORDER BY 1,2;",
"Plan": {
"Node Type": "Sort",
"Parallel Aware": false,
"Startup Cost": 32.93,
"Total Cost": 33.01,
"Plan Rows": 32,
"Plan Width": 224,
"Actual Startup Time": 1.292,
"Actual Total Time": 1.298,
"Actual Rows": 0,
[... lots of text snipped ...]
Để tìm hiểu thêm về auto_explain, hãy xem tài liệu chính thức.
Phần mở rộng pg_stat_statements và auto_explain là hai tùy chọn duy nhất được hỗ trợ mà PostgreSQL có để quản lý hiệu suất truy vấn và quản lý kế hoạch truy vấn. Bạn phải trả tiền để biết hai tính năng này và lên kế hoạch trước khi sử dụng chúng trong sản xuất.
Tên ứng dụng
Tên ứng dụng là một tham số phía máy khách và thường có thể được đặt trongDSN hoặc chuỗi kết nối kiểu libpq mà ứng dụng của bạn sử dụng cho thông tin kết nối. Nhiều công cụ và tiện ích trong hệ sinh thái PostgreSQL hiểu được tên ứng dụng và nó giúp đặt giá trị này thành một giá trị có ý nghĩa, ví dụ:
application_name = weekly-revenue-report
Điều này sẽ được đặt cho từng ứng dụng khách kết nối với PostgreSQLserver của bạn.