PostgreSQL ERROR: hủy bỏ tuyên bố do xung đột với phục hồi


139

Tôi đang gặp lỗi sau khi chạy truy vấn trên db PostgreSQL ở chế độ chờ. Truy vấn gây ra lỗi hoạt động tốt trong 1 tháng nhưng khi bạn truy vấn hơn 1 tháng thì có kết quả lỗi.

ERROR: canceling statement due to conflict with recovery
Detail: User query might have needed to see row versions that must be removed

Bất kỳ đề xuất về cách giải quyết? Cảm ơn


Vui lòng tìm tài liệu AWS có đề cập đến lỗi này, nó cũng có giải pháp aws.amazon.com/bloss/database/iêu
arunjos007

Câu trả lời:


89

Chạy các truy vấn trên máy chủ dự phòng nóng có phần khó khăn - có thể thất bại, vì trong quá trình truy vấn, một số hàng cần thiết có thể được cập nhật hoặc xóa trên chính. Vì một chính không biết rằng một truy vấn được bắt đầu trên thứ cấp, nó nghĩ rằng nó có thể dọn sạch (chân không) các phiên bản cũ của các hàng. Sau đó, thứ cấp phải phát lại việc dọn dẹp này và buộc phải hủy bỏ tất cả các truy vấn có thể sử dụng các hàng này.

Các truy vấn dài hơn sẽ bị hủy thường xuyên hơn.

Bạn có thể giải quyết vấn đề này bằng cách bắt đầu một giao dịch đọc lặp lại trên chính, một truy vấn giả và sau đó nằm im trong khi một truy vấn thực sự được chạy trên thứ cấp. Sự hiện diện của nó sẽ ngăn chặn việc hút bụi các phiên bản hàng cũ trên chính.

Thông tin thêm về chủ đề này và các cách giải quyết khác được giải thích trong phần Chờ nóng - Xử lý xung đột truy vấn trong tài liệu.


10
Đối với người dùng PostgreSQL 9.1+: xem câu trả lời của eradman bên dưới để biết giải pháp thực tế.
Zoltán

3
Đối với người dùng PostgreSQL 9.1+: câu trả lời của max-malysh là lành mạnh hơn nhiều. Đừng làm đề nghị eradman trừ khi bạn hiểu những rủi ro.
Davos

91

Không cần chạm vào hot_standby_feedback. Như những người khác đã đề cập, thiết lập nó để oncó thể làm chủ. Hãy tưởng tượng mở giao dịch trên một nô lệ và không đóng nó.

Thay vào đó, hãy đặt max_standby_archive_delaymax_standby_streaming_delaymột số giá trị lành mạnh:

# /etc/postgresql/10/main/postgresql.conf on a slave
max_standby_archive_delay = 900s
max_standby_streaming_delay = 900s

Bằng cách này, các truy vấn trên nô lệ có thời lượng dưới 900 giây sẽ không bị hủy. Nếu khối lượng công việc của bạn yêu cầu các truy vấn dài hơn, chỉ cần đặt các tùy chọn này thành giá trị cao hơn.


1
Đây là giải pháp chúng tôi đã sử dụng. Có vẻ như sự thỏa hiệp tốt nhất giữa tất cả các tùy chọn được trình bày ở đây.
mohit6up

2
Đây là câu trả lời tốt nhất. Lưu ý theo các tài liệu này là tích lũy; nếu bạn có nhiều truy vấn trên bản sao giữ bản sao thì có thể là bạn nhận được tới 899 thì truy vấn 2 giây khác sẽ bị hủy. Tốt nhất là chỉ thực hiện một số dự phòng theo cấp số nhân trong mã của bạn. Ngoài ra, độ trễ phát trực tuyến có hiệu lực trong khi sao chép đang truyền phát. Nếu sao chép không thể theo kịp với phát trực tuyến, nó sẽ chuyển sang sao chép từ kho lưu trữ. Nếu bạn đang sao chép từ kho lưu trữ, có lẽ bạn nên để nó bắt kịp, max_standby_archive_delaycó thể cần phải nhỏ hơn cái khác.
Davos

2
Đây vẫn là giải pháp tốt nhất ở đây. Xin lưu ý rằng trong Redshift, bạn có thể đặt cài đặt này thông qua cài đặt nhóm tham số, chỉ có điều nó phải ở trong ms, tức là 900s = 16 phút = 900000ms.
NullDev

Để cập nhật thông tin này trên GCP, cũng được thực hiện trong ms cloud.google.com/sql/docs/postgres/,
howMuchCheeseIsTooMuchCheese

