Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Trong bài viết này, tôi sẽ cho bạn biết cách chúng tôi tiếp cận vấn đề về khả năng chịu lỗi của PostgreSQL, tại sao nó lại trở nên quan trọng đối với chúng tôi và cuối cùng điều gì đã xảy ra.

Chúng tôi có một dịch vụ được tải cao: 2,5 triệu người dùng trên toàn thế giới, hơn 50 nghìn người dùng hoạt động mỗi ngày. Các máy chủ được đặt tại Amazone ở một vùng của Ireland: hơn 100 máy chủ khác nhau hoạt động liên tục, trong đó gần 50 máy chủ có cơ sở dữ liệu.

Toàn bộ chương trình phụ trợ là một ứng dụng Java có trạng thái nguyên khối lớn giúp duy trì kết nối websocket liên tục với máy khách. Khi một số người dùng làm việc trên cùng một bảng cùng một lúc, tất cả họ đều thấy các thay đổi trong thời gian thực, bởi vì chúng tôi ghi từng thay đổi vào cơ sở dữ liệu. Chúng tôi có khoảng 10 nghìn yêu cầu mỗi giây đối với cơ sở dữ liệu của mình. Ở mức tải cao nhất trong Redis, chúng tôi viết 80-100 nghìn yêu cầu mỗi giây.
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Tại sao chúng tôi chuyển từ Redis sang PostgreSQL

Ban đầu, dịch vụ của chúng tôi hoạt động với Redis, một kho lưu trữ khóa-giá trị lưu trữ tất cả dữ liệu trong RAM của máy chủ.

Ưu điểm của Redis:

  1. Tốc độ phản hồi cao, bởi vì mọi thứ được lưu trữ trong bộ nhớ;
  2. Dễ dàng sao lưu và nhân rộng.

Nhược điểm của Redis đối với chúng tôi:

  1. Không có giao dịch thực sự. Chúng tôi đã cố gắng mô phỏng chúng ở cấp độ ứng dụng của chúng tôi. Thật không may, điều này không phải lúc nào cũng hoạt động tốt và yêu cầu viết mã rất phức tạp.
  2. Lượng dữ liệu bị giới hạn bởi dung lượng bộ nhớ. Khi lượng dữ liệu tăng lên, bộ nhớ sẽ tăng lên và cuối cùng, chúng tôi sẽ xem xét các đặc điểm của phiên bản đã chọn, trong AWS yêu cầu dừng dịch vụ của chúng tôi để thay đổi loại phiên bản.
  3. Cần phải liên tục duy trì mức độ trễ thấp, bởi vì. chúng tôi có một số lượng rất lớn các yêu cầu. Mức độ trễ tối ưu đối với chúng tôi là 17-20 ms. Ở mức 30-40 mili giây, chúng tôi nhận được phản hồi dài đối với các yêu cầu từ ứng dụng của chúng tôi và sự xuống cấp của dịch vụ. Thật không may, điều này đã xảy ra với chúng tôi vào tháng 2018 năm 2, khi một trong những trường hợp với Redis vì lý do nào đó nhận được độ trễ gấp XNUMX lần so với bình thường. Để giải quyết vấn đề này, chúng tôi đã dừng dịch vụ vào giữa ngày để bảo trì đột xuất và thay thế phiên bản Redis có vấn đề.
  4. Rất dễ xảy ra tình trạng dữ liệu không nhất quán ngay cả với những lỗi nhỏ trong mã và sau đó dành nhiều thời gian viết mã để sửa dữ liệu này.

Chúng tôi đã tính đến những nhược điểm và nhận ra rằng chúng tôi cần chuyển sang thứ gì đó thuận tiện hơn, với các giao dịch bình thường và ít phụ thuộc vào độ trễ hơn. Tiến hành nghiên cứu, phân tích nhiều tùy chọn và chọn PostgreSQL.

