我们监视PostgreSQL数据库-谁该负责以及该怎么做

我已经讨论过如何在数百个服务器上同时使用批量日志监视来“捕获” PostgreSQL问题。但是,除了日志,此DBMS还为我们提供了许多分析其状态的工具 -不使用它们是一个罪过。

没错,如果您只是从控制台查看它们,则可以非常快速地进行操作而没有任何好处,因为我们可用的数据量超过了所有合理的限制。


因此,为了使情况可控,我们为Zabbix开发了一个插件该插件可提供度量标准,形成屏幕并为其中的所有服务器和数据库设置统一的监视规则

今天的文章是关于通过动态观察PostgreSQL服务器基础的各种指标可以得出什么结论,以及该问题可能隐藏的地方。

连接状态


关于“我们的数据库发生了什么/它是不好的”主题的所有拆解的第一件事都是监视pg_stat_activity的摘要状态



在左图上,我们看到所有正在等待某事的连接,在右图上-这是某事做。根据PG版本,连接状态由pg_stat_activity.state/wait_event和/或请求本身的文本确定

寻找什么

  • idle -在某些时候你的应用程序可能没有足够的已连接到数据库的开启,而当你试图打开一个又一个,你会发现自己在等待的过程中初始化服务于一个新的连接。
  • idle «» , max_connections.
  • idle in transaction — , - pgbouncer. .

    , , idle_in_transaction_session_timeout.
  • wait — - «» . — .

    , «» pg_terminate_backend(pid).
  • active ( max-) , «». - (, « ») , , …

    — , «» .
  • maintenance — , - :

    query ~* E'^(\\s*(--[^\\n]*\\n|/\\*.*\\*/|\\n))*(autovacuum|VACUUM|ANALYZE|REINDEX|CLUSTER|CREATE|ALTER|TRUNCATE|DROP)'

    在大多数情况下,将同时进行自动清理/自动分析的数量,其危害仅在于将服务器资源用于“外部”情况。如果这是你的关键-扭曲autovacuum_max_workersautovacuum_naptime,但其完全关闭-你不应该

    但是,如果同时开始增长waitmaintenance那么就有机会查看是否有人决定退出DBA或开发人员代码,例如,将功能性应用程序的机会减少了一半。

由于不仅要删除大量指标,而且要尽可能高效地删除它,这对我们很重要,所以我们尝试在一个请求的框架内同步拍摄其中一些指标:

连接和锁定状态
WITH event_types(wait_event_type) AS(
  VALUES
    ('lwlock')
  , ('lock')
  , ('bufferpin')
  , ('client')
  , ('extension')
  , ('ipc')
  , ('timeout')
  , ('io')
)
, events(wait_event) AS(
  VALUES
    ('walwritelock')
  , ('wal_insert')
  , ('buffer_content')
  , ('buffer_io')
  , ('lock_manager')
  , ('relation')
  , ('extend')
  , ('page')
  , ('tuple')
  , ('transactionid')
  , ('virtualxid')
  , ('speculative token')
  , ('object')
  , ('userlock')
  , ('advisory')
  , ('clientread')
  , ('datafileextend')
  , ('datafileread')
  , ('datafilewrite')
  , ('slruread')
  , ('slruwrite')
)
, states(state) AS(
  VALUES
    ('running')
  , ('maintenance')
  , ('waiting')
  , ('transaction')
  , ('idle')
)
, stats AS(
  SELECT
    pid
  , datname
  , state
  , lower(wait_event_type) wait_event_type
  , lower(wait_event) wait_event
  , query
  FROM
    pg_stat_activity
  WHERE
    pid <> pg_backend_pid()
)
, dbs AS(
  SELECT
    datname
  FROM
    pg_database db
  WHERE
    NOT db.datistemplate
)
  SELECT
    date_part('epoch', now())::integer ts
  , coalesce(s.qty, 0) val
  , dbs.datname dbname
  , states.state
  , true total
  FROM
    dbs
  CROSS JOIN
    states
  NATURAL LEFT JOIN
    (
      SELECT
        datname
      , CASE
          WHEN query ~* E'^(\\s*(--[^\\n]*\\n|/\\*.*\\*/|\\n))*(autovacuum|VACUUM|ANALYZE|REINDEX|CLUSTER|CREATE|ALTER|TRUNCATE|DROP)' THEN
            'maintenance'
          WHEN wait_event IS NOT NULL AND
            wait_event <> 'clientread' AND
            state = 'active' THEN
            'waiting'
          WHEN state = 'active' THEN
            'running'
          WHEN state = 'idle' THEN
            'idle'
          WHEN state IN ('idle in transaction', 'idle in transaction (aborted)') THEN
            'transaction'
          WHEN state = 'fastpath function call' THEN
            'fastpath'
          ELSE
            'disabled'
        END state
      , count(*) qty
      FROM
        stats
      GROUP BY
        1, 2
    ) s