Với mục đích của chế độ chờ là ví dụ như báo cáo và nó không phải là chế độ chờ nóng cần sẵn sàng để xử lý chuyển đổi dự phòng, đây hoàn toàn là câu trả lời tốt nhất.
súp

77

Không cần phải bắt đầu giao dịch nhàn rỗi trên bản gốc. Trong postgresql-9.1, cách trực tiếp nhất để giải quyết vấn đề này là bằng cách thiết lập

hot_standby_feedback = on

Điều này sẽ làm cho chủ nhận thức được các truy vấn dài. Từ các tài liệu :

Tùy chọn đầu tiên là đặt tham số hot_standby_feedback, điều này ngăn VACUUM xóa các hàng chết gần đây và do đó không xảy ra xung đột dọn dẹp.

Tại sao đây không phải là mặc định? Tham số này đã được thêm vào sau khi triển khai ban đầu và đó là cách duy nhất mà chế độ chờ có thể ảnh hưởng đến chủ.


11
Thông số này nên được đặt ở chế độ chờ.
Steve Kehlet

3
Có một số nhược điểm cho chủ trong trường hợp này Phản hồi nóng-Phản hồi
Evgeny Liskovets

50

Như đã nêu ở đây về hot_standby_feedback = on:

Chà, nhược điểm của nó là chế độ chờ có thể làm hỏng chủ, điều này cũng có thể gây ngạc nhiên cho một số người

đây :

Với cài đặt nào của max_standby_streaming_delay? Tôi thà mặc định là -1 hơn mặc định hot_standby_feedback. Bằng cách đó, những gì bạn làm ở chế độ chờ chỉ ảnh hưởng đến chế độ chờ


Vì vậy, tôi đã thêm

max_standby_streaming_delay = -1

Và không còn pg_dumplỗi cho chúng tôi, cũng không làm chủ bloat :)

Để biết ví dụ AWS RDS, hãy kiểm tra http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appcill.PostgreQuery.CommonDBAT task.html


1
@lennard, cái này hiệu quả với tôi Tôi đã thêm cấu hình này vào postgresql.conf của nô lệ, sau đó khởi động lại nô lệ.
Ardee Aram

13
Tất nhiên, bạn có thể nhận được bản sao không bị ràng buộc theo cách này. Và nếu bạn đang sử dụng vị trí sao chép để kết nối bản sao với chủ, điều đó có thể dẫn đến việc giữ lại xlog quá mức trên bản gốc, do đó, nó thực sự chỉ khả thi nếu bạn đang sử dụng lưu trữ WAL.
Craig Ringer

7
Làm thế nào để thiết lập điều này trên AWS RDS?
MP Kris

1
@KrisMP Sử dụng psql
Yehonatan


13

Dữ liệu bảng trên máy chủ nô lệ dự phòng nóng được sửa đổi trong khi truy vấn chạy dài đang chạy. Một giải pháp (PostgreSQL 9.1+) để đảm bảo dữ liệu bảng không bị sửa đổi là tạm dừng sao chép và tiếp tục sau khi truy vấn:

select pg_xlog_replay_pause(); -- suspend
select * from foo; -- your query
select pg_xlog_replay_resume(); --resume

1
Điều này đòi hỏi quyền siêu người dùng. Vì vậy, nó có thể không phải là một giải pháp trong một số trường hợp.
Joao Baltazar

1
Trong PostgreSQL 10, xlogđã được thay thế bằng wal, vì vậy bạn muốn gọi pg_wal_replay_pause()pg_wal_replay_resume().
womble

3

Có thể đã quá muộn cho câu trả lời nhưng chúng tôi phải đối mặt với cùng một loại vấn đề trong quá trình sản xuất. Trước đó, chúng tôi chỉ có một RDS và khi số lượng người dùng tăng lên ở phía ứng dụng, chúng tôi đã quyết định thêm Bản sao Đọc cho nó. Đọc bản sao hoạt động đúng trên dàn nhưng một khi chúng tôi chuyển sang sản xuất, chúng tôi bắt đầu gặp lỗi tương tự.

Vì vậy, chúng tôi giải quyết điều này bằng cách bật thuộc tính hot_standby_feedback trong thuộc tính Postgres. Chúng tôi đã giới thiệu các liên kết sau đây

https://aws.amazon.com/bloss/database/best-practices-for-amazon-rds-postgresql-replication/

Tôi mong nó sẽ có ích.


2

