<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Postgres in okmeter.io blog on Medium]]></title>
        <description><![CDATA[Latest stories tagged with Postgres in okmeter.io blog on Medium]]></description>
        <link>https://blog.okmeter.io/tagged/postgres?source=rss----4e571b327a8c--postgres</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Postgres in okmeter.io blog on Medium</title>
            <link>https://blog.okmeter.io/tagged/postgres?source=rss----4e571b327a8c--postgres</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 16 May 2026 17:00:42 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/okmeter-io/tagged/postgres" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <item>
            <title><![CDATA[PgBouncer monitoring improvements in recent  versions]]></title>
            <link>https://blog.okmeter.io/pgbouncer-monitoring-improvements-in-recent-versions-5905f5d1a1ed?source=rss----4e571b327a8c--postgres</link>
            <guid isPermaLink="false">https://medium.com/p/5905f5d1a1ed</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[postgres]]></category>
            <category><![CDATA[database-administration]]></category>
            <category><![CDATA[distributed-systems]]></category>
            <category><![CDATA[monitoring]]></category>
            <dc:creator><![CDATA[pavl t]]></dc:creator>
            <pubDate>Mon, 15 Oct 2018 13:48:48 GMT</pubDate>
            <atom:updated>2018-10-15T13:48:47.929Z</atom:updated>
            <content:encoded><![CDATA[<h3>PgBouncer monitoring improvements in recent versions</h3><p>As I wrote in my previous article “<a href="https://blog.okmeter.io/use-red-and-real-world-pgbouncer-monitoring-61b34ebeebb8?utm_source=blog.okmeter.io&amp;utm_content=pgbouncer-new">USE, RED and real world PgBouncer monitoring</a>” there are some nice commands in PgBouncer’s admin interface that allow to collect stats how things going and spot problems, if you know where to look.</p><p>This post is about new stats added in these commands in new PgBouncer versions.</p><p>So as you know, SHOW STATS shows cumulative stats for each proxied DB:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1xOem_uDO7ef1dTS.png" /></figure><p>Since PgBouncer version 1.8 there’s a couple of new columns in its output.</p><p>First one — total_xact_time — total number of microseconds spent by pgbouncer when connected to PostgreSQL in a transaction, either idle in transaction or executing queries.</p><p>This will allow us to chart db pool utilization in terms of time spent in transactions and compare it to the query time utilization:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/567/1*pAJVYl8ejtcWp3Wu9RI9TA.png" /></figure><p>We see two totally different situations — while database is used for serving queries only 5 to 25 % of the time, PgBouncer connections around 8:00 am spend up to 70% of time in transactions!</p><blockquote>But this total_xact_time is useful in one more very important way.</blockquote><p>There’s a known anti-pattern in Postgres usage, is when your application opens up a transaction, makes a query and then starts doing something else, for example some CPU-heavy calculation on that result or query to some other resource/service/database, while transaction keeps hangging. Later this app will probably return back to this transaction and might, for example, update something and commit it. The bad thing in that case is that there’s a corresponding Postgres backend process, that sits there doing nothing, while transaction is idling. And Postgres backends are somewhat expensive.</p><blockquote>Your app should avoid such behavior.</blockquote><p>This idle in transaction state might be monitored in the Postgres itself — there’s state column in pg_stat_activity system view. But pg_stat_activity provides us only with a snapshot of current states, that leads to possible false negative errors in reporting occurrences of such cases. Using PgBouncer&#39;s stats we can calculate a percentage of time that clients were performing some queries (total_query_time) from the total time spent by client while in transaction: total_xact_time. If we subtract that from 100% that will be idling percentage:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/0*UKR7tzK0Sz-LDQkG.png" /></figure><p>Moreover, there’s new two metrics in 1.8 version of PgBouncer that substitute original total_requests stat, that showed number of queries performed. With modern version of PgBouncer you’ll have total_query_count instead of total_requests, and additionally total_xact_count — that counts number of transactions.</p><p>So with that in hand, we can divide total_xact_time - total_query_time (total idling time) to the number of transactions —total_xact_count — this will give us how long on average each transaction is idling.</p><p>Furthermore with all that, we can characterize database workload in one more useful way: we can calculate average number of queries per transaction, by dividing the rate of queries by the rate of transactions. In okmeter monitoring you can do that as simple as this:</p><pre>rate(<br>   metric(name=&quot;total_query_count&quot;, database=&quot;*&quot;)<br>) / rate(<br>   metric(name=&quot;total_xact_count)&quot;, database=&quot;*&quot;)<br>) </pre><p>And here’s a corresponding chart:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/0*vj5UzwADOojgltLg.png" /></figure><p>We can see clearly when there were changes in workload profile.</p><h3>Request Durations</h3><p>As we saw in the previous article if you divide total_query_time by total_requests you’ll get average query duration. With newer PgBouncer versions these new stats you get —total_xact_time and total_wait_time can be charted in the same way — divided by the number of transactions and queries respectfully. This will produce a chart like this one:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/0*dT4qjlnWBtVt0THw.png" /></figure><p>This wait_time metric is way more handy in spotting pool saturation, than the one we discussed previous time, calculated from the number of waiting client in SHOW STATS output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/0*QTuhLd3RRFZY_qsL.png" /></figure><p>With all that and other <a href="https://okmeter.io/i/integrations/pgbouncer-monitoring?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-2">detailed PgBouncer metrics</a> and <a href="https://okmeter.io/i/integrations/postgresql-monitoring?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-2">Postgres metrics</a> you’ll be prepared to anything happening with your databases.</p><p>I hope you find this write up useful. I’ve tried to cover all the bases, if you feel that you have something to add — please, tell me, I’ll be glad to discuss.</p><p>We’re preparing next articles on Postgres and monitoring. So if you’re interested — follow our blog <a href="https://blog.okmeter.io">here</a>, or at <a href="http://fb.com/okmeter.io">facebook</a> or <a href="https://twitter.com/okmeterio/">twitter</a> to stay tuned!</p><p><em>Our </em><a href="https://okmeter.io/pg?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-2"><em>monitoring service — okmeter.io</em></a><em> will help you stay on-top of everything happening with you Postgresql, RDS and other infrastructure services.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5905f5d1a1ed" width="1" height="1" alt=""><hr><p><a href="https://blog.okmeter.io/pgbouncer-monitoring-improvements-in-recent-versions-5905f5d1a1ed">PgBouncer monitoring improvements in recent  versions</a> was originally published in <a href="https://blog.okmeter.io">okmeter.io blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[USE, RED and real world PgBouncer monitoring]]></title>
            <link>https://blog.okmeter.io/use-red-and-real-world-pgbouncer-monitoring-61b34ebeebb8?source=rss----4e571b327a8c--postgres</link>
            <guid isPermaLink="false">https://medium.com/p/61b34ebeebb8</guid>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[postgres]]></category>
            <category><![CDATA[database-administration]]></category>
            <dc:creator><![CDATA[pavl t]]></dc:creator>
            <pubDate>Tue, 25 Sep 2018 17:57:46 GMT</pubDate>
            <atom:updated>2018-10-15T10:06:47.986Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/314/0*YdkX3mlEVASMS7lN.png" /></figure><p>Brendan Gregg’s USE (Utilization, Saturation, Errors) method for monitoring is quite known. There are even some monitoring dashboard templates shared on the Internet. There’s also Tom Wilkie’s RED (Rate, Errors, Durations) method, which is suggested to be better suited to monitor microservices than USE.</p><p>We, at <a href="https://okmeter.io/?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1">okmeter.io</a>, recently updated our PgBouncer monitoring plugin and while doing that we’ve tried to comb everything and we used USE and RED as frameworks to do so.</p><p>Why we needed both and not just stuck with USE, as it is more commonly known? To answer that we need to understand their applicability first. While they are know, I don’t think they are widely systematically applied in practice of covering IT-systems with monitoring.</p><h3>USE</h3><p>Using <em>Brendan Gregg’s </em><a href="http://www.brendangregg.com/usemethod.html">own words</a>:</p><blockquote><strong><em>For every resource, check utilization, saturation, and errors.</em></strong></blockquote><p>Where <strong>resource</strong> is all and any physical server functional component (CPUs, disks, busses, …). But also some software resources as well, or software imposed limits/resource controls (containers, cgroups, etc).</p><p><strong>Utilization</strong>: the average time that the resource was busy servicing work. So CPU utilization or disk IO utilisation of 90% means that it is idle, not doing work only 10% of the time, and <em>busy </em>90% of time. But also, for such resources as memory, where one can’t apply the idea of “non idle percentage of time”, one could measure the proportion of a resource that is used.</p><p>Anyways, 100% utilization means no more “work” can be accepted, either at all, i.e. when memory is full, it is full, you can’t do anything about it. Or it’s 100% utilized only now, at the moment (as with CPU), and new work could be put into a waiting list, queue or something. And these two scenarios are covered by the corresponding remaining two USE metrics:</p><p><strong>Saturation</strong>: the degree to which the resource has extra work which it can’t service, often queued.</p><p><strong>Errors</strong>: the count of error events, i.e. such as “resource is busy”, “Cannot allocate memory”, “Not enough space”. While those usually do not produce performance impact directly, they either lead to client errors, or, through retries, redundant devices etc, lead to performance impact from client point of view anyway.</p><h3>RED</h3><p>Tom Wilkie, former Google engineer and Grafana’s VP Product now, was frustrated with the USE performance monitoring methodology. For instance, how would you measure i.e. the saturation of memory? Error counts also can be problematic, especially IO errors and memory bandwidth.</p><blockquote>The nice thing about this [USE] kind of pattern is that it turns the guesswork of figuring out why things are slow into a much more of a methodological approach.</blockquote><p>So, as an alternative Wilkie suggests another easy-to-remember acronym, RED:</p><ul><li>(Request)<strong> Rate</strong>: The number of requests per second.</li><li>(Request) <strong>Errors </strong>: The number of failed requests.</li><li>(Request) <strong>Duration </strong>: The amount of time to process a request, a.k.a. service latency.</li></ul><p>Though RED is designed only for request-driven services. As opposed to batch-oriented or streaming services for instance.</p><p>So how is it better?</p><p>RED offers a way of looking at service functioning and performance consistent across different services. Thus reducing cognitive load of on-call engineers, which is crucial in times of outages.</p><h3>PgBouncer</h3><p>While PgBouncer is a connections pooling service after all, and as such it might be monitored with RED, it also has all kinds of internal limits and limited resources, so in this case we concluded we’re going to need to use USE as well :)</p><p>Application of those methods to Pgbouncer should be done with regards to its main purpose and also one should know specifics of its internal structure — all the software kind of resources and limits to cover with USE.</p><blockquote>It’s not enough to monitor PgBouncer as a black-box network service — to know whether a Linux process is alive and a TCP port is open. You actually need to know whether it’s working properly from client point of view — proxying SQL transactions and queries in a timely manner.</blockquote><p>So here’s how it looks like from client’s, say, some web-application, PoV:</p><ol><li>Client connects to PbBouncer.</li><li>Client makes SQL request / query / transaction</li><li>Gets a response.</li><li>Repeat steps 2–3 as many times as needed.</li></ol><p>Here’s client’s connection states diagram:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*wVmktZYFm7vU1FCN.jpeg" /></figure><p>During LOGIN (CL_ stands for client) Pgbouncer might authorize a client based on some local info (such as auth_file, certificates, PAM or hba files), or in a remote way — with auth_query in a database. Thus a client connection while logging in might need and be executing a query. We show that as Executing substate:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*AqBgLx0NrWmW-cuS.png" /></figure><p>But CL_ACTIVEqueries also might be actually executing some queries and so linked to actual database server connections by PgBouncer, or idling, doing nothing. This linking / matching of clients and server connections is the whole raison d’etre of PgBouncer. PgBouncer links those clients with server only for some time, depending on pool_mode — either for a session, transaction or just one request.</p><blockquote>As transaction pooling is the most common, we’ll assume it for the rest of this post</blockquote><p>So client while being in cl_active state is actually might be or might be not linked to a server connection. To account for that we split this state in two: active and active-linked/executing. So here’s a new diagram:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*B03PDy-IwA31zj7H.png" /></figure><p>These server connections, that clients get linked to, are “pooled” — limited in number and reused. Because of that it might occur that while client sends some request (beginning a transaction or performing a query) a corresponding server connection pool is exhausted, i.e. pgbouncer oppened as many connections as were allowed it and all of them are occupied by (linked to) some other clients. PgBouncer in this scenario puts client into a queue, and this client’s connection goes to a CL_WAITING state. This might happen as well while client only logging in, so there’s CL_WAITING_LOGIN for that also:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/0*1UjrQVd9Dq_phwQ1.png" /></figure><p>On the other end there are server connections — from PgBouncer to the actual database. Those have respectful states: SV_LOGIN for when authorizing, SV_ACTIVE for when it’s linked with (and used or not by) client’s connections, or if it’s free — SV_IDLE.</p><h3>USE and PgBouncer</h3><p>Thus we can formulate (a naive version) of a specific PgBouncer pool Utilization:</p><pre>pool_u = #_server_connections_utilized_by_clients / pool_size</pre><p>PgBouncer has an administration interface available through a connection to a special ‘virtual’ database named pgbouncer. There are a number of SHOW commands in it, one of those — SHOW POOLS — will show number of connections in each state for each pool:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YHQXhZ0EndaHJL2S.png" /></figure><p>We see here 4 client’s connections opened, all of them — cl_active. And 5 server connections: 4 — sv_active an one is insv_used.</p><p>One can collect this SHOW POOLS output, using for example some prometheus exporter. And chart them, to get something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/0*sEIIPB9_dHcOk4sw.png" /></figure><p>But how do we get utilization from that? We need to answer these first:</p><ul><li>What’s this pool size?</li><li>How do we count utilized connections? Current number or as a percentage of time? In average or as peak usage?</li></ul><h3>Pool size</h3><p>It’s not a that simple, PgBouncer has <strong>5 different setting</strong> related to limiting connection count!</p><ul><li>You can specify pool_size for each proxied database. This will create a <em>separate pool of that size for every user</em> connecting to a database. It defaults, if not set, to default_pool_size setting, which again by default has a value of 20. So if you have multiple users in your database (and you, probably, should) it might by default create 20 Postgres connections, which seems alright. But each Postgres connection in a postgres process, and if you have many users, thus many pool, you might end up with a pretty high total number of postgres server processes (aka backends).</li></ul><blockquote>Suggestion: If you don’t have a limit on number of different users in your database, your pgbouncer also probably have automatically created database pools. Set a pretty low default_pool_size , just in case.</blockquote><ul><li>max_db_connections is exactly suitable for covering this problem — it limits total number of connections to any database, so badly behaving clients won’t be able to create too many Postgres backends. But max_db_connections is not set by default, so it’s unlimited ¯_(ツ)_/¯</li></ul><blockquote>Suggestion: limit it! As a baseline you can use, for example, Postgres’s max_connections setting, which is 100 by default. But don’t forget to adjust it if you have multiple PgBouncer instances going directly to one DB server.</blockquote><ul><li>reserve_pool_size — is a limit on an additional, reserve pool, which kicks in if a regular pool is exhausted, i.e. there are pool_size open server connections. In that case PgBouncer might open up these additional connections. As I understand it was designed to help serve a burst of clients, but from my understanding it’s not a very useful for that, because in a moment of a peak load, when pool might be exhausted and a DB might be having bad time serving all that load, opening more connections to it won’t do any good. But this reserve pool is handy to watch for pool saturation, as we’ll discuss later.</li><li>max_user_connections — this limits total number of conns <em>to any database </em>from one user. From my point of view, it’s a very strange limit, it makes sense only in case of multiple databases with same users.</li><li>max_client_conn — limits total number of incoming clients connections. It differs from max_user_connections because it includes connections from any user. And if you see such errors in pgbouncer log: no more connections allowed — this meansmax_client_conn is reached. By default it is set to 100, so pgbouncer will just reset any new incoming TCP connection.</li></ul><blockquote>Suggestion: you might want to set max_client_conn &gt;&gt; SUM ( pool_size + reserve pool), like, 10 times, maybe.</blockquote><p>Pgbouncer’s administration interface database besides SHOW POOLS has also SHOW DATABASES command, that shows actually applied limits and all configured and currently present pools:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QlyCtKb_oKMk7V4J.jpeg" /></figure><h3>Server connection monitoring</h3><p>So let’s return to the question — how do we count utilized connections? Just take current number or should we measure it as a percentage of time? Should that be average or peak usage?</p><p>In practice it’s not so easy to properly track pool utilization because pgbouncer reports many indicators only in a form of current values. Therefore allowing only sampling mode of metrics collection with a probability of artifacts. Here’s a real life example, where depending on when pgbouncer metrics collection happened, at the start of a minute or at the end of it, one can see quite different picture of pool utilization:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/0*stjYX0bE4hDSXWfE.png" /></figure><p>There were no changes in load profile during charted period. Check out these Postgres connections chart and Pgbouncer files usage chart for the same period — no changes at all:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/634/0*GkKAi3JhcCFE_DcB.png" /></figure><p>So we, implementing our <a href="https://okmeter.io/i/integrations/pgbouncer-monitoring?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1">pgbouncer monitoring</a>, decided that we are going to provide a combined picture to our clients: our monitoring agent samples SHOW POOLS each seconds and once a minute reports average, as well as peak count of connections in each state:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/634/0*LWpFTT_h8Ghz2krN.png" /></figure><p>So dividing this by pool_size will give you average and peak pool utilization as a percentage, so you can trigger an alert if it goes somewhere close to 100%.</p><p>PgBouncer also provides SHOW STATS command, that provides stats (not a surprize, I know) on requests and traffic for every proxied database:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1xOem_uDO7ef1dTS.png" /></figure><p>Here, for the purpose of measuring pool utilization we are mostly interested in total_query_time — total number of microseconds spent by pgbouncer when <em>actively connected to PostgreSQL, executing queries</em>. Dividing this by respectful pool size (considering pool size to be the number of seconds that all the server connections might spent in total serving queries within one wall clock second) we get another measure/estimate of pool utilization, let’s call it “query time utilization”. This one (unlike an utilization estimate calculated from server connection counts) is not prone to problems with sampling, thanks to total_query_time being a cumulative sum, so it won’t miss a thing.</p><p>Compare this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/629/0*zygCGsbUeedKFFZZ.png" /></figure><p>To the one we saw before:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/611/0*PId4eXZ9XuedcSga.png" /></figure><p>You see later one not really showing all the times when utilization was ~100%, while the first chart with “query time utilization” does.</p><h3>Monitoring of PgBouncer pools saturation</h3><p>Let’s discuss for a moment why we need Saturation metric at all, when we can tell if everything is overloaded looking only if Utilization is high or not?</p><p>The problem is that even with cumulative stats like total_query_time one can’t tell if there were some short periods of high utilization between two moments when we look at the stats. For example, you have some cron jobs configured to simultaneously start and make some queries to a database. If these queries are short enough, i.e. shorter than stats collection period, then measured utilization might still be low, while at these moment of crons start time they might exhaust resource (be that connection pool or something else). In this case, as we discussed, they probably waited in a queue of some sort. But they probably also might’ve affected queries coming from other clients in that way, leading to a local performance degradation from these clients point of view. But looking only on Utilization metric, you won’t be able to diagnose that.</p><p>How can we track that on PgBouncer. A straightforward (and naive) approach is to count clients in SHOW POOLS output in a cl_waiting state, that we discussed. In under normal circumstances you won’t see them, and seeing number of waiting client greater than 0 means pool saturation, as here:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/0*YbnPMuD30fA5_jP4.png" /></figure><p>But as you know, you can only sample SHOW POOLS, and this leads to a possibility of missing such waitings.</p><p>Here’s where we can use PgBouncer built-in saturation detection — as I wrote before, you can configure it to open additional connections in case of when pool fills up, just set non zeroreserve_pool_size. Thereby we can detect pool saturation by comparing a number of open server connections to a respectful pool_size, if it exceeds the limit, pool was saturated at some point:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/0*vOhKXCAP-1Aa-Swb.png" /></figure><p>Here we can clearly see a picture of some sort of cron/periodic jobs, that kick in at the start of each hour and saturate this pool. And even though we do not see at any moment number of active connections exceeding pool_size limit, we know for sure that pgbouncer detected that and opened reserve connections.</p><p>There’s another related setting — reserve_pool_timeout — it defines a timeout so pgbouncer won’t be using that reserve pool. And it defaults to 5 seconds, so if you’re going to user reserve pool for pool saturation detection, you should probably set it quite low.</p><p>While I showed problems due to only sampling metrics collection possible with SHOW POOLS data, it is anyways very useful to monitor clients connection states. Because thanks to distinct pools for different users, one can see users that are in active usage of actual server connections (linked with those). At <a href="https://okmeter.io/?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1">okmeter.io</a> you can chart it as this:</p><pre>sum_by(user, database, <br>   metric(name=&quot;pgbouncer.clients.count&quot;, state=&quot;active-link&quot;)<br>)</pre><p>And that’s an example chart:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/0*gwikEiIn10GyMtQn.png" /></figure><p>We, at <a href="https://okmeter.io/?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1">okmeter.io</a>, provide even more deep details on that usage. You can see distribution of client’s IP addresses. This allows to distinguish not only most active DB users, but most active in that way instances of applications:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/0*gspZxklEaV0_oKj7.png" /></figure><p>In this example, you can see IP addresses of specific kubernetes pods with a web-application instances running in them.</p><h3>Errors</h3><p>For server connection pool exhaustion there is these saturation metrics. But for client connections there are some limits too, as we discussed. Reaching those will produce not queueing and waiting, but blunt denial of service errors. For which you should monitor in pgbouncer logs, where you might find some of those:</p><pre>launch_new_connection: user full <br>launch_new_connection: database full <br>no more connections allowed</pre><h3>RED monitoring and PgBouncer</h3><p>While USE is designed to find performance issues and bottlenecks, RED is more targeted on characterizing workload, i.e. incoming and outgoing traffic. So RED will tell you if everything works as intended (or at least as before), and if something’s not right, USE will help to find a cause.</p><h3>Request Rate</h3><p>This one is, at a first glance, pretty straightforward for SQL proxy / pooler. Clients send requests (transactions and queries) in a form of SQL statements. You will find total_requests in SHOW STATS output. Let’s chart its rate, which in <a href="https://okmeter.io/?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1">okmeter.io</a> will be simply rate(metric(name=&quot;pgbouncer.total_requests&quot;))</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/0*-6xCx7U20xXHjk5s.png" /></figure><p>We clearly can see daily changes and short, anomalous spikes in usage.</p><h3>Request Errors</h3><p>Well, RED and USE have this “E” in common, which is Errors. The way I see it is that USE’s errors are more about the case of when this service/resource we’re monitoring is unable to handle more load. While RED’s errors should be more about errors from clients point of view: statement timeouts “canceling statement due to statement timeout”, rollbacks etc.</p><h3>Request Durations</h3><p>Here again we can useSHOW STATS with its cumulative total_query_time and total_requests. Dividing one to another we’ll get average query time, and if you track that in time, you’ll get average query time chart:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/0*Fno130_bGaRiWdfp.png" /></figure><p>So we clearly see that most of the time it is pretty stable. While there were some anomalous spikes at 19:30 an later. Having that, we could dig deeper using more <a href="https://okmeter.io/i/integrations/pgbouncer-monitoring?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1">detailed PgBouncer metrics</a> or we might need to look deeper into <a href="https://okmeter.io/i/integrations/postgresql-monitoring?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1">Postgres metrics</a>.</p><p>I hope you find this write up useful. I’ve tried to cover all the bases, if you feel that you have something to add — please, tell me, I’ll be glad to discuss.</p><p>I’m preparing next article on PgBouncer and Postgres metrics and monitoring. So if you’re interested — follow us <a href="https://blog.okmeter.io">here</a>, at <a href="http://fb.com/okmeter.io">facebook</a> or <a href="https://twitter.com/okmeterio/">twitter</a> to stay tuned!</p><p><em>Our </em><a href="https://okmeter.io/pg?utm_source=medium_blog&amp;utm_medium=blog_post&amp;utm_campaign=blog&amp;utm_content=pgbouncer-1"><em>monitoring service — okmeter.io</em></a><em> will help you stay on-top of everything happening with you Postgresql, RDS and other infrastructure services.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=61b34ebeebb8" width="1" height="1" alt=""><hr><p><a href="https://blog.okmeter.io/use-red-and-real-world-pgbouncer-monitoring-61b34ebeebb8">USE, RED and real world PgBouncer monitoring</a> was originally published in <a href="https://blog.okmeter.io">okmeter.io blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PostgreSQL: why and how WAL bloats]]></title>
            <link>https://blog.okmeter.io/postgresql-why-and-how-wal-bloats-2252578985c7?source=rss----4e571b327a8c--postgres</link>
            <guid isPermaLink="false">https://medium.com/p/2252578985c7</guid>
            <category><![CDATA[postgres]]></category>
            <category><![CDATA[database-administration]]></category>
            <category><![CDATA[observability]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[postgresql]]></category>
            <dc:creator><![CDATA[pavl t]]></dc:creator>
            <pubDate>Mon, 03 Sep 2018 15:12:58 GMT</pubDate>
            <atom:updated>2018-09-04T07:20:01.652Z</atom:updated>
            <content:encoded><![CDATA[<h4>Today’s post is about real life of PG’s Write-Ahead log.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*GBokz4E7UymMqo3U.png" /></figure><h4>WAL. An almost short introduction</h4><p>Any changes to a Postgresql database first of all are saved in Write-Ahead log, so they will never get lost. Only after that actual changes are made to the data in memory pages (in so called buffer cache) and these pages are marked dirty — meaning they need to be synced to disk later.</p><p>For that there’s a Checkpoint process, ran periodically, that dumps all the ‘dirty’ pages to disk. It also saves the position in WAL (called <strong>REDO point</strong>), up to which all changes are synchronized.</p><p>So in case of a Postgres DB crashes, it will restore its state by sequentially replaying the WAL records from <strong>REDO point</strong>. So all the WAL records before this point are useless for recovery, but still might be needed for replication purposes or for Point In Time Recovery.</p><p>From this description a Super-Engineer might’ve figured out all the ways it will go wrong in real life :-) But in reality usually one will do this in a reactive way: one need to stumble upon a problem first.</p><h4>WAL bloats #1</h4><p>Our monitoring agent for every instance of Postgres will find WAL files and collect their number and total size.</p><p>Here’s a case of some strange x6 growth of WAL size and segment count:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/977/0*oaSR_Vvs_UEdFj23.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/968/0*dk3CM4pUdB56KuL7.png" /></figure><p>What could that be?</p><p>WAL is considered unneeded and to be removed after a Checkpoint is made. This is why we check it first. Postgres has a special system view called pg_stat_bgwriter that has info on checkpoints:</p><ul><li><strong>checkpoints_timed</strong> — is a counter of checkpoints triggered due that the time elapsed from the previous checkpoint is more than pg setting checkpoint_timeout<em>. </em>These are so called <em>scheduled</em> checkpoints.</li><li><strong>checkpoints_req</strong> — is a counter of checkpoints ran due to uncheckpointed WAL size grew to more than max_wal_size setting — <em>requested</em> checkpoints.</li></ul><p>So let’s see:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/0*VdWMPUSXcRf4MfJ9.png" /></figure><p>We see that after 21 Aug checkpoints ceased to run. Though we would love to know the exact reason it’s so, we can’t ¯\_(ツ)_/¯</p><p>As one might remember, Postgres is known to be prone to unexpected behavior due to long lasting transactions. Let’s see:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/0*FtiCsVRQZYn1McGD.png" /></figure><p>Yeah, it definitely might be the case.</p><p>So what can we do about it?</p><ul><li>Kill it. Try pg_cancel_backend</li><li>Try to figure out reasons of it halting.</li><li>Wait, but check and monitor free disk space.</li></ul><p>There’s an additional quirk here: all this leads to WAL bloat on all of replicas too.</p><blockquote>Using this as a chance to remind — <strong>replica is not a backup</strong>.</blockquote><h3>WAL archiving</h3><p>Good backup is the one that will allow you to restore at any point in the past.</p><p>So if “someone” (not you of course) executes this on primary database:</p><pre>DELETE FROM very_important_tbl;</pre><p>You better have a way to restore your DB state right before this transaction. It’s called Point-In-Time-Recovery, or just short — PITR.</p><p>And in Postgres you would do this as a periodical full backup + WAL segments archives. For that there’s a special setting — <a href="https://www.postgresql.org/docs/current/static/continuous-archiving.html">archive_command</a> and ran a special postgres: archiver process. It periodically runs this command of your choose and, if it returns no error, deletes corresponding WAL segment file. But if there’s an error in archiving WAL file, which became more common with wide use of cloud infrastructure (yes, I’m looking at you, AWS S3), it will retry and retry, until success. And this can lead to massive amount of WAL files residing on disk and eating up its space.</p><p>So here’s a chart of a broken for a while WAL archiving:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/0*NjvlDgXFO30XYTkD.png" /></figure><p>You can get these counters from pg_stat_archiver system view.</p><p>Any monitoring systems collects different metrics on server infrastructure. And it’s not only charts, but also you can alert on them and use them to improve your infrastructure to be more resilient.</p><p>The thing is that most of widely used software is not designed with goal of having deep observability capabilities. That’s why it’s so hard to have your monitoring set up in such way, so it will show you everything you need in time.</p><p>The most crucial metrics are hard to collect. It’s usually not presented by some system view, so you can just SELECT supa_useful_stat FROM cool_stat_view. While developing our monitoring agent we dig deep for meaningful and detailed metrics, so you’ll just have them when there’s need.</p><p>That is true for WAL and archiving as well — we not only collect fails from pg_stat_archiver and WAL size on disks, but with okmeter.io you’ll have a metric that shows the amount of WAL residing on disks for the sole purpose of archiving. And here’s how it looks when your archival storage fails:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/966/0*_N3LTCFdouuy5ntZ.png" /></figure><p>Our monitoring system — <a href="https://okmeter.io/?utm_source=medium_blog&amp;utm_medium=blog_post-middle&amp;utm_campaign=blog&amp;utm_content=pg_wal">okmeter.io</a> — will not only automatically collect such metrics but also we’ll alert you whenever archiving fails.</p><h3><strong>Replication</strong></h3><p>Postgres is well known for its Streaming Replication, that works via continuous transfer and replay of WAL segment files to/on a replica server.</p><p>For the case when some replica were unable to get all needed WAL segments instantly, there’s a stash of WAL files on the primary server. Special setting wal_keep_segments controls how many files will be kept by primary. But if a said replica will hang and lag behind for more than that, files will be removed silently. Which will result in that this replica won’t be able to connect to primary and continue it’s streaming replication, drawing it unusable. To turn it back on, one would need to recreate the whole thing from a base backup.</p><p>For further controlling and mitigating that, Postgres, since version 9.4, has a special mechanism of Replication slots.</p><h3>Replication slots</h3><p>When those are used when setting up replication, and a slot has got a connection from a replica at least once (you can think of it as “was initiated”). Then in case of replica falling behind, Primary server will keep all the needed WAL segments until said replica will connect and catch up with current state.</p><p>Or, if replica is forever gone, Primary <strong>will keep these segments forever, </strong>causing all the disk space to be used for that.</p><blockquote>A forgotten (one without monitoring) replication slot cause not only WAL bloat but a possible database downtime.</blockquote><p>Fortunately it’s really easy to monitor it through pg_replication_slots system view.</p><p>We, at okmeter, suggest that you not only monitor for replication stots statuses, but also track WAL size retained for that, as we do, for example, here:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/0*O2g_rvDbCao_m4s0.png" /></figure><p>It not only shows total bloat of WAL, but in detailed view you can see which slot causes that in particular:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/974/0*YHrKNJJ8NjHwmQAp.png" /></figure><p>When we see which is it, we can decide what to do about it. Either trying to fix those replicas, or, if it’s not needed anymore, delete the slot.</p><p>These are most common causes of WAL bloat, though I’m sure there are some others. It’s crucial to monitor it, for database’s uninterruptible service.</p><p><em>Our </em><a href="https://okmeter.io/?utm_source=medium_blog&amp;utm_medium=blog_post-footer&amp;utm_campaign=blog&amp;utm_content=pg_wal"><em>monitoring service — okmeter.io</em></a><em> will help you stay on-top of everything happening with you Postgresql, RDS and other infrastructure services.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2252578985c7" width="1" height="1" alt=""><hr><p><a href="https://blog.okmeter.io/postgresql-why-and-how-wal-bloats-2252578985c7">PostgreSQL: why and how WAL bloats</a> was originally published in <a href="https://blog.okmeter.io">okmeter.io blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Real world SSD wearout]]></title>
            <link>https://blog.okmeter.io/real-world-ssd-wearout-a3396a35c663?source=rss----4e571b327a8c--postgres</link>
            <guid isPermaLink="false">https://medium.com/p/a3396a35c663</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[database-administration]]></category>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[postgres]]></category>
            <category><![CDATA[redis]]></category>
            <dc:creator><![CDATA[pavl t]]></dc:creator>
            <pubDate>Mon, 27 Aug 2018 15:16:46 GMT</pubDate>
            <atom:updated>2018-08-27T19:41:22.502Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/575/0*zFgiHN4aXwDc8SR7.png" /></figure><p>A year ago we’ve added SMART metrics collection to our monitoring agent that collects disk drive attributes on clients servers.</p><p>So here a couple of interesting cases from the real world.</p><p>Because we needed it to work without installing any additional software, like smartmontools, we implemented collection not of all the attributes, but only basic and not vendor-specific ones — to be able to provide consistent experience. And also that way we skipped burdensome task of maintaining a knowledge base of specific stuff — and I like that a lot :)</p><p>This time we’ll discuss only SMART attribute named “media wearout indicator”. Normalized, it shows a percentage of “write resource” left in the device. Under the hood the device keeps track of the number of cycles the NAND media has undergone, and the percentage is calculated against the maximum number of cycles for that device. The normalized value declines linearly from 100 to 1 as the average erase cycle count increases from 0.</p><h3>Are there any actually dead SSDs?</h3><p>Though SSDs are pretty common nowadays, just couple of years earlier you could hear a lot of fear talk about SSD wearout. So we wanted to see if some of it were true. So we searched for the maximum wearout across all the devices of all of our clients.</p><blockquote>It was just 1%</blockquote><p>Reading the docs says it just won’t go below 1%. So it is<strong> worn</strong> <strong>out</strong>.</p><p>We notified this client. Turns out it was a dedicated server in Hetzner. Their support replaced the device:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/969/1*SdQ9aCAwRGX458JSUh0hEA.png" /></figure><h3>Do SSDs die fast?</h3><p>As we introduced SMART monitoring for some of the clients already some time ago, we have accumulated history. And now we can see it on a timeline.</p><p>A server with highest wearout rate we have across our clients servers unfortunately was added to okmeter.io monitoring only two month ago:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/965/0*Y7q1_ElmAIvSxYah.png" /></figure><p>This chart indicates that during these two month only, it burned through 8% of “write resource”.</p><blockquote>So 100% of this SSD lifetime under that load will end in 100/(8/2) = <strong>2 years</strong>.</blockquote><p>Is that a lot or too little? I don’t know. But let’s check what kind of load it’s serving?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/964/0*Lz1UAiMmmGoEXWMO.png" /></figure><p>As you can see, it’s ceph doing all the disk writes, but it’s not doing these writes for itself — it’s a storage system for some application. This particular environment was running under Kubernetes, so let’s sneak a peek what’s running inside:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/0*bkDlCKW1gLB4WsNS.png" /></figure><p>It’s Redis! Though you might’ve noticed divergence in values with the previous chart — values here are 2 times lower (it’s probably due to ceph’s data replication), load profile is the same, so we conclude it’s redis after all.</p><p>Let’s see what redis is doing:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/0*EfSMZwmgn8X2RUoI.png" /></figure><p>So it’s on average less than 100 write commands per second. As you might know, there’s two ways Redis makes actual writes to disk:</p><ul><li><strong>RDB</strong> — which periodically snapshots all the dataset to the disk, and</li><li><strong>AOF</strong> — which writes a log of all the changes.</li></ul><p>It’s obvious that’s here we saw RDB with 1 minute dumps:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/976/0*__u2ctpL9Bt62f7G.png" /></figure><h3>Case: SSD + RAID</h3><p>We see that there are three common patterns of server storage system setup with SSDs:</p><ul><li>Two SSDs in a RAID-1 that holds everything there is.</li><li>Some HDDs + SSDs in a RAID-10 — we see that setup a lot on traditional RDBMS servers: OS, WAL and some “cold” data on HDD, while SSD array hold hotest data.</li><li>Just a bunch of SSDs (JBOD) for some NoSQL like Apache Cassandra.</li></ul><p>So in the first case with RAID-1 writes go to both disks symmetrically, and wearout happens with the same rate:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/0*afOWCXamhJrXccpL.png" /></figure><p>Looking for some anomalies we found one server where it was completely different:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/975/0*fzHUjZnEBD_mwdUY.png" /></figure><p>Checking mount options, to understand this, didn’t produce much insight — all the partitions were RAID-1 mdraids:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ueVc9ZCCoIBvAQIF.png" /></figure><p>But looking for per device IO metrics we see, again, there’s difference between two disks. And /dev/sda gets more bytes written:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/977/0*bPqGKHbnWbnLl9uv.png" /></figure><p>Turns out there’s swap configured on one of the /dev/sda partitions. And pretty decent swap IO on this server:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/968/0*JP9Is8jbLCmtmmhP.png" /></figure><h3>SSD wearout and PostgreSQL</h3><p>This journey began with me looking to check SSD wearout with different Postgres write load profiles. But not much luck — all of our client’s Postgres databases, with at least somewhat high write load, are configured pretty carefully — writes go mostly to HDDs.</p><p>But I found one pretty interesting case nevertheless:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/0*YsUWDGfQIBlam0Zl.png" /></figure><p>We see these two SSDs in a RAID-1 wore out 4% during 3 months. But checking if it’s high amount of WAL writes turned out to be wrong — it’s only less than 100Kb/s:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/973/0*ltKc_FaKVtrbfL6o.png" /></figure><p>I figured that probably Postgres generates writes in some other way, and it is indeed. Constant temp files writes all the time:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/0*nhOuHI8tLKGA-Ib8.png" /></figure><p>Thanks to Postgres elaborate internal statistics and okmeter.io’s rich support for it, we easily spotted the root cause of that:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*arJ0IoqyjvFMSfEM9te_lg.png" /></figure><p>It was a SELECT query generating all that load and wearout! SELECT’s in Postgres can sometime generate even non-temp file, but real writes. <a href="https://blog.okmeter.io/postgresql-exploring-how-select-queries-can-produce-disk-writes-f36c8bee6b6f">Read about it here</a>.</p><h3>Summary</h3><ul><li>Redis+RDB generates a ton of disk writes and it depends not on the amount of changes in Redis db, but on DB size and dump frequency. RDB seems to produce the maximum Write Amplification from all known to me storages.</li><li>Actively used SWAP on SSD is probably a bad idea. Unless you want to add some jitter to RAID-1 SSDs wearout.</li><li>In DBMSes like Postgresql it might be not only WAL and datafiles that dominate disk writes. Bad database design or access patterns might produce a lot of temp files writes. <a href="https://blog.okmeter.io/postgresql-query-monitoring-375ee8048c10">Read how to monitor Postgres queries</a>.</li></ul><h3>That’s all for today. Be aware of your SSDs wearout!</h3><p>Follow us on <a href="https://blog.okmeter.io/">our blog</a> or <a href="https://twitter.com/okmeterio/">twitter</a> to read more cases.</p><p><em>We at </em><a href="https://okmeter.io/?utm_source=medium_blog&amp;utm_medium=blog-post&amp;utm_campaign=blog&amp;utm_content=ssd_smart"><em>okmeter.io</em></a><em> believe that for engineer to dig up a root cause of a problem, he needs decent tooling and a lot of metrics on every layer and part of infrastructure. That where we’re trying to help.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3396a35c663" width="1" height="1" alt=""><hr><p><a href="https://blog.okmeter.io/real-world-ssd-wearout-a3396a35c663">Real world SSD wearout</a> was originally published in <a href="https://blog.okmeter.io">okmeter.io blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PostgreSQL: Exploring how SELECT Queries can produce disk writes]]></title>
            <link>https://blog.okmeter.io/postgresql-exploring-how-select-queries-can-produce-disk-writes-f36c8bee6b6f?source=rss----4e571b327a8c--postgres</link>
            <guid isPermaLink="false">https://medium.com/p/f36c8bee6b6f</guid>
            <category><![CDATA[database-administration]]></category>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[database-monitoring]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[postgres]]></category>
            <dc:creator><![CDATA[Nikolay Sivko]]></dc:creator>
            <pubDate>Sun, 04 Mar 2018 19:57:19 GMT</pubDate>
            <atom:updated>2018-03-26T12:39:29.801Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/391/0*8HB3gkIJSBLDGHdZ." /></figure><p>We already wrote about<em> </em><a href="https://blog.okmeter.io/postgresql-query-monitoring-375ee8048c10"><em>monitoring posgresql queries</em></a>, at the time we thought that we completely understood how PostgreSQL works with various server resources.</p><p>Working regularly with the statistics of PostgreSQL queries, we noticed some anomalies and decided to dig a bit deeper for better understanding. Through this process, we found that while the behavior of postreSQL is kind of strange at first glance (or at least very peculiar), the clarity of its source code is quite admirable.</p><h3><strong>A SELECT query can “dirty” some pages</strong></h3><p>It turns out that in PostgreSQL, SELECTs (which usually believed to be read-only)may cause modifications to some database records, which postgres will then write to disk.</p><blockquote>Wait, what?</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*mQYGrlnPT1wl88F5." /></figure><p>PostgreSQL uses MVCC (MultiVersion Concurrency Control) technology for transactional integrity. All changes to the database records only happen in transactions. Each transaction is assigned an identification number. Postgresql refers to this transaction ID as <strong><em>txid </em>(int32)</strong>. Table data — records — is represented in <strong>tuples</strong>. A tuple contains data from one particular row, as well as metadata associated with this row:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/914/0*YZtBy67fvFm6vpKh." /></figure><p><em>Picture: </em><a href="http://www.interdb.jp"><em>www.interdb.jp</em></a></p><p>Postgresql refers to the id of a transaction that created this particular tuple<strong> </strong>as the <strong><em>xmin</em> </strong>(or<em> t_xmin</em>) of a tuple. And the id of a transaction that marked this tuple as deleted (if any) is referred to as the <strong><em>xmax</em> </strong>(or <em>t_xmin</em>).</p><p>Here’s how they are calculated and changed:</p><ul><li>An <strong>INSERT</strong> to a table creates a new tuple with <strong><em>xmin = txid</em></strong> of that <strong>INSERT</strong> transaction.</li><li><strong>DELETE</strong> marks the tuples as deleted, setting its <strong><em>xmax</em> <em>= txid</em></strong> of that <strong>DELETE</strong></li><li><strong>UPDATE</strong> works as a combination of a <strong>DELETE</strong> and an <strong>INSERT</strong>.</li></ul><p>The SELECT statement queries the database and retrieves selected data from a specified table, while also performing a <strong>visibility check</strong>, which goes as follow:</p><p>At a high level, a transaction with the <strong><em>txid1</em></strong> identifier will ”see” a specific tuple, only if the following conditions are met:</p><p><strong><em>xmin &lt;= txid1 &lt;= xmax</em></strong></p><p>Although tuple changes occur immediately, transactions may take a long time to complete. This is why during the visibility check it is necessary to also check whether transactions with the identifiers <strong><em>xmin</em></strong> and <strong><em>xmax</em></strong> have been completed or not, and what was the status of each completed transaction.</p><p>Because, for example, while for a particular tuple <strong><em>xmin</em></strong> might be <strong><em>&lt; txid1</em></strong>, the transaction with <strong><em>txid = xmin</em>,</strong> that created this tuple, might still be in-flight, and still might fail later, leading to deletion of this tuple. So this tuple should nevertheless be “invisible” for <strong><em>txid1</em></strong>.</p><p>PostgreSQL stores information about the current state of each transaction in a commit log (<strong>CLOG</strong>). Checking the states of a large number of transactions in CLOG is resource-intensive so Postgres therefore caches the information about transaction states directly in the header of the tuple. For example, if during a SELECT it is recognised that an <strong><em>xmin</em></strong> transaction is completed, Postgresql saves this knowledge into so called <strong>hint bits</strong> of the tuple<strong>. </strong>Both xmin and xmax statuses are recorded in these hint bits, which are placed in an <strong>infomask</strong> part of the tuple header.</p><p>We previously described the process of changing tuples, however, to complete our investigation , we need to clarify the meaning of “<strong>dirty pages</strong>” in Postgresql. PostgreSQL works with the information stored on the disk, as well as in memory, and organizes data by blocks, or “<strong>pages</strong>”. This is done to boost efficiency. Each page contains a number of tuples and their associated metadata. If a single tuple is modified, an entire page is marked as “<strong>dirty</strong>”. This implies that there is a difference between this data in memory and the corresponding data saved to disk. This modified page must therefore be synchronized with that on the disk. Additionally, these modifications are recorded into the <strong>WAL </strong>(write-ahead log). This is done for the purpose of restoring data integrity (in the event that the database process terminates abnormally).</p><h3><strong>SELECT can cause synchronous writes on the disk:</strong></h3><p>As you might know, PostgreSQL works with data using a buffer cache. If needed data is not in the buffer cache, PostgreSQL reads it from the disk and puts into the buffer cache . If there is not enough space in this cache, then the least requested page is pushed out, evicted. If this page turns out to be in a “dirty” condition at the time of an eviction, then it must be written to disk in this exact moment.</p><h3>Conclusion:</h3><p>Most cases of “strange” PostgreSQL behaviour are caused by built in functionality, which is intended to optimize the efficiency and performance of a database.</p><p><em>Subscribe to us here, </em><a href="http://twitter.com/okmeterio/"><em>on Twitter</em></a><em> or on </em><a href="http://fb.com/okmeter.io"><em>our Facebook page</em></a><em> to receive okmeter updates, or </em><a href="https://okmeter.io/user/signup"><em>sign up with okmeter.io</em></a><em> directly.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f36c8bee6b6f" width="1" height="1" alt=""><hr><p><a href="https://blog.okmeter.io/postgresql-exploring-how-select-queries-can-produce-disk-writes-f36c8bee6b6f">PostgreSQL: Exploring how SELECT Queries can produce disk writes</a> was originally published in <a href="https://blog.okmeter.io">okmeter.io blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Postgresql query monitoring]]></title>
            <link>https://blog.okmeter.io/postgresql-query-monitoring-375ee8048c10?source=rss----4e571b327a8c--postgres</link>
            <guid isPermaLink="false">https://medium.com/p/375ee8048c10</guid>
            <category><![CDATA[postgres]]></category>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[database-monitoring]]></category>
            <category><![CDATA[database-administration]]></category>
            <dc:creator><![CDATA[pavl t]]></dc:creator>
            <pubDate>Tue, 05 Dec 2017 13:30:36 GMT</pubDate>
            <atom:updated>2018-08-22T13:50:05.892Z</atom:updated>
            <cc:license>https://creativecommons.org/licenses/by-nc/4.0/</cc:license>
            <content:encoded><![CDATA[<p>Since 2008, ‘pgsql-hackers’ have been discussing an extension for collecting query statistics reports. This extension called ‘pg_stat_statements’, which is now part of PostgreSQL from 8.4 and above, allows for collecting statistical information about queries executed by a server.</p><p>The extension is typically used by database administrators as a data source for various reports. Though this data, in fact, represents only cumulative performance indicators since the last reset of counters, such information can be very useful for monitoring query execution time, locating performance issues, and in-depth analysis of what’s going on with a database server.</p><h3>pg_stat_statements</h3><p>So, let’s take a closer look at pg_stat_statements view (this one is from 9.4):</p><pre>postgres=# \d pg_stat_statements;<br>          View &quot;public.pg_stat_statements&quot;<br>       Column        |       Type       | Modifiers<br>---------------------+------------------+-----------<br> userid              | oid              |<br> dbid                | oid              |<br> queryid             | bigint           |<br> query               | text             |<br> calls               | bigint           |<br> total_time          | double precision |<br> rows                | bigint           |<br> shared_blks_hit     | bigint           |<br> shared_blks_read    | bigint           |<br> shared_blks_dirtied | bigint           |<br> shared_blks_written | bigint           |<br> local_blks_hit      | bigint           |<br> local_blks_read     | bigint           |<br> local_blks_dirtied  | bigint           |<br> local_blks_written  | bigint           |<br> temp_blks_read      | bigint           |<br> temp_blks_written   | bigint           |<br> blk_read_time       | double precision |<br> blk_write_time      | double precision |</pre><p>As you can see, all the queries are grouped, i.e. the statistics is collected not for individual queries, but for groups of queries which PostgreSQL considered similar (I will explain it in more detail below). Values of all counters are incrementing since the start of the Postgresql process or since last call of ‘pg_stat_statements_reset’.</p><ul><li><strong>query</strong> — query text</li><li><strong>calls</strong> — number of query calls</li><li><strong>total_time</strong> — total execution time of all query calls, in milliseconds</li><li><strong>rows</strong> — number of rows returned (‘select’) or modified (‘update’) during the query execution</li><li><strong>shared_blks_hit</strong> — number of shared memory blocks returned from the cache</li><li><strong>shared_blks_read</strong> — number of shared memory blocks returned NOT from the cache. It’s not quite clear in the documentation whether it’s a total number of returned memory blocks or only the number of memory blocks not found in the cache, so let’s check out the source code:</li></ul><pre>/*<br>* lookup the buffer. IO_IN_PROGRESS is set if the requested block is<br>* not currently in memory.<br>*/<br>bufHdr = BufferAlloc(smgr, relpersistence, forkNum, blockNum,<br>                     strategy, &amp;found);<br>if (found)<br>    pgBufferUsage.shared_blks_hit++;<br>else<br>    pgBufferUsage.shared_blks_read++;</pre><ul><li><strong>shared_blks_dirtied</strong> — number of shared memory blocks marked as “dirty” during the query execution (i.e. a query modified as least one tuple in a block, and thus the block must be written to a drive using ‘checkpointer’ or ‘bgwriter’)</li><li><strong>shared_blks_written</strong> — number of shared memory blocks written synchronously to a drive during the query execution. PostgreSQL worker attempts to synchronously write a block if it got it “dirty”.</li><li><strong>local_blks</strong> — similar counters for blocks which are considered as local blocks by the backend and thus are used for temporary tables</li><li><strong>temp_blks_read</strong> — number of blocks of temporary files read from a drive. Temporary files are used when there’s not enough memory to execute a query (the memory limit can be set in the ‘work_mem’ parameter)</li><li><strong>temp_blks_written</strong> — number of blocks of temporary files written to a drive</li><li><strong>blk_read_time</strong> — total waiting time for reading blocks, in milliseconds</li><li><strong>blk_write_time</strong> — total waiting time for writing blocks to a drive, in milliseconds (only synchronous write operations by a worker are considered, the execution time of ‘checkpointer’/’bgwriter’ is not included)</li></ul><p>Note that<strong> blk_read_time</strong> and <strong>blk_write_time</strong> are collected only when additional ‘track_io_timing’ setting is enabled.</p><p>The thing is that ‘pg_stat_statements’ considers only fully completed queries, i.e. if your query has been performing a resource-intensive task for about an hour, you will be able to view such a query only in ‘pg_stat_activity’.</p><h3>How the queries are grouped</h3><p>Previously I’ve been thinking that queries are grouped in the same order as they are executed. However, I also noticed that queries with different number of IN arguments usually show up in different groups, though such queries were expected to have the same execution plan.</p><p>After looking it up in the code, I understood that the queries are grouped by hash value of their “query jumble” (consisting of only significant parts of the query text obtained after parsing) — in version 9.4 and above, you can view this hash in the ‘queryid’ column.</p><p>In practice, we need to additionally normalize and group queries already in the agent, e.g. merge variable number of IN arguments into a single placeholder ‘?’ or replace inline arguments with placeholders — this is especially difficult when query’s content is not complete.</p><p>In versions older than 9.4, each query was cut down to ‘track_activity_query_size’, but in version 9.4 and above, this limitation is removed since query‘s content is now stored outside of the shared memory. However, we still cut large queries down to 8 KB to not to affect the performance of PostgreSQL significantly.</p><p>This is why we cannot parse a query with an SQL parser for additional normalization — any SQL parser will report an error on such cutted query text/ And thus we need to write several heuristics and regular expressions for better query cleanup. Certainly, adding new heuristics is far from perfect, but this is the only working solution we came up with.</p><p>Yet another issue is that PostgreSQL uses the ‘query’ field to store the first received query text in a group without normalization and any formatting, and thus resetting counters may lead to overwriting this query text with another one from the same group but looking completely different. In addition, many developers write comments directly in a query (e.g. to indicate the query’s ID or a function which calls the query), and these comments are also written to the ‘query’ field.</p><p>To avoid creating new metrics for the same queries every time, we remove all comments etc.</p><h3>The question to ask</h3><p>Together with our friends from PostgreSQL Consulting, we have deeply analyzed PostgreSQL’s internals and picked up the most useful metrics to locate database issues.</p><p>The goal of our monitoring is to answer to the following questions:</p><ul><li>How does the database operate at this moment compared to previous periods?</li><li>What queries are the most resource-intensive for the server (by CPU, drive, etc.)?</li><li>How many queries (by type) are received?</li><li>How quickly are various queries executed?</li></ul><h3>Collecting the metrics</h3><p>In fact, it’s not reasonable to monitor counters for all queries, so we have picked up TOP-50 queries for our analysis. However, we cannot simply apply ‘top’ to ‘total_time’, because the ‘total_time’ values for new queries will for a long time be much lower than those for older queries.</p><p>We decided to apply ‘top’ to the derivative of ‘total_time’ (rate). To do this, our agent fully reads the ‘pg_stat_statements’ values and saves the previous values of the counters. Then for each counter of each query, we attempt to additionally group similar queries (which Postgres considers different) and sum up their statistics. Finally, we apply ‘top’ to them and create dedicated metrics, while all remaining queries are summed up and written to the ”~other” query.</p><p>As a result, we will obtain 11 metrics for each query from ‘top’:</p><ul><li>postgresql.query.time.cpu (we just subtracted the total drive awaiting time from ‘total_time’ for convenience)</li><li>postgresql.query.time.disk_read</li><li>postgresql.query.time.disk_write</li><li>postgresql.query.calls</li><li>postgresql.query.rows</li><li>postgresql.query.blocks.hit</li><li>postgresql.query.blocks.read</li><li>postgresql.query.blocks.written</li><li>postgresql.query.blocks.dirtied</li><li>postgresql.query.temp_blocks.read</li><li>postgresql.query.temp_blocks.written</li></ul><p>Each of them will have a set of attributes (labels):</p><pre>{“database”: “&lt;db&gt;”, “user”: “&lt;user&gt;”, “query”: “&lt;query&gt;”}</pre><blockquote>Detailed description — <a href="https://okmeter.io/i/integrations/postgresql-monitoring?lang=en&amp;utm_content=twitch_pg&amp;utm_medium=tldr">Postgres Query Monitoring metrics.</a></blockquote><h3>Interpreting the metrics</h3><p>Users are often confused with the ‘postgresql.query.time.*’ metrics and their physical interpretation. Though it’s not always clear what the total response time really means, such metrics may be a good illustration of how various processes interact with one another.</p><p>Assuming that blockings are not taken into account, we can consider that PostgreSQL utilizes certain resources (CPU or disks) during query execution, and thus we can express this usage in resource seconds per second or in percent of CPU core utilization by a query vs. total CPU utilization.</p><h3>Let’s see what we’ve got</h3><p>First, we need to check whether our metrics are usable. For example, let’s try to find out why our database server performs more disk write operations than usual.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9X4GPhGmkip-Z05g." /></figure><p>Let’s check whether PostgreSQL wrote anything to the disks at that moment:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ZJ09Gr5SKtrKfwhF." /></figure><p>Then we can figure out which queries have ‘dirtied’ the pages:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aBDEOQp8Ez6m2MR-NXbJ3Q.png" /></figure><p>As we can see, though the query chart is not exactly the same as the buffer write chart, there is certain correlation between the two. The difference is because the block writing process is performed in background, thus changing the drive utilization profile.</p><p>Now let’s see the charts for read operations:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-gsfCrzV_AlAQ6r7." /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2bG4gY8zG8ahR79a." /></figure><p>And again, there is certain correlation, but not an exact match — this is because PostgreSQL reads blocks from a drive not directly, but from file system’s cache, and thus the actual drive workload is partly hidden.</p><p>The CPU utilization rate can also be attributed to specific queries, but the analysis is not quite accurate due to possible locks and other delays:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*M1kSeRUWAyVM81ZV." /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fxfrNW2zJKVTSQcG." /></figure><p><strong>Summary</strong></p><ul><li>We believe that ‘pg_stat_statements’ is a really great extension which provides in-depth statistics without heavy server workload.</li><li>However, users should keep in mind certain assumptions and inaccuracies in order to interpret these metrics.</li></ul><blockquote><a href="https://okmeter.io/pg?lang=en&amp;utm_source=blog_okmeter&amp;utm_content=pg_q_mon">Okmeter.io</a> provides a complete and ready-to-use Postgres monitoring. Though we have an online live demo with <a href="https://okmeter.io/example/autodash/postgresql/source_hostname=db-postgresql1/instance=127.0.0.1:5432?lang=en&amp;utm_source=blog_okmeter&amp;utm_content=pg_q_mon">query charts</a> and <a href="https://okmeter.io/example/dashboards/postgresql-queries?lang=en&amp;utm_source=blog_okmeter&amp;utm_content=pg_q_mon">statistics</a>, it is still a demo with a synthetic workload, and it doesn’t quite resemble real life.</blockquote><p>It’s always better to try it out on your project to see what’s happening in your actual production environment<em>.</em></p><blockquote>We offer <a href="https://okmeter.io/pg?lang=en&amp;utm_source=blog_okmeter&amp;utm_content=pg_q_mon"><em>two-week </em></a><a href="https://okmeter.io/pg?lang=en&amp;utm_source=blog_okmeter&amp;utm_content=pg_q_mon"><em>free</em></a><em> </em><a href="https://okmeter.io/pg?lang=en&amp;utm_source=blog_okmeter&amp;utm_content=pg_q_mon"><em>trial</em></a>, that you can use just for that!</blockquote><p>I encourage you to try it, at the very least, you’ll know that <strong>everything is OK</strong> with your database and services.</p><p>If you want to know more about Postgres operations, you’ll find this article on “<a href="https://blog.okmeter.io/postgresql-exploring-how-select-queries-can-produce-disk-writes-f36c8bee6b6f">When SELECT can cause a data change and a disk write</a>” truly interesting!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=375ee8048c10" width="1" height="1" alt=""><hr><p><a href="https://blog.okmeter.io/postgresql-query-monitoring-375ee8048c10">Postgresql query monitoring</a> was originally published in <a href="https://blog.okmeter.io">okmeter.io blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>