Connection pooling là một cách đơn giản nhưng hiệu quả để cải thiện hiệu suất của ứng dụng và giảm tải trên các máy chủ PostgreSQL của bạn. Đọc tiếp để tìm hiểu thêm về cách sử dụng PgBouncer để gộp các kết nối PostgreSQL.

Tại sao sử dụng Connection Pooling?

PostgreSQL có kiến ​​trúc xử lý kết nối khá nặng. Đối với mỗi kết nối đến, postmaster (daemon Postgres) đưa ra một process mới (thường được gọi là backend ) để xử lý nó. Mặc dù thiết kế này mang lại sự ổn định và cô lập tốt hơn, nhưng nó không làm cho nó đặc biệt hiệu quả trong việc xử lý các kết nối có tuổi thọ ngắn. Một kết nối client Postgres mới bao gồm thiết lập TCP, tạo process và khởi tạo backend – tất cả đều tốn kém về thời gian và tài nguyên hệ thống.

Tất nhiên đây chỉ là một vấn đề nếu các kết nối được tạo quá thường xuyên và bị loại bỏ mà không sử dụng lại. Thật không may, không có gì lạ khi có một cụm các node web chạy các ứng dụng được viết bằng PHP hoặc các ngôn ngữ khác cần kết nối với cơ sở dữ liệu một lần mỗi lần tải trang. Các công việc hàng loạt nhanh chóng tạo ra một loạt các kết nối liên tiếp nhanh chóng cũng rất phổ biến. Sử dụng connection pool trong các tình huống như vậy có thể giảm đáng kể tải trên máy chủ PostgreSQL của bạn và cải thiện đáng kể độ trễ truy vấn.

Với connection pool, các client kết nối với server proxy duy trì một tập hợp các kết nối trực tiếp đến server PostgreSQL. Thông thường, các máy khách không (và không nên) nhận ra rằng họ được kết nối với một máy chủ proxy hơn là máy chủ thực tế. Proxy có thể chạy trên cùng một node với máy khách (ví dụ: trên mỗi node web), trong trường hợp đó, máy khách có thể kết nối với proxy qua các domain socket Unix – cái mà có chi phí hoạt động kết nối rất thấp. Ngay cả khi proxy nằm trên một node khác và máy khách cần kết nối TCP để truy cập proxy, thì có thể tránh được chi phí hoạt động của backend Postgres mới.

PgBouncer là gì?

PgBouncer là một trình gộp kết nối nhị phân đơn mã nguồn mở, nhẹ, dành cho PostgreSQL. Nó có thể gộp các kết nối đến một hoặc nhiều cơ sở dữ liệu (trên các máy chủ có thể khác nhau) và phục vụ các máy khách qua các domain socket TCP và Unix.

PgBouncer duy trì một nhóm kết nối cho mỗi cặp cơ sở dữ liệu, người dùng duy nhất. Nó thường được cấu hình để cung cấp một trong những kết nối này cho kết nối client mới đến và đưa nó trở lại nhóm khi client ngắt kết nối. Bạn có thể định cấu hình PgBouncer để gộp mạnh hơn, để nó có thể nhận và trả kết nối vào nhóm tại ranh giới giao dịch hoặc câu lệnh thay vì ranh giới kết nối. Tuy nhiên, có một số vấn đề không mong muốn có thể xảy ra.

Bạn sẽ có thể cài đặt PgBouncer bằng trình quản lý gói của bản phân phối:

# RedHat/CentOS/..
$ sudo yum install pgbouncer

# Debian/Ubuntu/..
$ sudo apt-get install pgbouncer

Nó cũng có sẵn từ các repo Postgres APT và YUM tiêu chuẩn , có thể được sử dụng nếu các gói phân phối của bạn đã cũ hoặc bị hỏng.

PgBouncer dựa trên một tệp cấu hình chính, thường được lưu trữ dưới dạng /etc/pgbouncer/pgbouncer.ini. Bạn có thể gọi pgbouncer dưới dạng dịch vụ systemd hoặc đơn giản là chạy nó ngay cả khi không có đặc quyền của người dùng root với đường dẫn đến tệp cấu hình này.