Chúng tôi đã chuyển sang cơ sở dữ liệu mới được 1,5 năm và chỉ chuyển một phần nhỏ dữ liệu, vì vậy hiện tại chúng tôi đang làm việc đồng thời với Redis và PostgreSQL. Thông tin thêm về các giai đoạn di chuyển và chuyển đổi dữ liệu giữa các cơ sở dữ liệu được viết trong bài viết của đồng nghiệp của tôi.

Khi chúng tôi mới bắt đầu di chuyển, ứng dụng của chúng tôi làm việc trực tiếp với cơ sở dữ liệu và truy cập Redis và PostgreSQL chính. Cụm PostgreSQL bao gồm một bản chính và một bản sao với bản sao không đồng bộ. Đây là cách sơ đồ cơ sở dữ liệu trông như thế nào:
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Triển khai PgBouncer

Trong khi chúng tôi di chuyển, sản phẩm cũng đang phát triển: số lượng người dùng và số lượng máy chủ hoạt động với PostgreSQL tăng lên và chúng tôi bắt đầu thiếu kết nối. PostgreSQL tạo một quy trình riêng cho từng kết nối và tiêu tốn tài nguyên. Bạn có thể tăng số lượng kết nối đến một điểm nhất định, nếu không, sẽ có khả năng nhận được hiệu suất cơ sở dữ liệu dưới mức tối ưu. Tùy chọn lý tưởng trong tình huống như vậy là chọn một trình quản lý kết nối sẽ đứng trước cơ sở.

Chúng tôi có hai tùy chọn cho trình quản lý kết nối: Pgpool và PgBouncer. Nhưng cái đầu tiên không hỗ trợ chế độ giao dịch làm việc với cơ sở dữ liệu, vì vậy chúng tôi đã chọn PgBouncer.

Chúng tôi đã thiết lập sơ đồ công việc sau: ứng dụng của chúng tôi truy cập một PgBouncer, đằng sau đó là các bản chính PostgreSQL và đằng sau mỗi bản chính là một bản sao với bản sao không đồng bộ.
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Đồng thời, chúng tôi không thể lưu trữ toàn bộ lượng dữ liệu trong PostgreSQL và tốc độ làm việc với cơ sở dữ liệu rất quan trọng đối với chúng tôi, vì vậy chúng tôi đã bắt đầu phân tách PostgreSQL ở cấp ứng dụng. Lược đồ được mô tả ở trên tương đối thuận tiện cho việc này: khi thêm phân đoạn PostgreSQL mới, chỉ cần cập nhật cấu hình PgBouncer là đủ và ứng dụng có thể hoạt động ngay lập tức với phân đoạn mới.

Chuyển đổi dự phòng PgBouncer

Kế hoạch này hoạt động cho đến thời điểm phiên bản PgBouncer duy nhất chết. Chúng tôi đang ở AWS, nơi tất cả các phiên bản đang chạy trên phần cứng chết định kỳ. Trong những trường hợp như vậy, phiên bản chỉ cần chuyển sang phần cứng mới và hoạt động trở lại. Điều này đã xảy ra với PgBouncer, nhưng nó không khả dụng. Kết quả của sự sụp đổ này là dịch vụ của chúng tôi không có sẵn trong 25 phút. AWS khuyến nghị sử dụng dự phòng phía người dùng cho những tình huống như vậy, điều này chưa được triển khai ở quốc gia của chúng tôi vào thời điểm đó.

Sau đó, chúng tôi đã suy nghĩ nghiêm túc về khả năng chịu lỗi của các cụm PgBouncer và PostgreSQL vì tình huống tương tự có thể xảy ra với bất kỳ phiên bản nào trong tài khoản AWS của chúng tôi.

Chúng tôi đã xây dựng sơ đồ chịu lỗi PgBouncer như sau: tất cả các máy chủ ứng dụng đều truy cập Network Load Balancer, phía sau có hai PgBouncer. Mỗi PgBouncer xem xét cùng một chủ PostgreSQL của mỗi phân đoạn. Nếu phiên bản AWS lại xảy ra sự cố, tất cả lưu lượng truy cập sẽ được chuyển hướng qua một PgBouncer khác. Chuyển đổi dự phòng Network Load Balancer do AWS cung cấp.

