Tim*_*mer 6 java postgresql spring hibernate
在这一天上,我的头发被撕掉了几天.我们在使用独占数据库锁时遇到了一些问题,导致我们的生产系统出现性能问题一段时间了.我能够仔细研究它,并注意到持有独占锁的查询是由Hibernate的延迟加载生成的选择.
我们正在使用Spring事务管理,@Transactional( readOnly= "true")
在服务入口点定义.我们使用会话每请求模型和映射到传输对象的实体.读取数据库默认隔离级别已提交.JDBC驱动程序配置为read committed.我使用以下方法检查了实际交易的隔离级别:
select current_setting('transaction_isolation')
Run Code Online (Sandbox Code Playgroud)
哪个返回read committed.我们使用JPA来配置Hibernate映射.我们没有在任何地方明确升级交易.在这个特定的事务中,我们只运行select语句.打开Hibernate SQL日志记录我没有看到任何这些:
select ... for update
Run Code Online (Sandbox Code Playgroud)
只记录简单的select语句.
这似乎是两件事之一.我对read committed的理解是完全关闭的,读取提交的隔离级别应该导致在执行选择的事务期间保持独占的行级锁定.或者正在发生其他事情并错误地升级事务所持有的锁.
任何帮助,将不胜感激.
编辑1:
好吧,在这一条路上走了很长的路.事实证明这与锁定无关.我用来检测锁的查询已经过时,并且显示锁定类型为"virtualxid".一些挖掘告诉我们,virtualxid是每个事务自身锁定的锁,因为PostgreSQL的内部原因与此讨论没有密切关系.我们cron'd另一个监控查询测试真正的独占锁,还没有见过.
这是我们用来监视"virtualxid"锁的查询,这个锁更像是一个长时间运行的查询监视器:
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;
Run Code Online (Sandbox Code Playgroud)
这是我们得到的一些输出:
<redacted> | ExclusiveLock | virtualxid | t | <redacted> | SELECT current_timestamp | 01:03:51.809594 | 22578
Run Code Online (Sandbox Code Playgroud)
一个简单的选择current_timestamp运行超过一个小时!
无论如何,对于那些感兴趣的人,它开始看起来像这些神秘的长时间运行的查询偶尔会耗尽我们的数据库连接池.所以我们提高了连接池的限制,现场网站又恢复了嗡嗡声.我们已经在关键流程上设置了应用程序端超时和重试逻辑,以处理偶尔的打嗝.而这些天我们通常至少有一个数据库线程卡住了这些奇怪的执行查询之一.绝对不理想:(
我们将尝试打开基于成本的自动吸尘器,看看这是否有助于解决问题.
编辑2:
事实证明这是一段漫长的旅程,可能就在它的尽头.为了响应这种行为,除了上面提到的数据库查询监控之外,我们还支持了批处理错误报告.结合一些智能超时,这使我们能够将特定的应用程序用例与长时间运行的数据库查询相关联.这使我们能够对生产中出现的错误做出反应,以防止特定用法挂起JVM节点.
我们还能够解决为什么在一个进程中长时间运行的只读TX会挂起连接到同一数据库的其他进程的问题.这是事情变得有点奇怪的地方.我们使用hibernate-memcached将hibernate的二级缓存移动到连接到同一数据库的所有Java进程的共享memcached服务器.每当我们得到奇怪的挂起行为时,JVM进程中就会有大量的memcached客户端线程.
删除hibernate-memcached模块后,回到ehcache进行二级缓存,我们注意到奇怪的多JVM衰弱的悬挂消失了.我们仍会偶尔收到一封电子邮件,告诉我们TX内部发生的事情比应该发生的要多一些.我们仍然偶尔会出现单个JVM进程,因为它有太多的这些长TX正在大规模进行.但是我们不再看到一个JVM中的进程以某种方式影响其他JVM.以前我们会看到其他节点没有响应,直到我们杀死显示不良TX行为的初始节点.
这没有意义.但后来这个问题从来没有:)
- 蒂姆
不知何故,hibernate-memcached 似乎是这个问题的根本原因。从我们的系统中删除 hibernate-memcached 使我们的所有问题(即使没有消失)至少开始像正常的数据库问题一样,您希望发现增强和扩展应用程序。
我并不是想说 hibernate-memcached 的任何坏话。我们在生产中成功使用该项目一年多,没有发生任何事故。更有可能的是与我们系统特定的其他内容发生冲突,而 hibernate-memcached 对我们来说是最容易更改的。
归档时间: |
|
查看次数: |
2434 次 |
最近记录: |