Unexpected data when subscribing to logical replication slot
We have a .NET application which subscribes to a logical replication slot using wal2json. The purpose of the application is to publish events to AWS SQS. We are required to first "enrich" these events by querying the database. We have found that these queries will often find old data (i.e. the data that existed prior to the update) which is unexpected. For example, when I use a psql terminal to update a user's last name from "Jones" to "Smith" then I would expect the enrichment query to find "Smith" but it will sometimes still find "Jones". It finds the old data perhaps 1 in 50 times. To reproduce this I use a psql terminal to execute an update statement which changes a user's last name with \watch 1.5 and monitor our application logs for cases where the wal2json output and the enrichment query output have different last names. We have compared transaction ids by adding include-xids to pg_recvlogical and adding txid_current() to to the enrich query and the txid_current() is always the xid + 1. We have found two things that appear to resolve the problem - - Using a more powerful EC2 instance. We can reproduce the issue with a r7a.medium instance but not with a r7a.large EC2 instance. - Changing the Postgres synchronous_commit parameter from "on" to "off". We cannot reproduce the issue with synchronous_commit set to "off". We need help to understand this unexpected behaviour. We are using Postgres 14.10. Thanks, Daniel McKenzie
Re: Unexpected data when subscribing to logical replication slot
It's running both (in docker containers) and also quite a few more docker containers running various .NET applications. Daniel McKenzie Software Developer Office: +1 403.910.5927 x 251 Mobile: +44 7712 159045 Website: www.curvedental.com *Curve Dental Confidentiality Notice* This message is intended exclusively for the individual or entity to which it is addressed. This communication may contain information that is proprietary, privileged, confidential, or otherwise legally exempt from disclosure. If you are not the named addressee, you are not authorized to read, print, retain, copy, or disseminate this message or any part of it. If you have received this message in error, please notify the sender immediately by replying to this e-mail and delete all copies of this message. On Wed, May 8, 2024 at 4:17 PM Adrian Klaver wrote: > > > > > We have found two things that appear to resolve the problem - > > > > * Using a more powerful EC2 instance. We can reproduce the issue with > > a r7a.medium instance but not with a r7a.large EC2 instance. > > * Changing the Postgres synchronous_commit parameter from "on" to > > "off". We cannot reproduce the issue with synchronous_commit set to > > "off". > > What is running on the EC2 instance?: > > 1) The Postgres server. > > 2) The replication receiver. > > 3) Both. > > > > > > We need help to understand this unexpected behaviour. > > > > We are using Postgres 14.10. > > > > Thanks, > > Daniel McKenzie > > -- > Adrian Klaver > adrian.kla...@aklaver.com > >
Re: Unexpected data when subscribing to logical replication slot
> > Asynchronous commit introduces the risk of data loss. There is a short > time window between the report of transaction completion to the client > and the time that the transaction is truly committed. The documentation speaks about synchronous_commit changing how transactions change behaviour for the client. So in this case, my psql terminal is the client, and I would expect a faster commit (from its perspective) and then a period of risk (as a process usually done as part of the commit is now being done in the background) but it's not clear how that affects a replication slot subscriber. What we're struggling to understand is: why are we seeing any updates in the replication slot before they have been "truly committed"? There appears to be a state of limbo between updating data and that data being available to query (and our subscriber is picking up changes in this period of time) but I can't pin down any documentation which describes it. We've had this running in live now for years without a hiccup so we are surprised to learn that we have this massive race condition and it just so happens that the hardware is fast enough to process the transaction before the .NET application can react to replication slot changes. Daniel McKenzie Software Developer Office: +1 403.910.5927 x 251 Mobile: +44 7712 159045 Website: www.curvedental.com *Curve Dental Confidentiality Notice* This message is intended exclusively for the individual or entity to which it is addressed. This communication may contain information that is proprietary, privileged, confidential, or otherwise legally exempt from disclosure. If you are not the named addressee, you are not authorized to read, print, retain, copy, or disseminate this message or any part of it. If you have received this message in error, please notify the sender immediately by replying to this e-mail and delete all copies of this message. On Wed, May 8, 2024 at 5:28 PM Adrian Klaver wrote: > On 5/8/24 08:24, Daniel McKenzie wrote: > > It's running both (in docker containers) and also quite a few more > > docker containers running various .NET applications. > > I think what you found is that the r7a.medium instance is not capable > enough to do all that it is asked without introducing lag under load. > Answering the questions posed by Tomas Vondra would help get to the > actual cause of the lag. > > In meantime my suspicion is this part: > > "For example, when I use a psql terminal to update a user's last name > from "Jones" to "Smith" then I would expect the enrichment query to find > "Smith" but it will sometimes still find "Jones". It finds the old data > perhaps 1 in 50 times." > > If this is being run against the Postgres server my guess is that > synchronous_commit=on is causing the commit on the server to wait for > the WAL records to be flushed to disk and this is not happening in a > timely manner in the '... 1 in 50 times' you mention. In that case you > see the old values not the new committed values. This seems to be > confirmed when you set synchronous_commit=off and don't see old values. > For completeness per: > > https://www.postgresql.org/docs/current/wal-async-commit.html > > "However, for short transactions this delay is a major component of the > total transaction time. Selecting asynchronous commit mode means that > the server returns success as soon as the transaction is logically > completed, before the WAL records it generated have actually made their > way to disk. This can provide a significant boost in throughput for > small transactions. > > Asynchronous commit introduces the risk of data loss. There is a short > time window between the report of transaction completion to the client > and the time that the transaction is truly committed (that is, it is > guaranteed not to be lost if the server crashes). ... > " > > > > > Daniel McKenzie > > Software Developer > > -- > Adrian Klaver > adrian.kla...@aklaver.com > >
Re: Unexpected data when subscribing to logical replication slot
Thank you all for your input. We have solved the problem by - 1. Configuring wal2json to include xids <https://github.com/eulerto/wal2json/blob/master/README.md>. 2. Updating our enrichment queries to return the xmin <https://www.postgresql.org/docs/9.1/ddl-system-columns.html>. 3. Retrying our enrichment queries after a brief sleep if xmin < xid. This seems to be working very well so far. Daniel McKenzie Software Developer Office: +1 403.910.5927 x 251 Mobile: +44 7712 159045 Website: www.curvedental.com *Curve Dental Confidentiality Notice* This message is intended exclusively for the individual or entity to which it is addressed. This communication may contain information that is proprietary, privileged, confidential, or otherwise legally exempt from disclosure. If you are not the named addressee, you are not authorized to read, print, retain, copy, or disseminate this message or any part of it. If you have received this message in error, please notify the sender immediately by replying to this e-mail and delete all copies of this message. On Thu, May 9, 2024 at 5:45 PM Adrian Klaver wrote: > On 5/9/24 00:32, Daniel McKenzie wrote: > > > We've had this running in live now for years without a hiccup so we are > > surprised to learn that we have this massive race condition and it just > > so happens that the hardware is fast enough to process the transaction > > before the .NET application can react to replication slot changes. > > On broad scale I'm going to say that over 'for years' there has been an > increase in load on the Postgres server as well as the I/0 system of the > machine it is running on. What you are seeing now is the canary in the > mine giving you the heads up that more trouble lies ahead as the > hardware and software is reaching load limits. > > On finer scale my guess is that the following is happening when > synchronous_commit = on: > > 1) Postgres session #1 does data change. > > 2) This is replicated out and picked up by wal2json, which sees the new > data. > > 3) The Postgres server waits for the confirmation that the WAL record > has been written out to disk. Upon confirmation it commits on the > server. This is the part that I am not sure of in relation to wal2json. > > 4) Postgres session #2 queries the database for the record. In the case > where 3) has not completed it sees the old values as the data change in > session #1 has not committed and therefore the new values are not seen > by other sessions. > > > > > Daniel McKenzie > > Software Developer > > -- > Adrian Klaver > adrian.kla...@aklaver.com > >