Sơ đồ này giúp dễ dàng thêm các máy chủ PgBouncer mới.
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Tạo cụm chuyển đổi dự phòng PostgreSQL

Khi giải quyết vấn đề này, chúng tôi đã xem xét các tùy chọn khác nhau: chuyển đổi dự phòng tự viết, repmgr, AWS RDS, Patroni.

Kịch bản tự viết

Họ có thể giám sát công việc của bản chính và nếu không thành công, hãy thăng cấp bản sao lên bản chính và cập nhật cấu hình PgBouncer.

Ưu điểm của phương pháp này là sự đơn giản tối đa, bởi vì bạn tự viết các tập lệnh và hiểu chính xác cách chúng hoạt động.

Nhược điểm:

  • Chủ có thể không chết, thay vào đó có thể xảy ra lỗi mạng. Failover, không biết về điều này, sẽ thăng cấp bản sao lên bản chính, trong khi bản chính cũ sẽ tiếp tục hoạt động. Do đó, chúng tôi sẽ có hai máy chủ đóng vai trò là máy chủ và chúng tôi sẽ không biết máy chủ nào có dữ liệu cập nhật mới nhất. Tình trạng này còn được gọi là chia não;
  • Chúng tôi bị bỏ lại mà không có phản hồi. Trong cấu hình của chúng tôi, bản chính và một bản sao, sau khi chuyển đổi, bản sao sẽ chuyển lên bản chính và chúng tôi không còn bản sao nữa, vì vậy chúng tôi phải thêm bản sao mới theo cách thủ công;
  • Chúng tôi cần giám sát bổ sung hoạt động chuyển đổi dự phòng, trong khi chúng tôi có 12 phân đoạn PostgreSQL, nghĩa là chúng tôi phải giám sát 12 cụm. Với sự gia tăng số lượng phân đoạn, bạn cũng phải nhớ cập nhật chuyển đổi dự phòng.

Chuyển đổi dự phòng tự viết trông rất phức tạp và yêu cầu hỗ trợ không tầm thường. Với một cụm PostgreSQL duy nhất, đây sẽ là tùy chọn dễ dàng nhất, nhưng nó không mở rộng quy mô nên không phù hợp với chúng tôi.

đại diện

Trình quản lý nhân bản cho cụm PostgreSQL, có thể quản lý hoạt động của cụm PostgreSQL. Đồng thời, nó không có tính năng chuyển đổi dự phòng tự động ngay lập tức, vì vậy, đối với công việc, bạn sẽ cần viết “trình bao bọc” của riêng mình lên trên giải pháp đã hoàn thành. Vì vậy, mọi thứ có thể trở nên phức tạp hơn so với các tập lệnh tự viết, vì vậy chúng tôi thậm chí đã không thử Repmgr.

AWS RDS

Hỗ trợ mọi thứ chúng tôi cần, biết cách tạo bản sao lưu và duy trì một nhóm kết nối. Nó có tính năng chuyển đổi tự động: khi bản chính chết, bản sao sẽ trở thành bản chính mới và AWS thay đổi bản ghi dns thành bản chính mới, trong khi các bản sao có thể được đặt ở các Vùng sẵn sàng khác nhau.

Những bất lợi bao gồm việc thiếu điều chỉnh tốt. Như một ví dụ về tinh chỉnh: các phiên bản của chúng tôi có các hạn chế đối với kết nối tcp, điều không may là không thể thực hiện được trong RDS:

net.ipv4.tcp_keepalive_time=10
net.ipv4.tcp_keepalive_intvl=1
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_retries2=3

Ngoài ra, AWS RDS đắt gần gấp đôi so với giá phiên bản thông thường, đây là lý do chính khiến bạn từ bỏ giải pháp này.

thần hộ mệnh

Đây là một mẫu python để quản lý PostgreSQL với tài liệu tốt, chuyển đổi dự phòng tự động và mã nguồn trên github.

