v2.2.0-beta2 #6083
jarohen
announced in
Announcements
v2.2.0-beta2
#6083
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Hey folks - XTDB 2.2.0-beta2 is here. 🚀
You'll notice the version's gone backwards: rc1 was a release candidate, and this one isn't.
Leadership election has changed substantially since rc1, and we'd rather run that through a beta than carry it into another candidate.
A couple of breaking config changes fall out of it, and the upgrade route depends on how you deploy.
Leadership election (breaking: Kafka config)
In the 2.2.0 line, XTDB has started electing a leader node per database, and the leader is the only node that indexes that database's source log.
In 2.2.0-beta2, a database elects its leader in its own replica log, and claims its term from that same log.
The log is totally ordered, so whichever claim lands first wins, and the term is monotone by construction.
Nothing outside that database's two topics takes part.
Previously the term came from Kafka - the consumer group's generation ID in rc1, transactional producers in rc0 - which ties the fence to a value Kafka owns rather than one XT can reason about.
A generation ID restarts at 1 whenever the coordinator drops the group, and transactional producers aren't available on Azure Event Hubs' standard tier at all.
Owning the term outright lifts both constraints, and takes the consumer group out of the picture with them.
I've written the Raft-inspired design up in a blog: Following the leader: leadership election in XTDB 2.2.
Practically, there's no longer a consumer group for you to configure, so three settings have gone (breaking):
groupIdandpollDurationon the!Kafkacluster configtermEpochon the!Kafkalog configAn unrecognised key fails config parsing rather than being quietly ignored, so a config carried over from rc0 or rc1 will stop your node starting until you remove them.
Deployments sharing a Kafka cluster are now separated by topic name alone - see the Kafka log docs for the details.
Postgres source now needs PostgreSQL 17 (breaking)
The Postgres external source now always creates its replication slot as a failover slot, so that the slot survives a promotion of the upstream standby rather than being lost with the primary.
Losing the slot means re-attaching the database and re-snapshotting from scratch.
Failover slots arrived in PostgreSQL 17, so that's now the minimum for this source.
Whilst we were in there, we've also documented how to size WAL retention for an XTDB slot.
XTDB confirms the slot only as far as the last block it has written to object storage, so what Postgres has to retain is set by XTDB's block cadence rather than by how promptly it indexes each transaction.
See Size WAL retention - the 15-minute default below moves that number considerably.
Blocks are now flushed every 15 minutes
indexer.flushDuration- how long a database that's too quiet to fill a block waits before writing one anyway - previously defaulted to four hours.It's now 15 minutes.
That interval turns out to bound four separate things: how much recent data lives only in the log, how long a starting node spends replaying the tail behind the last block, how stale a reader pointed at another deployment's storage can be, and how much upstream WAL an external source's server has to retain.
Nothing to do on upgrade - config that sets
flushDurationexplicitly is honoured unchanged.Expect more, smaller blocks on quiet databases, and correspondingly more compaction work; a database busy enough to reach
rowsPerBlockcuts on row count long before the timer fires, so it's unaffected either way.Upgrading
From rc0, step through rc1 first - so 2.1.0 -> 2.2.0-rc0 -> 2.2.0-rc1 -> 2.2.0-beta2.
Then, whichever route you took:
groupIdandpollDurationfrom your!Kafkacluster config,termEpochfrom your!Kafkalog config. Leaving them in place fails config parsing at startup.max_slot_wal_keep_sizeagainst the new 15-minute flush default at the same time.jsonoutput are now unquoted numbers -{"n":1.0010}where you'd previously have got{"n":"1.0010"}. If you've a client parsing those as strings, either read them as numbers or setfallback_output_formattojson-ldortransit, where a decimal arrives with an explicit type rather than as a bare literal.If you need to roll back to rc1, raise
termEpochon your!Kafkalog config as you go - it defaults to0, so a node that's never set it wantstermEpoch: 1.rc1 pairs its term with the Kafka consumer group's generation, which starts at 1 in a fresh group and so sits below the terms beta2 has been claiming from the replica log; raising the epoch is what lifts rc1's terms back above them.
An rc1 node that comes up fenced will tell you so, and name the epoch to beat.
If you're coming from 2.1.0, the rc0 upgrade notes still apply in full on top of the above - authentication, logging and Docker paths all changed there.
Elsewhere
Dispatchers.IO, turning one stalled request into a silently wedged node. Object-store I/O is now bounded, and Azure and GCP are isolated from the shared pool.max.message.bytesstopped that database indexing, with the transaction behind it already committed. Oversized messages now go to object storage and are referenced from the log - raising the topic's limit is still worthwhile, since the indirection costs a round trip, but it's no longer what stands between a largeUPDATEand a stalled database.FILTER (WHERE ...)on aggregate functions, so you can count two different things over the same groups without a subquery (docs):version()returnsPostgreSQL 16 (XTDB 2.2.0), putting us where a real PostgreSQL puts its build information, andcurrent_setting('xtdb.version')gives you the version on its own (docs). If you've been sniffing for XT by probing incidental behaviour, this is the intended way._id = <cast expression>silently returned zero rows in rc1.?parameters over Flight SQL were bound in planner-traversal order when a placeholder appeared in the projection, rather than in source order; #5995 - as were an inline XTQL fn's params in SQL. Both now number by source position.EXPLAINworks for plans containing window functions orUNNEST./healthz/startedno longer blocks node startup while a non-critical database catches up.TEXT[]elements no longer arrive carrying literal double quotes, an element containing a comma is no longer split in two, and a null element in aBIGINT[], a top-level JSONnull, or a JSON integer beyondint64no longer halt ingestion or wrap around.As always, the milestone has the full list.
A big thanks again to our design partners and clients, whose production deployments shaped most of the above - it's massively appreciated 🙏
If you've any questions or thoughts, please do get in touch - we'd love to hear from you!
Cheers!
James & the XT Team
This discussion was created from the release v2.2.0-beta2.
All reactions