Đã xé tóc của tôi ra trong một vài ngày qua cái này. Chúng tôi đã gặp sự cố với các khóa cơ sở dữ liệu độc quyền gây ra các vấn đề về hiệu suất trong hệ thống sản xuất của chúng tôi trong một thời gian. Tôi đã có thể có một cái nhìn sâu hơn về nó, và nhận thấy các truy vấn giữ khóa độc quyền là lựa chọn được tạo ra bởi tải lười biếng của Hibernate.Hibernate + PostgreSQL: Tải Lười Biếng với Ổ Khóa Độc Quyền
Chúng tôi đang sử dụng Quản lý giao dịch mùa xuân, @Transactional(readOnly= "true")
được xác định tại điểm nhập dịch vụ. Chúng tôi sử dụng mô hình phiên cho mỗi yêu cầu với các đối tượng được ánh xạ tới các đối tượng chuyển. Mức cô lập mặc định của cơ sở dữ liệu được đọc là cam kết. Trình điều khiển JDBC được cấu hình với đọc đã cam kết. Tôi đã kiểm tra mức độ cách ly của giao dịch thực tế đang được đề cập đến bằng cách sử dụng:
select current_setting('transaction_isolation')
Trả về đã đọc cam kết. Chúng tôi đang sử dụng JPA để cấu hình ánh xạ Hibernate. Không nơi nào chúng tôi nâng cấp giao dịch một cách rõ ràng. Trong giao dịch cụ thể này, chúng tôi chỉ chạy các câu lệnh chọn. Bật ghi nhật ký SQL Hibernate Tôi không thấy bất kỳ điều nào sau đây:
select ... for update
Chỉ các câu lệnh chọn đơn giản mới được ghi lại.
Dường như một trong hai điều đang diễn ra ở đây. Hoặc sự hiểu biết của tôi về đọc cam kết là hoàn toàn tắt và đọc mức cô lập cam kết NÊN kết quả trong khóa cấp hàng độc quyền được tổ chức trong thời gian giao dịch thực hiện các lựa chọn. Hoặc cái gì khác đang xảy ra và nâng cấp không chính xác các khóa được tổ chức bởi giao dịch.
Mọi trợ giúp sẽ được đánh giá cao.
Sửa 1:
Ok, là một con đường dài quanh co trên thế này. Hóa ra điều này không có gì để làm với khóa ở tất cả. Truy vấn tôi đang sử dụng để phát hiện khóa đã lỗi thời và đang hiển thị loại khóa "virtualxid". Một số đào cho chúng tôi biết virtualxid là khóa mọi giao dịch diễn ra trên chính nó, vì lý do bên trong PostgreSQL không phải là nguyên nhân của cuộc thảo luận này. Chúng tôi đã cron'd một kiểm tra truy vấn kiểm tra cho các khóa độc quyền thực sự, và đã không nhìn thấy một được nêu ra.
Dưới đây là truy vấn chúng tôi đang sử dụng để giám sát cho ổ khóa "virtualxid", mà là giống như một màn hình truy vấn dài chạy tại thời điểm này:
SELECT pg_stat_activity.datname, pg_locks.mode, pg_locks.locktype, pg_locks.granted, pg_stat_activity.usename,pg_stat_activity.query,age(now(),pg_stat_activity.query_start) AS "age", pg_stat_activity.pid
FROM pg_stat_activity,pg_locks
LEFT OUTER JOIN pg_class ON (pg_locks.relation = pg_class.oid)
WHERE
age(now(),pg_stat_activity.query_start) > interval '1 minute' AND
pg_stat_activity.datname <> 'postgres' AND
pg_locks.pid=pg_stat_activity.pid AND
pg_stat_activity.query not like '%autovacuum%' AND
pg_stat_activity.query not like '%COPY%stdout%'
order by query_start;
Và đây là một số đầu ra chúng tôi nhận được:
<redacted> | ExclusiveLock | virtualxid | t | <redacted> | SELECT current_timestamp | 01:03:51.809594 | 22578
Một current_timestamp chọn đơn giản chạy trong hơn một giờ !!!
Dù sao, đối với những người quan tâm, nó bắt đầu trông giống như những truy vấn bí ẩn chạy lâu này thỉnh thoảng thoát khỏi nhóm kết nối cơ sở dữ liệu của chúng tôi. Vì vậy, chúng tôi sẽ giới hạn kết nối hồ bơi và trang web trực tiếp trở lại để làm ồn cùng. Chúng tôi đã có thời gian chờ của ứng dụng và thử lại logic tại chỗ trên các quy trình quan trọng để xử lý các trục trặc thường xuyên. Và những ngày này, chúng tôi thường có ít nhất một chuỗi cơ sở dữ liệu bị mắc kẹt phục vụ một trong các truy vấn thực hiện kỳ lạ này. Chắc chắn không phải lý tưởng: (
Chúng tôi sẽ thử bật máy hút bụi tự động dựa trên chi phí và xem điều này có giúp ích gì cho vấn đề không.
Chỉnh sửa 2:
Cái này hóa ra là một hành trình rất dài, mà có thể là lúc đó là kết thúc. Để đối phó với hành vi này, chúng tôi đã lưu trữ báo cáo lỗi xử lý hàng loạt của chúng tôi ngoài việc theo dõi truy vấn cơ sở dữ liệu mà chúng tôi đưa ra ở trên. Cùng với một số thời gian chờ thông minh, điều này cho phép chúng tôi tương quan các trường hợp sử dụng ứng dụng cụ thể với các truy vấn cơ sở dữ liệu chạy dài. Điều này cho phép chúng tôi phản ứng với các lỗi được thấy trong sản xuất để ngăn chặn các tập quán cụ thể khỏi việc treo nút JVM.
Chúng tôi cũng có thể giải quyết vấn đề tại sao một TX chạy dài, chỉ đọc trong một quy trình sẽ treo lên các quy trình khác kết nối với cùng một cơ sở dữ liệu. Đây là nơi mọi thứ trở nên hơi lạ. Chúng tôi đã sử dụng hibernate-memcached để di chuyển bộ nhớ cache cấp thứ hai của hibernate vào một máy chủ được chia sẻ memcached cho tất cả các quy trình Java kết nối với cùng một cơ sở dữ liệu. Bất cứ khi nào chúng ta có hành vi treo lạ lùng sẽ có một tấn các luồng máy khách được ghi nhớ trong các quy trình JVM.
Sau khi gỡ bỏ mô-đun ngủ đông-ngủ đông, di chuyển trở lại ehcache cho bộ nhớ cache cấp thứ hai, chúng tôi nhận thấy treo nhiều lỗi JVM kỳ lạ đã biến mất. Chúng tôi vẫn nhận được các email thường xuyên cho chúng tôi biết thêm một chút đang xảy ra bên trong một TX hơn là nên. Chúng tôi vẫn nhận được quá trình JVM đơn lẻ không thường xuyên treo lên vì nó có quá nhiều trong số các TX dài này xảy ra ở quy mô lớn. Nhưng chúng tôi không còn thấy các quy trình trong một JVM bằng cách nào đó ảnh hưởng đến các JVM khác. Trong khi trước đây chúng ta sẽ thấy các nút bổ sung không phản hồi cho đến khi chúng ta giết nút ban đầu cho thấy hành vi xấu của TX.
Điều gì không có ý nghĩa. Nhưng sau đó vấn đề này chưa bao giờ :)
- Tim
Bạn thực sự cần xem xét 'pg_locks' để xem điều gì đang xảy ra. Xem http://wiki.postgresql.org/wiki/Lock_Monitoring. Cũng vui lòng chỉ định phiên bản Hibernate và phiên bản PostgreSQL của bạn. –
xin vui lòng truy vấn povide giữ khóa –
@CraigRinger: Cập nhật để hiển thị truy vấn và kết quả khóa. Tôi không chắc chắn nó là Hibernate ở tất cả các điểm này. PostgreSQL v9.2. –