Để mang lại hiệu quả, hãy tạo cơ sở dữ liệu db1 và người dùng user1 trên máy chủ của chúng ta:

$ sudo -u postgres psql
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.

postgres=# create user user1 password 'user1pass';
CREATE ROLE
postgres=# create database db1 owner user1;
CREATE DATABASE
postgres=#

Client sẽ kết nối với cơ sở dữ liệu db1 bằng tên người dùng user1 và mật khẩu user1pass. Mục tiêu của chúng ta là làm cho các client kết nối với PgBouncer sẽ ủy quyền và gộp các kết nối với máy chủ thực tế.

Bây giờ, hãy tạo một tệp (ở bất kỳ đâu) với các nội dung sau:

[databases]
db1 = host=localhost dbname=db1

[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt

Chúng ta cũng cần tạo tệp “userlist.txt” trong cùng một thư mục, với tên người dùng và mật khẩu (đã băm) của người dùng mà PgBouncer sẽ cho phép kết nối. Tạo “userlist.txt” với các nội dung sau:

"user1" "md5638b81c77071ea624d1ad4adb1433540"

Giá trị thứ hai là MD5 của “user1passuser1”, có tiền tố là “md5”. Đây là quy ước Postgres thông thường.

Bây giờ, hãy bắt đầu PgBouncer ở phía trước:

$ /usr/sbin/pgbouncer pgbouncer.ini
2019-02-05 11:46:18.011 10033 LOG file descriptor limit: 1024 (H:1048576), max_client_conn: 100, max fds possible: 130
2019-02-05 11:46:18.012 10033 LOG listening on 127.0.0.1:16432
2019-02-05 11:46:18.013 10033 LOG listening on unix:/tmp/.s.PGSQL.16432
2019-02-05 11:46:18.014 10033 LOG process up: pgbouncer 1.9.0, libevent 2.0.21-stable (epoll), adns: c-ares 1.12.0, tls: OpenSSL 1.1.0j  20 Nov 2018

Bây giờ chúng ta đã khởi động PgBouncer đang lắng nghe trên cổng 127.0.0.1 TCP 16432, cũng như trên domain socket Unix /tmp/.s.PGSQL.16432. “Cơ sở dữ liệu” duy nhất có sẵn trên máy chủ proxy này là db1. Người dùng duy nhất có thể kết nối với máy chủ này là user1. Hãy thử kết nối với psql:

$ psql -U user1 -p 16432 -h localhost db1
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.

db1=> select inet_server_addr(), inet_server_port();
 inet_server_addr | inet_server_port
------------------+------------------
 127.0.0.1        |             5432
(1 row)

db1=>

Client (psql) kết nối thành công với localhost:16432, nhưng bạn có thể thấy rằng kết nối thực sự đang được ủy quyền cho localhost:5432.

Bạn có thể thử ngắt kết nối và kết nối lại một vài lần, sau đó kiểm tra xem còn bao nhiêu kết nối trên máy chủ thực tế:

postgres=# select count(*) from pg_stat_activity
postgres-#   where datname='db1' and usename='user1';
 count
-------
     1
(1 row)

PgBouncer sẽ không ngắt kết nối thực khi máy khách ngắt kết nối. Bạn có thể định cấu hình các kết nối tối thiểu, tối đa và dành riêng mà PgBouncer sẽ duy trì cho mỗi nhóm trong tệp cấu hình.

Triển khai PgBouncer

Bạn cài đặt và chạy PgBouncer ở đâu? Có những câu trả lời khác nhau, với những ưu điểm khác nhau:

  • Trên máy chủ Postgres : Bạn có thể cài đặt nó cùng với chính máy chủ PostgreSQL, trên cùng một node. Các máy khách kết nối với cổng PgBouncer hơn là cổng Postgres. Điều này có tác dụng như một Postgres “nâng cao” thực hiện kết nối tổng hợp nội bộ. Bạn cũng chỉ phải duy trì một bản sao của các tệp cấu hình cho PgBouncer. Mặt khác, điều này thực sự liên quan đến việc chạy một cái gì đó khác cũng trên node máy chủ PostgreSQL, điều này có thể không dễ dàng hoặc không được phép (tường lửa, policy) hoặc thậm chí có thể (AWS RDS).
  • Trên các node Client : Bạn có thể cài đặt PgBouncer trong mỗi server client, ví dụ: mỗi node web chạy Apache và PHP và các tập lệnh PHP kết nối với PgBouncer localhost. Điều này có lợi thế là không phải làm phiền quá trình thiết lập máy chủ và cấu hình pool có thể được sử dụng để giữ cho tải máy chủ có thể dự đoán được. Mặt khác, nếu số lượng server client rất lớn hoặc có thể thay đổi rất nhiều tùy thuộc vào tải / lưu lượng, máy chủ có thể bị quá tải nhanh chóng.
  • Là một cụm độc lập : Tùy chọn thứ ba để có một cụm các node PgBouncer độc lập, không trạng thái, được hỗ trợ bởi bộ cân bằng tải TCP như HAProxy. Thiết lập này, mặc dù phức tạp hơn hai tùy chọn còn lại, nhưng cung cấp khả năng kiểm soát và cấu hình tối đa.

Administration

PgBouncer cho phép người dùng được đánh dấu là quản trị viên với cơ sở dữ liệu ảo gọi là “pgbouncer” và ra lệnh để điều khiển máy chủ và xem số liệu thống kê. Để thử điều này, trước tiên hãy đánh dấu “user1” là quản trị viên bằng cách sửa đổi tệp pgbouncer.ini:

[databases]
db1 = host=localhost dbname=db1

[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt
admin_users = user1

Bây giờ user1 có thể kết nối với cơ sở dữ liệu có tên “pgbouncer”:

$ psql -U user1 -p 16432 -h localhost pgbouncer
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1), server 1.9.0/bouncer)
Type "help" for help.

