2013-03-23 38 views
6

Đã 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

+0

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. –

+0

xin vui lòng truy vấn povide giữ khóa –

+0

@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. –

Trả lời

0

Bằng cách nào đó ngủ đông-memcached dường như là tại nguyên nhân gốc rễ của vấn đề này . Loại bỏ hibernate-memcached khỏi hệ thống của chúng tôi đã tạo ra tất cả các vấn đề của chúng tôi, nếu không biến mất, ít nhất bắt đầu hoạt động như các vấn đề cơ sở dữ liệu bình thường mà bạn mong đợi để tìm cách nâng cao và mở rộng ứng dụng.

Tôi không cố gắng nói bất cứ điều gì xấu về hibernate-memcached. Chúng tôi đã sử dụng thành công dự án này trong hơn một năm sản xuất mà không có sự cố. Nó có nhiều khả năng có một cuộc xung đột với cái gì khác cụ thể cho hệ thống của chúng tôi, và ngủ đông-memcached chỉ đơn giản là điều dễ nhất để chúng ta thay đổi.

1

Trước tiên, bạn cần phải là tuyệt vời Scaling Hibernate Ứng dụng với Postgres nói chuyện được trình bày bởi Jim mlodgenski và Bruce Momjian trong JBoss Thế giới năm 2009 để giải quyết hầu hết các các vấn đề thường gặp với Hibernate và PostgreSQL (Caching, replication, Connection pooling, vv). Yo thể tìm thấy nó here:

Sau đó, bạn có thể gửi câu hỏi trực tiếp trong SQL đơn giản nếu bạn có một số rắc rối với Lazy Chở Hàng:

String SQL_QUERY = "SELECT insurance_name, id, invested_amount, avg(i... 
       + "invested_amount - avg(invested_amount) OVER(PARTI... 
       + "FROM insurance "; 
Query query = session.createSQLQuery(SQL_QUERY) 
        .addScalar("insurance_name", Hibernate.STRING) 
        .addScalar("id", Hibernate.LONG) 
        .addScalar("invested_amount", Hibernate.LONG) 
        .addScalar("a", Hibernate.DOUBLE) 
        .addScalar("diff", Hibernate.DOUBLE); 
+0

Cảm ơn bạn đã đề xuất. Tôi thực sự không chắc chắn nếu đây là một điều Hibernate ở tất cả các điểm này. Dường như cuộc săn lùng đã đưa chúng ta xuống sâu vào lớp cơ sở dữ liệu, nhưng đây chỉ là giả thuyết của thời điểm này :) –

Các vấn đề liên quan