Ưu điểm của Patroni:

  • Mỗi tham số cấu hình được mô tả, rõ ràng về cách thức hoạt động của nó;
  • Tự động chuyển đổi dự phòng hoạt động tốt;
  • Được viết bằng python và vì bản thân chúng tôi viết rất nhiều bằng python nên chúng tôi sẽ dễ dàng giải quyết các vấn đề hơn và thậm chí có thể giúp ích cho sự phát triển của dự án;
  • Quản lý hoàn toàn PostgreSQL, cho phép bạn thay đổi cấu hình trên tất cả các nút của cụm cùng một lúc và nếu cụm cần được khởi động lại để áp dụng cấu hình mới, thì điều này có thể được thực hiện lại bằng Patroni.

Nhược điểm:

  • Tài liệu không rõ ràng về cách làm việc với PgBouncer một cách chính xác. Mặc dù khó có thể gọi đó là một điểm trừ, bởi vì nhiệm vụ của Patroni là quản lý PostgreSQL và các kết nối với Patroni sẽ diễn ra như thế nào đã là vấn đề của chúng tôi;
  • Có rất ít ví dụ về việc triển khai Patroni trên khối lượng lớn, trong khi có rất nhiều ví dụ về việc triển khai từ đầu.

Do đó, chúng tôi đã chọn Patroni để tạo cụm chuyển đổi dự phòng.

Quá trình thực hiện Patroni

Trước Patroni, chúng tôi có 12 phân đoạn PostgreSQL trong cấu hình gồm một bản chính và một bản sao với bản sao không đồng bộ. Các máy chủ ứng dụng đã truy cập cơ sở dữ liệu thông qua Network Load Balancer, phía sau là hai phiên bản với PgBouncer và phía sau chúng là tất cả các máy chủ PostgreSQL.
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Để triển khai Patroni, chúng tôi cần chọn cấu hình cụm lưu trữ phân tán. Patroni hoạt động với các hệ thống lưu trữ cấu hình phân tán như etcd, Zookeeper, Consul. Chúng tôi chỉ có một cụm Consul chính thức trên thị trường, hoạt động cùng với Vault và chúng tôi không sử dụng nó nữa. Một lý do tuyệt vời để bắt đầu sử dụng Consul cho mục đích đã định.

Cách Patroni làm việc với Lãnh sự

Chúng tôi có một cụm Lãnh sự, bao gồm ba nút và cụm Patroni, bao gồm một thủ lĩnh và một bản sao (trong Patroni, chủ được gọi là thủ lĩnh cụm và các nô lệ được gọi là bản sao). Mỗi phiên bản của cụm Patroni liên tục gửi thông tin về trạng thái của cụm tới Lãnh sự. Do đó, từ Lãnh sự, bạn luôn có thể tìm hiểu cấu hình hiện tại của cụm Patroni và ai là người lãnh đạo tại thời điểm này.

Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Để kết nối Patroni với Lãnh sự, chỉ cần nghiên cứu tài liệu chính thức, trong đó nói rằng bạn cần chỉ định máy chủ lưu trữ ở định dạng http hoặc https, tùy thuộc vào cách chúng tôi làm việc với Lãnh sự và sơ đồ kết nối, tùy chọn:

host: the host:port for the Consul endpoint, in format: http(s)://host:port
scheme: (optional) http or https, defaults to http

Nó có vẻ đơn giản, nhưng ở đây những cạm bẫy bắt đầu. Với Consul, chúng tôi làm việc trên một kết nối an toàn qua https và cấu hình kết nối của chúng tôi sẽ như thế này:

consul:
  host: https://server.production.consul:8080 
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

Nhưng điều đó không hiệu quả. Khi khởi động, Patroni không thể kết nối với Consul vì nó vẫn cố gắng đi qua http.

Mã nguồn của Patroni đã giúp giải quyết vấn đề. Điều tốt là nó được viết bằng python. Nó chỉ ra rằng tham số máy chủ không được phân tích cú pháp theo bất kỳ cách nào và giao thức phải được chỉ định trong sơ đồ. Đây là cách khối cấu hình hoạt động để làm việc với Lãnh sự đối với chúng tôi:

consul:
  host: server.production.consul:8080
  scheme: https
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