pgbouncer=#

Từ đây, bạn có thể thực hiện nhiều việc khác nhau như bật hoặc tắt một cơ sở dữ liệu cụ thể, kiểm tra và tải lại cấu hình, v.v.

pgbouncer=# RELOAD;
RELOAD
pgbouncer=# DISABLE db1;
DISABLE
pgbouncer=# ENABLE db1;
ENABLE
pgbouncer=# SHOW FDS;
 fd |  task  | user  | database |   addr    | port  |     cancel     | link | client_encoding | std_strings | datestyle | timezone  | pa
----+--------+-------+----------+-----------+-------+----------------+------+-----------------+-------------+-----------+-----------+---
  6 | pooler |       |          | 127.0.0.1 | 16432 |              0 |    0 |                 |             |           |           |
  7 | pooler |       |          | unix      | 16432 |              0 |    0 |                 |             |           |           |
  9 | server | user1 | db1      | 127.0.0.1 |  5432 | 45404395804679 |    0 | UTF8            | on          | ISO, MDY  | localtime |
(3 rows)

Monitor

Ngoài ra còn có các lệnh để hiển thị các số liệu thống kê khác nhau về PgBouncer, bao gồm:

  • Thống kê trên mỗi cơ sở dữ liệu về thời lượng truy vấn, thời gian chờ của client, mức sử dụng mạng, số lượng giao dịch
  • Thống kê theo nhóm về số lượng client đang hoạt động và đang chờ, kết nối máy chủ nhàn rỗi và đã sử dụng

Thống kê được truy xuất bằng lệnh kiểu “SHOW xyz”, như lệnh này để tìm nạp thống kê liên quan đến pool:

pgbouncer=# SHOW POOLS;
-[ RECORD 1 ]---------
database   | db1
user       | user1
cl_active  | 0
cl_waiting | 0
sv_active  | 0
sv_idle    | 0
sv_used    | 1
sv_tested  | 0
sv_login   | 0
maxwait    | 0
maxwait_us | 0
pool_mode  | session
-[ RECORD 2 ]---------
database   | pgbouncer
user       | pgbouncer
cl_active  | 1
cl_waiting | 0
sv_active  | 0
sv_idle    | 0
sv_used    | 0
sv_tested  | 0
sv_login   | 0
maxwait    | 0
maxwait_us | 0
pool_mode  | statement

Đọc thêm

Trang PgBouncer có thêm chi tiết về tất cả các tính năng khác nhau và các tùy chọn cấu hình của PgBouncer.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments