暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Postgres锁定:什么时候进行?

原创 eternity 2022-08-03
513

当使用诸如PgMonitor或pganalyze之类的监控工具时,Crunchy客户机经常会问我锁的数量多以及何时需要担心。与大多数工程相关的问题一样,答案是:“视情况而定”。

在这篇文章中,我将提供更多关于锁的信息,如何在PostgreSQL中使用锁,以及寻找什么东西来发现问题和高使用率。

PostgreSQL在其操作的所有部分都使用锁来序列化或共享对关键数据的访问。这可以以两种基本类型的锁的形式出现:共享锁或独占锁。

  • 共享锁—特定资源可以由多个后端/会话同时访问。

  • 独占锁—特定资源一次只能由单个后端/会话访问。

同一资源可以使用相同或不同的强度对其采取不同的锁。

锁定持续时间

PostgreSQL会话中运行的每个语句都在事务中运行。通过事务控制语句(BEGIN、COMMIT等)显式创建的事务或为单个语句创建的隐式事务。

当PostgreSQL获取锁时,它会在事务期间获取锁。除非交易最终终止,否则无法明确解锁。这样做的原因之一是为了快照的一致性,并确保现有事务具有适当的依赖关系。一旦交易结束,现在这无关紧要,所以可以释放锁。

值得注意的是,PostgreSQL(以及任何多进程系统)在内部使用锁进行SQL级后端和事务之外的其他访问

监控锁

如果您正在阅读本文并对监控感兴趣,那么您可能已经熟悉了pg_锁视图。这是一个系统视图,显示内置锁阵列的当前状态。此处可用字段和文档的详细信息可能因版本而异;有关详细信息,请从此页面选择您的PostgreSQL版本。

文档提供了有关此视图的许多详细信息。这里需要知道的重要一点是,这是监测/审查该系统的主要方式。一些相关领域包括:
image.png
特别需要注意的是“grated”字段,这是一个布尔值,显示给定的锁是否已被授予相关后端。如果有一个未授权的锁(即,grated=f),则这意味着后端在等待锁时被阻塞。在成功获得锁的进程以某种方式完成(即提交或回滚)之前,此进程将陷入僵局,无法继续。

可用于获取有关PostgreSQL后端进程的更多信息的相关系统视图是久负盛名的pg_stat_activity视图,尤其是wait_事件字段。如果给定的后端进程当前正在等待锁,则会显示wait_event,无论是“重量级”锁还是“轻量级”锁(由wait_event_type=LWLock表示)。

定期使用锁

当查询访问SELECT语句的表时,它对该表使用AccessShare锁。如果一个查询访问多个表,它将对每个表进行锁定。根据您的查询模式和事务长度,每个后端连接可能会有几十个甚至数百个AccessShare锁,而这并不表示存在问题。这也是为什么仅仅将pg_锁中的锁数作为数据库中问题的度量标准并不一定有用的原因。如果有大量连接在运行查询,或者如果工作负载发生变化(例如,随着应用程序部署),这可能会导致大量锁,而这不是问题。

那么问题是什么?

虽然大量锁并不一定表示存在问题,但有些问题可能会导致大量锁。例如,如果查询运行效率不高,因此需要很长时间,那么在后端等待释放资源时,可能会有大量备份连接,从而导致额外的锁累积。

任何长时间的未授权锁都表明存在问题,应该对此进行调查。

SELECT COUNT(*) FROM pg_locks WHERE NOT granted;

请注意,根据运行此查询的时间,可能会出现未授权锁的简短实例。然而,如果第二次调用此查询时仍然存在相同的锁,则可能表明存在更大的问题。

调查更多

如果您确实有一个未授权的锁,那么您需要查看当前拥有该锁的进程;这是一个行为不端的过程。为此,您可以运行以下查询以获取有关特定后端及其正在运行的查询的信息:

SELECT pid, pg_blocking_pids(pid), wait_event, wait_event_type, query
FROM pg_stat_activity
WHERE backend_type = 'client backend'
AND wait_event_type ~ 'Lock'

这里,pid进程将是被阻塞的进程,而pg_blocking_pids()函数将返回当前阻止该进程运行的pid数组。(实际上,这是一个具有pid后端正在等待的锁的进程列表。)根据此进程正在执行的操作,您可能希望采取某种纠正措施,例如取消或终止该后端。(此处的正确操作过程将取决于您的具体应用。)

非阻塞锁

由于锁只是PostgreSQL控制对其资源的访问的一种正常方式,因此可以预期高锁和高使用率。因此,大量锁是否表示存在问题,取决于这些锁是什么,以及系统本身是否存在任何其他问题。

如果IO使用率非常高,您经常会看到LWLock数据读取,这可能会影响多个后端。如果IO过载,任何试图从磁盘读取文件的进程都将处于这种状态。因此,执行更多IO操作将无法完成更多的读取;系统的IO带宽是有限的,如果您已经处于系统的极限。添加更多请求只会进一步分割资源,并将其拆分到其他后端。

如果系统正在读取大量缓冲区,或者对相同的缓冲区有很多争用(例如,试图清空使用的缓冲区,但其他进程除外),那么最终可能会遇到缓冲区锁。这是一个锁,在尝试同时加载大量缓冲区时基本上可以看到。有多个共享锁用于确保没有单个锁保护缓冲区页面负载,但这仍然是一个有限的资源,因此在高负载时,您可以看到这显示为一个阻塞过程。任何一个锁都可能很短,但在高负载期间,您会经常在pg_stat_activity中看到这些寄存器。

根据系统的事务量和事务类型,您可以在主或副本上看到许多带有多个SLRU锁之一的查询。这里有几种类型,包括SubtransSLRU和MultiXactSLRU。

咨询锁

客户端还遇到了一些关于咨询锁的问题,特别是在使用事务级连接池(如PgBouncer)时。PostgreSQL中的显式顾问锁函数允许用户访问其应用程序代码中的锁原语,并允许在应用程序级别序列化资源,这在尝试与外部系统协调访问时特别有用。也就是说,如果不正确使用这些原语,可能会遇到问题。

需要特别注意的是,如果用户在使用数据库池时使用应用程序代码中的pg_advision_lock(),则由于可能使用不同的数据库会话,最终可能会出现死锁或令人困惑的行为。由于pg_advision_lock()函数为其当前数据库会话(而不是当前事务)获取锁,因此多个pg_advision_lock()调用可能最终会在不同的后端运行(因为PgBouncer会为单独的事务使用相当任意的后端)。

由于锁在单独的会话中被获取并可能被释放(甚至来自同一个应用程序数据库连接),因此不能保证它们打算序列化访问的资源以一致的方式完成。PgBouncer特别建议不要出于这个原因使用这些基于会话的锁定功能。

使用数据库池的应用程序应该考虑使用基于事务的锁,以便序列化这些访问;i、 例如,pg_advisory_xact_lock()和朋友。如果这不可能,则应使用会话模式下的单独数据库池,以允许会话处理按预期工作。

注意,pg_advision_lock()在数据库池之外有自己的一组问题。即使创建锁的事务回滚,它也不会释放锁。它可以在应用程序代码方面进行仔细的协调和异常处理,以有效地使用它。

最后的想法

我希望本文能让您了解到在应用程序级别可能需要关注哪些类型的锁定。这些情况可能需要调查和/或更改应用程序:

  • 未安装锁

  • pg_stat_activity中始终出现大量LWLocks

  • 会话级咨询锁

原文标题:Postgres Locking: When is it Concerning?
原文作者:David Christensen
原文链接:https://www.crunchydata.com/blog/postgres-locking-when-is-it-concerning

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论