mẫu lãnh sự

Vì vậy, chúng tôi đã chọn bộ lưu trữ cho cấu hình. Bây giờ chúng ta cần hiểu cách PgBouncer sẽ chuyển đổi cấu hình của nó khi thay đổi người dẫn đầu trong cụm Patroni. Không có câu trả lời cho câu hỏi này trong tài liệu, bởi vì. ở đó, về nguyên tắc, công việc với PgBouncer không được mô tả.

Trong quá trình tìm kiếm giải pháp, chúng tôi đã tìm thấy một bài báo (rất tiếc là tôi không nhớ tiêu đề) trong đó viết rằng Сonsul-template đã giúp ích rất nhiều trong việc ghép nối PgBouncer và Patroni. Điều này đã thôi thúc chúng tôi điều tra cách hoạt động của Consul-template.

Hóa ra là Consul-template liên tục theo dõi cấu hình của cụm PostgreSQL trong Consul. Khi đường dẫn đầu thay đổi, nó sẽ cập nhật cấu hình PgBouncer và gửi lệnh để tải lại cấu hình đó.

Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Một điểm cộng lớn của mẫu là nó được lưu trữ dưới dạng mã, vì vậy khi thêm một phân đoạn mới, chỉ cần thực hiện một cam kết mới và tự động cập nhật mẫu, hỗ trợ Cơ sở hạ tầng làm nguyên tắc mã.

Kiến trúc mới với Patroni

Kết quả là, chúng tôi có sơ đồ làm việc sau:
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Tất cả các máy chủ ứng dụng đều truy cập bộ cân bằng → có hai phiên bản PgBouncer đằng sau nó → trên mỗi phiên bản, Consul-template được khởi chạy, theo dõi trạng thái của từng cụm Patroni và theo dõi mức độ liên quan của cấu hình PgBouncer, cấu hình này sẽ gửi yêu cầu đến người dẫn đầu hiện tại của từng cụm.

Kiểm tra bằng tay

Chúng tôi đã chạy sơ đồ này trước khi khởi chạy nó trên một môi trường thử nghiệm nhỏ và kiểm tra hoạt động của chuyển mạch tự động. Họ mở bảng, di chuyển nhãn dán và ngay lúc đó họ đã “giết chết” người đứng đầu cụm. Trong AWS, điều này đơn giản như tắt phiên bản thông qua bảng điều khiển.

Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Nhãn dán quay trở lại trong vòng 10-20 giây, sau đó bắt đầu di chuyển bình thường trở lại. Điều này có nghĩa là cụm Patroni đã hoạt động chính xác: nó đã thay đổi người lãnh đạo, gửi thông tin đến Сonsul và Сonsul-template ngay lập tức thu thập thông tin này, thay thế cấu hình PgBouncer và gửi lệnh tải lại.

Làm thế nào để tồn tại dưới tải trọng cao và giữ thời gian chết ở mức tối thiểu?

Mọi thứ hoạt động hoàn hảo! Nhưng có những câu hỏi mới: Nó sẽ hoạt động như thế nào dưới tải trọng cao? Làm thế nào để triển khai mọi thứ trong sản xuất một cách nhanh chóng và an toàn?

Môi trường thử nghiệm mà chúng tôi tiến hành kiểm tra tải giúp chúng tôi trả lời câu hỏi đầu tiên. Nó hoàn toàn giống với sản xuất về mặt kiến ​​trúc và đã tạo ra dữ liệu thử nghiệm có khối lượng xấp xỉ bằng với sản xuất. Chúng tôi quyết định chỉ "giết" một trong những bậc thầy PostgreSQL trong quá trình thử nghiệm và xem điều gì sẽ xảy ra. Nhưng trước đó, điều quan trọng là phải kiểm tra cuộn tự động, bởi vì trên môi trường này, chúng tôi có một số phân đoạn PostgreSQL, vì vậy chúng tôi sẽ kiểm tra các tập lệnh cấu hình tuyệt vời trước khi sản xuất.