UNION
  SELECT
    date_part('epoch', now())::integer ts
  , coalesce(t.qty, 0) val
  , dbs.datname dbname
  , event_types.wait_event_type
  , false total
  FROM
    dbs
  CROSS JOIN
    event_types
  NATURAL LEFT JOIN
    (
      SELECT
        datname
      , wait_event_type
      , count(*) qty
      FROM
        stats
      WHERE
        wait_event_type IS NOT NULL
      GROUP BY
        1, 2
    ) t
UNION
  SELECT
    date_part('epoch', now())::integer ts
  , coalesce(e.qty, 0) val
  , dbs.datname dbname
  , events.wait_event
  , false total
  FROM
    dbs
  CROSS JOIN
    events
  NATURAL LEFT JOIN
    (
      SELECT
        datname
      , wait_event
      , count(*) qty
      FROM
        stats
      WHERE
        wait_event IS NOT NULL
      GROUP BY
        1, 2
    ) e;

锁具


由于我们在上一段中谈到了锁的监视,因此值得注意的是PostgreSQL喜欢左右左右应用锁:在这些锁中



,我们对两种类型最感兴趣:

  • Exclusive -通常在锁定特定记录时发生。
  • AccessExclusive -在桌子上进行维护操作时。

但是请不要忘记的总数不是橡胶的
咨询锁和常规锁都存储在共享存储区中,共享存储区的大小由配置参数max_locks_per_transaction和决定max_connections此内存足够重要,因为否则服务器将无法发出任何因此,取决于服务器配置,服务器可以发出的建议锁定的数量通常限制为数以万计。
通常,如果没有释放应用程序“流程”和资源:与数据库的连接,事务上下文或咨询锁,就会出现这种情况因此,要注意整体动态。

每秒事务数(TPS)


要获取有关当前数据库的上下文中的更改的信息,可以使用系统视图pg_stat_database但是,如果服务器上有许多数据库,则对于连接到的postgres所有数据库而言,立即执行此操作很方便

TPS和元组
SELECT
  extract(epoch from now())::integer ts
, datname dbname
, pg_stat_get_db_tuples_returned(oid) tup_returned
, pg_stat_get_db_tuples_fetched(oid) tup_fetched
, pg_stat_get_db_tuples_inserted(oid) tup_inserted
, pg_stat_get_db_tuples_updated(oid) tup_updated
, pg_stat_get_db_tuples_deleted(oid) tup_deleted
, pg_stat_get_db_xact_commit(oid) xact_commit
, pg_stat_get_db_xact_rollback(oid) xact_rollback
FROM
  pg_database
WHERE
  NOT datistemplate;

我想单独强调-不要忽略指标最大值的输出



在此图中,我们可以清楚地看到进行的commit交易数量突然达到峰值的情况这不是一对一地对应于服务器上的负载,并且事务可能具有不同的复杂性,但是4倍的增长清楚地表明,服务器应该具有一定的性能储备,以便能够在没有问题的情况下生存下来。

很好,rollback事务的回滚()是检查您的应用程序是否有意识地执行ROLLBACK或服务器是否由于错误而自动执行的时候。

记录中的操作数


首先,请注意我们从索引/表中减去的记录:



  • tuples.returned — , «» .
  • tuples.fetched — , « » Rows Removed by Filter, «» .
  • tuples.ratio — , , 1, — . , , , .

如果您观察到一个尖锐的峰值tuples.ratio,则可以确定在日志旁边,您会发现有关文章描述的有关处理它们的食谱的类别中的一些无效请求

但是,即使ratio理论上等于1,但峰值也下降了returned/fetched -也不要指望好。通常,这可能意味着计划中存在某种麻烦,例如:

Hash Join
  - Hash
    - Seq Scan on BIG_TABLE
  - Index Scan ...

Merge Join
  - Index Scan on BIG_INDEX
  - Index Scan ...

自从我们开始检查那里正在读取的内容之后,让我们看看它是如何发生的。也就是说,我们通过索引读取了多少记录,以及结果多少Seq Scan



很明显,任何计划外的指标增长都应该引起怀疑。例如,如果出于某种原因您需要每晚读取整盘10M记录,那么白天出现这种高峰就是拆卸的原因。

以及任何质量异常的插入/更新/删除:



使用数据缓存


要了解对文件进行大规模校对实际上如何使服务器的寿命变差,让我们看一下服务器在处理数据页和比率时block.read/hit的工作情况在理想情况下,服务器不应绝对不从磁盘(shared read在计划节点上)“读取” 任何内容,所有内容都应该已经在内存中(shared hit),因为访问磁盘总是很慢

实际上,这并不完全正确,这是在高峰时间对请求进行全面分析的原因:



最长的请求/交易


对于MVCC,繁忙的系统中长时间运行的查询和事务是性能的灾难。可以在此处此处阅读有关此内容的详细信息和图片-在这样的条件下您仍然如何生存。



抓住这样的恶棍对我们有帮助pg_stat_activity.query_start/xact_start

正如我们的经验所示,这些指标的可视化表示已经足以大致表示进一步“挖掘”的位置:

  • 在应用程序中查找资源泄漏
  • 优化失败的请求
  • 放置更具生产力的硬件
  • ...或确保按时间正确分配负载

All Articles