Re: Potential "AIO / io workers" inter-worker locking issue in PG18?
Marco Boeringa <marco@boeringa.demon.nl>
From: Marco Boeringa <marco@boeringa.demon.nl>
To: Thom Brown <thom@linux.com>
Cc: pgsql-bugs@lists.postgresql.org
Date: 2025-10-05T20:22:32Z
Lists: pgsql-bugs
Hi Thom, I realized that my observation of the pg_aios view being empty was likely with the "io_method = sync" option set, which I guess doesn't use or fill the pg_aios view? Can you confirm the pg_aios view is unused with "io_method = sync", this aspect is not documented in the PostgreSQL help? Anyway, I will need to re-test with 'worker' set. I do see Tomas Vondra mentioning that even the 'sync' option in PG18 still goes "through the AIO infrastructure", but what that exactly means, also in relation to the pg_aios view, IDK: https://vondra.me/posts/tuning-aio-in-postgresql-18/ Marco Op 5-10-2025 om 21:57 schreef Marco Boeringa: > > Hi Thom, > > I now also witnessed this issue with "io_method = sync", so it may not > have relation with the number of workers set. I initially thought it > did not occur with 'sync', as two runs successfully completed without > delays, however, the last did show the issue. Unfortunately, this is a > very complex multi-stage geoprocessing workflow, that cannot easily be > cut down to a simple one SQL statement reproducible case. And for the > specific Italy extract it takes about 7 hours to complete if the run > is successful and without the delays observed, so each test run costs > considerable time if I adjust anything. > > There is also a PostGIS upgrade in the mix (3.5.2 to 3.6.0) that may > or may not be involved, as that version of PostGIS is the minimum for > PG18. I see a 3.6.1 is already planned and will need to re-test with > that version once released. I definitely do use PostGIS functions at > the stage the processing gets heavily delayed. > > As to the question about the pg_aios view I wasn't aware off: it > appears to be empty at that point, but I will need to confirm that > observation, as with my last run, the moment I looked at the view, > some of the very delayed multi-threaded jobs (> 6.5 hours instead of > 10 seconds!) started slowly returning one by one, although some were > still in wait / stuck for some time before all had returned, so the > pg_aios view being empty probably is still representative of the stuck > situation. > > Also note that I also adjust the storage parameters of the tables > involved to force a more aggressive vacuuming to avoid transaction ID > wraparound (which shouldn't be an issue anyway with the small test > Italy extract). This has all proven pretty reliable in the past and > with previous PostgreSQL / PostGIS releases, up to the Facebook > Daylight multi-billion record tables as noted in the previous post. > There also is no PostgreSQL partitioning involved in any of this, > these are ordinary tables. > > Marco > > Op 5-10-2025 om 12:51 schreef Thom Brown: >> On Sun, 5 Oct 2025, 10:52 Marco Boeringa, <marco@boeringa.demon.nl> >> wrote: >> >> Hi, >> >> I currently run PG18 + PostGIS 3.6.0 on an Ubuntu 24.04 VM guest as >> Windows 10 Hyper-V virtual machine. >> >> The machine is a dedicated refurbished HP Z840 local workstation >> with >> 2x22 cores (E5-2699 v4) with 512 GB RAM and a 10 TB NVMe raid-0, >> with >> the Ubuntu guest having 400 GB RAM available. >> >> On this machine, which is dedicated to just one custom written >> geoprocessing workflow involving OpenStreetMap data, I have >> successfully >> processed up to global OpenStreetMap Facebook Daylight distribution >> data, with up to > 2.4 B record Polygon table for all Facebook >> Daylight >> buildings. So this has proven a very capable system. >> >> However, after upgrading to PG18 and the switch to the "io_method = >> worker" setting (tested with 3, 5, 16 and 22 workers), I am >> seeing an >> issue where it appears there may be a major issue with io workers >> potentially getting into some sort of locking conflict, that >> takes hours >> to resolve. >> >> The custom written geoprocessing workflow uses Python >> multi-threading >> based on the Python 'concurrent.futures' framework in combination >> with >> either pyodbc or psycopg2 as database connector to implement a >> powerful >> parallel processing solution to speed up some of the computationally >> intensive tasks (which use UPDATEs), which I generally use with >> up to 44 >> threads to fully saturate the dual CPU 44 core system. The custom >> code >> creates a pool of jobs to process for the threads, with the code >> being >> designed to minimize inter-thread locking issues by taking into >> account >> PostgreSQL page locality (although the actual records to process >> are not >> assigned by pages but by unique IDs in the tables). Basically, >> the code >> is designed such that different threads never attempt to access >> the same >> database pages, as each thread gets it own unique pages assigned, >> thus >> avoiding inter-thread locking conflicts. This has worked really >> well in >> the past, with system usage maximized over all cores and >> significantly >> speeding up processing. Jobs are implemented as database VIEWs, that >> point to the records to process via the unique ID of each. These >> views >> must of course be read by each thread, which is probably where >> the PG18 >> io workers kick-in. >> >> This has worked really well in previous versions of PostgreSQL >> (tested >> up to PG17). However, in PG18, during the multi-threaded >> processing, I >> see some of my submitted jobs that in this case were run against >> a small >> OpenStreetMap Italy extract of Geofabrik, all of a sudden take > >> 1 hour >> to finish (up to 6 hours for this small extract), even though >> similar >> jobs from the same processing step, finish in less than 10 >> seconds (and >> the other jobs should as well). This seems to happen kind of >> "random". >> Many multi-threading tasks before and after the affected processing >> steps, do finish normally. >> >> When this happens, I observe the following things: >> >> - High processor activity, even though the jobs that should >> finish in >> seconds, take hours, all the while showing the high core usage. >> >> - PgAdmin shows all sessions created by the Python threads as >> 'active', >> with *no* wait events attached. >> >> - The pg_locks table does not show locking conflicts, all locks are >> granted. I did notice however, that the relation / table locks >> were not >> "fastpath" locks, but ordinary ones. All other locks taken, e.g. on >> indexes related to the same table, were fastpath. I don't know if >> this >> has any relevance though, as from what I read about the >> difference, this >> shouldn't cause such a big difference, not seconds to hours. >> >> - Please note that the processing DOES eventually proceed, so it >> is not >> an infinite dead-lock or something where I need to kill my Python >> code. >> It just takes hours to resolve. >> >> - Switching to "io_method = sync" seems to resolve this issue, >> and I do >> not observe some jobs of the same batch getting "stuck". This is the >> behavior I was used to seeing in <=PG17. >> >> I am not to familiar with all the internals of PostgreSQL and the >> new >> AIO framework and its "io workers". However, it seems there may >> be some >> sort of locking issue between io workers that can occasionally >> happen in >> PG18 with "io_method = worker"? Is there anyone else observing >> similar >> issues in high multi-threaded processing worklflows? >> >> >> So, to confirm, you get the issue with as little as 3 io_workers? >> >> Also, what is pg_aios telling you during this time? >> >> Thom >>