Cả hai nhiệm vụ đều có vẻ đầy tham vọng, nhưng chúng tôi có PostgreSQL 9.6. Chúng tôi có thể nâng cấp ngay lên 11.2 không?

Chúng tôi quyết định thực hiện theo 2 bước: đầu tiên nâng cấp lên 11.2, sau đó khởi chạy Patroni.

Cập nhật PostgreSQL

Để cập nhật nhanh phiên bản PostgreSQL, hãy sử dụng tùy chọn -k, trong đó các liên kết cứng được tạo trên đĩa và không cần sao chép dữ liệu của bạn. Trên cơ sở 300-400 GB, quá trình cập nhật mất 1 giây.

Chúng tôi có rất nhiều phân đoạn, vì vậy việc cập nhật cần được thực hiện tự động. Để làm được điều này, chúng tôi đã viết một Playbook Ansible xử lý toàn bộ quá trình cập nhật cho chúng tôi:

/usr/lib/postgresql/11/bin/pg_upgrade 
<b>--link </b>
--old-datadir='' --new-datadir='' 
 --old-bindir=''  --new-bindir='' 
 --old-options=' -c config_file=' 
 --new-options=' -c config_file='

Điều quan trọng cần lưu ý ở đây là trước khi bắt đầu nâng cấp, bạn phải thực hiện nó với thông số --kiểm trađể đảm bảo bạn có thể nâng cấp. Tập lệnh của chúng tôi cũng thay thế các cấu hình trong suốt thời gian nâng cấp. Kịch bản của chúng tôi hoàn thành trong 30 giây, đó là một kết quả tuyệt vời.

Ra mắt Patroni

Để giải quyết vấn đề thứ hai, chỉ cần nhìn vào cấu hình Patroni. Kho lưu trữ chính thức có cấu hình ví dụ với initdb, chịu trách nhiệm khởi tạo cơ sở dữ liệu mới khi bạn khởi động Patroni lần đầu tiên. Nhưng vì chúng tôi đã có cơ sở dữ liệu làm sẵn, nên chúng tôi chỉ cần xóa phần này khỏi cấu hình.

Khi chúng tôi bắt đầu cài đặt Patroni trên một cụm PostgreSQL đã có sẵn và chạy nó, chúng tôi gặp phải một vấn đề mới: cả hai máy chủ đều bắt đầu với tư cách là người dẫn đầu. Patroni không biết gì về trạng thái ban đầu của cụm và cố gắng khởi động cả hai máy chủ dưới dạng hai cụm riêng biệt có cùng tên. Để giải quyết vấn đề này, bạn cần xóa thư mục chứa dữ liệu trên Slave:

rm -rf /var/lib/postgresql/

Điều này chỉ cần được thực hiện trên nô lệ!

Khi một bản sao sạch được kết nối, Patroni tạo một nhà lãnh đạo dự phòng cơ sở và khôi phục nó về bản sao, sau đó bắt kịp trạng thái hiện tại theo nhật ký tường.

Một khó khăn khác mà chúng tôi gặp phải là tất cả các cụm PostgreSQL được đặt tên chính theo mặc định. Khi mỗi cụm không biết gì về cụm khác, điều này là bình thường. Nhưng khi bạn muốn sử dụng Patroni, thì tất cả các cụm phải có một tên duy nhất. Giải pháp là thay đổi tên cụm trong cấu hình PostgreSQL.

thử tải

Chúng tôi đã đưa ra một thử nghiệm mô phỏng trải nghiệm người dùng trên bảng. Khi tải đạt đến giá trị trung bình hàng ngày của chúng tôi, chúng tôi đã lặp lại chính xác cùng một thử nghiệm, chúng tôi đã tắt một phiên bản với trình dẫn đầu PostgreSQL. Quá trình chuyển đổi dự phòng tự động hoạt động như chúng tôi mong đợi: Patroni đã thay đổi người lãnh đạo, Consul-template cập nhật cấu hình PgBouncer và gửi lệnh tải lại. Theo biểu đồ của chúng tôi ở Grafana, rõ ràng là có độ trễ từ 20-30 giây và một số lỗi nhỏ từ máy chủ liên quan đến kết nối với cơ sở dữ liệu. Đây là một tình huống bình thường, các giá trị như vậy có thể chấp nhận được đối với quá trình chuyển đổi dự phòng của chúng tôi và chắc chắn tốt hơn thời gian ngừng hoạt động của dịch vụ.

