{"id":8825,"date":"2022-04-03T14:17:58","date_gmt":"2022-04-03T19:17:58","guid":{"rendered":"https:\/\/www.rushworth.us\/lisa\/?p=8825"},"modified":"2022-04-20T00:08:27","modified_gmt":"2022-04-20T05:08:27","slug":"postgresql-querying-hot-standby-server","status":"publish","type":"post","link":"https:\/\/www.rushworth.us\/lisa\/?p=8825","title":{"rendered":"Postgresql &#8211; Querying Hot Standby Server"},"content":{"rendered":"<p>We hit our maximum connection limit on some PostgreSQL servers &#8212; which made me wonder why the hot standby servers weren&#8217;t being used &#8230; well, at all. They&#8217;re equally big, expensive servers with <em>loads<\/em> of disk space. But they&#8217;re just sitting there &#8220;in case&#8221;.<\/p>\n<p>So we directed some traffic over to the standby server. I&#8217;m also going to tweak a few settings related to user limits &#8212; increase the max connections since these are dedicated hosts and have plenty of available I\/O, memory, CPU, etc resources; increase the number of reserved connections since replication filled up all of the reserved slots; implement a per-user connection limit on one account that runs a <em>lot<\/em> of threads &#8212; but directing some people who were only trying to look at data over to the standby server seemed like a quick fix.<\/p>\n<p>Now, we discovered something interesting about how queries against the standby interact with replication. It makes a lot of sense when you start thinking about it &#8212; if you query against the writable replica, there&#8217;s some blocking that goes on. The system isn&#8217;t going to vacuum data that you&#8217;re currently trying to use. The standby, however, doesn&#8217;t have any way to clue the writable replica in to the fact you <em>are<\/em> trying to use some data. So the writable replica gets a delete, does its thing to hide those rows from future queries, and eventually auto-vacuum comes through and cleans up those rows. All of this gets pushed over to the standby &#8230; and there goes the data you were trying to read.<\/p>\n<p>Odds of this happening on a query that takes eight seconds? Incredibly low! Odds increase, however, the longer a query runs. So some of our super massive reports started seeing an error indicating that their query was cancelled &#8220;due to a conflict with recovery&#8221;<\/p>\n<p><a href=\"https:\/\/www.rushworth.us\/lisa\/?attachment_id=8826\" rel=\"attachment wp-att-8826\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-8826\" src=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2022\/04\/MicrosoftTeams-image.png\" alt=\"\" width=\"349\" height=\"46\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2022\/04\/MicrosoftTeams-image.png 349w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2022\/04\/MicrosoftTeams-image-300x40.png 300w\" sizes=\"auto, (max-width: 349px) 100vw, 349px\" \/><\/a><\/p>\n<p>There are <a href=\"https:\/\/www.postgresql.org\/docs\/current\/hot-standby.html#HOT-STANDBY-CONFLICT\" target=\"_blank\" rel=\"noopener\">two solutions in the PostgreSQL documentation<\/a> &#8212; one is to increase the <tt>max_standby_streaming_delay<\/tt> value (there&#8217;s also an archive delay, but we aren&#8217;t particularly concerned about clients querying the server during recovery operations) the other is to avoid vacuuming data too quickly &#8212; either by setting <tt>hot_standby_feedback<\/tt> on the standby or increasing <tt>vacuum_defer_cleanup_age<\/tt> on the primary.<\/p>\n<p>There&#8217;s a third option too &#8212; don&#8217;t use the standby for long-running queries. That&#8217;s easily done in our case &#8230; and doesn&#8217;t require tweaking any PostgreSQL settings. Ad hoc reporting and direct user access really <em>shouldn&#8217;t<\/em> be implementing such substantial queries (it&#8217;s always good to have a SQL expert plan out and optimize complex queries if that&#8217;s an option).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We hit our maximum connection limit on some PostgreSQL servers &#8212; which made me wonder why the hot standby servers weren&#8217;t being used &#8230; well, at all. They&#8217;re equally big, expensive servers with loads of disk space. But they&#8217;re just sitting there &#8220;in case&#8221;. So we directed some traffic over to the standby server. I&#8217;m &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1522],"tags":[1577,1349,1580,1579,1578],"class_list":["post-8825","post","type-post","status-publish","format-standard","hentry","category-postgresql","tag-load-balancing","tag-postgresql","tag-postgresql-replication","tag-replaying-wal","tag-wal"],"_links":{"self":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/8825","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8825"}],"version-history":[{"count":1,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/8825\/revisions"}],"predecessor-version":[{"id":8827,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/8825\/revisions\/8827"}],"wp:attachment":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8825"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8825"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8825"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}