Tôi sẽ thêm một số thông tin và tài liệu tham khảo được cập nhật vào câu trả lời tuyệt vời của @ max-malysh ở trên.

Nói tóm lại, nếu bạn làm một cái gì đó trên chủ, nó cần được nhân rộng trên nô lệ. Postgres sử dụng các bản ghi WAL cho việc này, được gửi sau mỗi hành động được ghi lại trên bản gốc cho nô lệ. Các nô lệ sau đó thực hiện hành động và hai người lại đồng bộ. Trong một trong một số tình huống, bạn có thể xung đột với nô lệ với những gì đến từ chủ trong hành động WAL. Trong hầu hết trong số họ, có một giao dịch xảy ra trên nô lệ mâu thuẫn với những gì hành động WAL muốn thay đổi. Trong trường hợp đó, bạn có hai tùy chọn:

  1. Trì hoãn ứng dụng của hành động WAL một chút, cho phép nô lệ hoàn thành giao dịch xung đột của mình, sau đó áp dụng hành động đó.
  2. Hủy bỏ các truy vấn xung đột trên nô lệ.

Chúng tôi quan tâm đến # 1 và hai giá trị:

  • max_standby_archive_delay - đây là độ trễ được sử dụng sau khi ngắt kết nối dài giữa chủ và phụ, khi dữ liệu đang được đọc từ kho lưu trữ WAL, đây không phải là dữ liệu hiện tại.
  • max_standby_streaming_delay - độ trễ được sử dụng để hủy các truy vấn khi các mục nhập WAL được nhận thông qua sao chép phát trực tuyến.

Nói chung, nếu máy chủ của bạn có nghĩa là sao chép tính sẵn sàng cao, bạn muốn giữ những con số này ngắn. Cài đặt mặc định của 30000(mili giây nếu không có đơn vị nào được cung cấp) là đủ cho việc này. Tuy nhiên, nếu bạn muốn thiết lập một cái gì đó như một kho lưu trữ, báo cáo hoặc đọc bản sao có thể có các truy vấn chạy rất lâu, thì bạn sẽ muốn đặt nó thành một cái gì đó cao hơn để tránh các truy vấn bị hủy. Các 900sthiết lập được đề xuất ở trên có vẻ như là một điểm khởi đầu tốt. Tôi không đồng ý với các tài liệu chính thức về việc đặt một giá trị vô hạn -1là một ý tưởng hay - có thể che giấu một số mã lỗi và gây ra nhiều vấn đề.

Một lưu ý về các truy vấn chạy dài và đặt các giá trị này cao hơn là các truy vấn khác chạy trên nô lệ song song với truy vấn chạy dài khiến hành động WAL bị trì hoãn sẽ thấy dữ liệu cũ cho đến khi hoàn thành truy vấn dài. Các nhà phát triển sẽ cần hiểu điều này và tuần tự hóa các truy vấn không nên chạy đồng thời.

Để được giải thích đầy đủ về cách thức max_standby_archive_delaymax_standby_streaming_delaycông việc và tại sao, hãy vào đây .


1

Tương tự như vậy, đây là một cảnh báo thứ 2 cho @ Artif3x về câu trả lời xuất sắc của @ max-malysh, cả hai ở trên.

Với bất kỳ ứng dụng chậm trễ nào của các giao dịch từ chủ, người theo dõi sẽ có một cái nhìn cũ hơn, cũ hơn về dữ liệu. Do đó, trong khi cung cấp thời gian để truy vấn trên người theo dõi kết thúc bằng cách đặt max_standby_archive_delay và max_standby_streaming_delay có ý nghĩa, hãy ghi nhớ cả hai điều này:

  • giá trị của người theo dõi dưới dạng dự phòng / dự phòng giảm dần
  • bất kỳ truy vấn nào khác đang chạy trên người theo dõi có thể trả về dữ liệu cũ .

Nếu giá trị của người theo dõi để sao lưu kết thúc quá nhiều mâu thuẫn với các truy vấn lưu trữ, một giải pháp sẽ là nhiều người theo dõi, mỗi giải pháp được tối ưu hóa cho cái này hoặc cái kia.

Ngoài ra, lưu ý rằng một số truy vấn liên tiếp có thể khiến ứng dụng của các mục wal tiếp tục bị trì hoãn. Vì vậy, khi chọn các giá trị mới, đây không chỉ là thời gian cho một truy vấn duy nhất, mà là một cửa sổ di chuyển bắt đầu bất cứ khi nào một truy vấn xung đột bắt đầu và kết thúc khi mục nhập cuối cùng được áp dụng.

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.