Đưa Patroni vào sản xuất

Kết quả là, chúng tôi đã đưa ra kế hoạch sau:

  • Triển khai Consul-template cho các máy chủ PgBouncer và khởi chạy;
  • PostgreSQL cập nhật lên phiên bản 11.2;
  • Thay đổi tên của cụm;
  • Bắt đầu cụm Patroni.

Đồng thời, sơ đồ của chúng tôi cho phép chúng tôi thực hiện điểm đầu tiên gần như bất cứ lúc nào, chúng tôi có thể lần lượt loại bỏ từng PgBouncer khỏi công việc và triển khai cũng như chạy mẫu lãnh sự trên đó. Vì vậy, chúng tôi đã làm.

Để triển khai nhanh chóng, chúng tôi đã sử dụng Ansible, vì chúng tôi đã thử nghiệm tất cả các playbook trên môi trường thử nghiệm và thời gian thực hiện toàn bộ tập lệnh là từ 1,5 đến 2 phút cho mỗi phân đoạn. Chúng tôi có thể lần lượt triển khai mọi thứ cho từng phân đoạn mà không cần dừng dịch vụ của mình, nhưng chúng tôi sẽ phải tắt từng PostgreSQL trong vài phút. Trong trường hợp này, người dùng có dữ liệu trên phân đoạn này không thể hoạt động đầy đủ vào lúc này và điều này là không thể chấp nhận được đối với chúng tôi.

Cách thoát khỏi tình trạng này là bảo trì theo kế hoạch, diễn ra 3 tháng một lần. Đây là cửa sổ dành cho công việc theo lịch trình, khi chúng tôi tắt hoàn toàn dịch vụ của mình và nâng cấp các phiên bản cơ sở dữ liệu của mình. Còn một tuần nữa là đến cửa sổ tiếp theo và chúng tôi quyết định chỉ chờ đợi và chuẩn bị thêm. Trong thời gian chờ đợi, chúng tôi cũng tự bảo vệ mình: đối với mỗi phân đoạn PostgreSQL, chúng tôi đã tạo một bản sao dự phòng trong trường hợp không giữ được dữ liệu mới nhất và thêm một phiên bản mới cho mỗi phân đoạn, phân đoạn này sẽ trở thành một bản sao mới trong cụm Patroni, để không thực hiện lệnh xóa dữ liệu. Tất cả điều này đã giúp giảm thiểu rủi ro sai sót.
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Chúng tôi đã khởi động lại dịch vụ của mình, mọi thứ hoạt động như bình thường, người dùng vẫn tiếp tục làm việc, nhưng trên biểu đồ, chúng tôi nhận thấy tải cao bất thường trên các máy chủ của Lãnh sự.
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Tại sao chúng ta không thấy điều này trong môi trường thử nghiệm? Vấn đề này minh họa rất rõ ràng rằng cần tuân theo nguyên tắc Cơ sở hạ tầng dưới dạng mã và tinh chỉnh toàn bộ cơ sở hạ tầng, từ môi trường thử nghiệm đến sản xuất. Nếu không, rất dễ gặp sự cố mà chúng tôi gặp phải. Chuyện gì đã xảy ra thế? Consul lần đầu tiên xuất hiện trên môi trường sản xuất, sau đó là trên môi trường thử nghiệm, kết quả là trên môi trường thử nghiệm, phiên bản của Consul cao hơn so với trên sản xuất. Chỉ trong một trong các bản phát hành, rò rỉ CPU đã được giải quyết khi làm việc với mẫu lãnh sự. Do đó, chúng tôi chỉ cần cập nhật Lãnh sự, do đó giải quyết vấn đề.

Khởi động lại cụm Patroni

