lncfg+scripts: use configurable global lock for postgres backends

Replace hardcoded WithGlobalLock assignment with configurable
options wallet postgres backends. Also add the WithGlobalLock
option to the channeldb table for postgres backends.

Defaults:
- channeldb: false (allow concurrent access)
- wallet: true (maintain safe single-writer behavior)

Users can now override these defaults via:
- db.postgres.channeldb-with-global-lock
- db.postgres.walletdb-with-global-lock

This gives operators flexibility while maintaining safe defaults
until full native SQL migration is complete.

Moreover exclude db.postgres.walletdb-with-global-lock check
in the sample config file script. We cannot easily check the
correct default because we set it later in the LND startup
sequence so we exclude it.
This commit is contained in:
ziggie 2025-11-27 20:03:17 +01:00
parent dd304e94fa
commit a25659a6e4
No known key found for this signature in database
GPG key ID: 1AFF9C4DCED6D666
4 changed files with 42 additions and 10 deletions

View file

@ -42,6 +42,16 @@ db.postgres.timeout=0
Connection timeout is disabled, to account for situations where the database
might be slow for unexpected reasons.
Moreover for particular kv tables we also add the option to access the
tables via a global lock (single wirter). This is a temorpary measure until
these particular tables have a native sql schema. This helps to mitigate
resource exhaustion in case LND experiencing high concurrent load:
* `db.postgres.walletdb-with-global-lock=true` to run LND with a single writer
for the walletdb_kv table (default is true).
* `db.postgres.channeldb-with-global-lock=false` to run the channeldb_kv table
with a single writer (default is false).
## Important note about replication
In case a replication architecture is planned, streaming replication should be avoided, as the master does not verify the replica is indeed identical, but it will only forward the edits queue, and let the slave catch up autonomously; synchronous mode, albeit slower, is paramount for `lnd` data integrity across the copies, as it will finalize writes only after the slave confirmed successful replication.

View file

@ -115,7 +115,15 @@ func DefaultDB() *DB {
},
Postgres: &sqldb.PostgresConfig{
MaxConnections: defaultPostgresMaxConnections,
QueryConfig: *sqldb.DefaultPostgresConfig(),
// Normally we don't use a global lock for channeldb
// access, but if a user encounters huge concurrency
// issues, they can enable this to use a global lock.
ChannelDBWithGlobalLock: false,
// Default to true to maintain safe single-writer
// behavior until the wallet subsystem is upgraded to
// a native sql schema.
WalletDBWithGlobalLock: true,
QueryConfig: *sqldb.DefaultPostgresConfig(),
},
Sqlite: &sqldb.SqliteConfig{
MaxConnections: defaultSqliteMaxConnections,
@ -400,9 +408,15 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
// users to native SQL.
postgresConfig := GetPostgresConfigKVDB(db.Postgres)
// Create a separate config for channeldb with the global lock
// setting if configured.
postgresConfigChannelDB := GetPostgresConfigKVDB(db.Postgres)
postgresConfigChannelDB.WithGlobalLock = db.Postgres.
ChannelDBWithGlobalLock
postgresBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSChannelDB,
postgresConfigChannelDB, NSChannelDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres graph "+
@ -450,14 +464,11 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
}
closeFuncs[NSTowerServerDB] = postgresTowerServerBackend.Close
// The wallet subsystem is still not robust enough to run it
// without a single writer in postgres therefore we create a
// new config with the global lock enabled.
//
// NOTE: This is a temporary measure and should be removed as
// soon as the wallet code is more robust.
// Create a separate config for wallet with the global lock
// setting if configured.
postgresConfigWalletDB := GetPostgresConfigKVDB(db.Postgres)
postgresConfigWalletDB.WithGlobalLock = true
postgresConfigWalletDB.WithGlobalLock = db.Postgres.
WalletDBWithGlobalLock
postgresWalletBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,

View file

@ -1616,6 +1616,17 @@
; Whether to skip executing schema migrations.
; db.postgres.skipmigrations=false
; Use a global lock for channeldb access. This ensures only a single writer at
; a time but reduces concurrency. This is a temporary workaround until the
; revocation log is migrated to native SQL.
; db.postgres.channeldb-with-global-lock=false
; Use a global lock for wallet database access. This is a temporary workaround
; until the wallet subsystem is upgraded to a native sql schema.
; db.postgres.walletdb-with-global-lock=true
; The maximum number of elements to use in a native-SQL batch query IN clause.
; db.postgres.query.max-batch-size=5000

View file

@ -59,7 +59,7 @@ OPTIONS_NO_LND_DEFAULT_VALUE_CHECK="channel-max-fee-exposure adminmacaroonpath \
backupfilepath maxchansize bitcoin.chaindir bitcoin.defaultchanconfs \
bitcoin.defaultremotedelay bitcoin.dnsseed signrpc.signermacaroonpath \
walletrpc.walletkitmacaroonpath chainrpc.notifiermacaroonpath \
routerrpc.routermacaroonpath"
routerrpc.routermacaroonpath db.postgres.walletdb-with-global-lock"
# EXITCODE is returned at the end after all checks are performed and set to 1