Tuy nhiên, chúng tôi gặp một vấn đề mới mà chúng tôi thậm chí không nghi ngờ. Khi cập nhật Consul, chúng ta chỉ cần xóa nút Consul khỏi cụm bằng lệnh rời khỏi consul → Patroni kết nối với máy chủ Consul khác → mọi thứ hoạt động. Nhưng khi chúng tôi đến phiên bản cuối cùng của cụm Lãnh sự và gửi lệnh rời khỏi lãnh sự cho nó, tất cả các cụm Patroni chỉ được khởi động lại và trong nhật ký, chúng tôi thấy lỗi sau:

ERROR: get_cluster
Traceback (most recent call last):
...
RetryFailedError: 'Exceeded retry deadline'
ERROR: Error communicating with DCS
<b>LOG: database system is shut down</b>

Cụm Patroni không thể truy xuất thông tin về cụm của nó và khởi động lại.

Để tìm ra giải pháp, chúng tôi đã liên hệ với các tác giả của Patroni thông qua một vấn đề trên github. Họ đã đề xuất các cải tiến cho các tệp cấu hình của chúng tôi:

consul:
 consul.checks: []
bootstrap:
 dcs:
   retry_timeout: 8

Chúng tôi đã có thể tái tạo sự cố trên môi trường thử nghiệm và thử nghiệm các tùy chọn này ở đó, nhưng tiếc là chúng không hoạt động.

Vấn đề vẫn chưa được giải quyết. Chúng tôi dự định thử các giải pháp sau:

  • Sử dụng Consul-agent trên mỗi phiên bản cụm Patroni;
  • Khắc phục sự cố trong mã.

Chúng tôi hiểu nơi xảy ra lỗi: vấn đề có thể là do sử dụng thời gian chờ mặc định, thời gian này không bị ghi đè thông qua tệp cấu hình. Khi máy chủ Lãnh sự cuối cùng bị xóa khỏi cụm, toàn bộ cụm Lãnh sự bị treo hơn một giây, vì điều này, Patroni không thể lấy trạng thái của cụm và khởi động lại toàn bộ cụm.

May mắn thay, chúng tôi đã không gặp phải bất kỳ lỗi nào nữa.

Kết quả sử dụng Patroni

Sau khi ra mắt thành công Patroni, chúng tôi đã thêm một bản sao bổ sung trong mỗi cụm. Giờ đây, trong mỗi cụm có một số đại biểu cần thiết giống nhau: một người lãnh đạo và hai bản sao, để đảm bảo mạng lưới an toàn trong trường hợp bị chia rẽ khi chuyển đổi.
Cụm chuyển đổi dự phòng PostgreSQL + Patroni. kinh nghiệm triển khai

Patroni đã làm việc sản xuất trong hơn ba tháng. Trong thời gian này, anh ấy đã xoay sở để giúp chúng tôi. Gần đây, người lãnh đạo của một trong các cụm đã chết trong AWS, chuyển đổi dự phòng tự động hoạt động và người dùng tiếp tục làm việc. Patroni đã hoàn thành nhiệm vụ chính của nó.

Một bản tóm tắt nhỏ về việc sử dụng Patroni:

  • Dễ dàng thay đổi cấu hình. Chỉ cần thay đổi cấu hình trên một phiên bản là đủ và nó sẽ được kéo lên toàn bộ cụm. Nếu cần phải khởi động lại để áp dụng cấu hình mới, thì Patroni sẽ cho bạn biết. Patroni có thể khởi động lại toàn bộ cụm bằng một lệnh duy nhất, điều này cũng rất thuận tiện.
  • Chuyển đổi dự phòng tự động hoạt động và đã quản lý để giúp chúng tôi.
  • Cập nhật PostgreSQL mà không có thời gian ngừng hoạt động của ứng dụng. Trước tiên, bạn phải cập nhật các bản sao lên phiên bản mới, sau đó thay đổi đường dẫn trong cụm Patroni và cập nhật đường dẫn cũ. Trong trường hợp này, việc kiểm tra cần thiết của chuyển đổi dự phòng tự động xảy ra.

Nguồn: www.habr.com

Thêm một lời nhận xét