Distributed Deployment Guide
Overview
monSQLize supports single-instance and multi-instance deployments. In a single instance environment, local query cache is usually enough. In a multi-instance deployment, use Redis-backed remote cache and distributed invalidation when cached reads must converge across processes.
Why is distributed support needed?
In a multi-instance deployment, each instance has its own local cache and lock manager. If no special treatment is done, it will lead to:
- Cache inconsistency window: after instance A updates data, instance B can briefly hold an old local cache entry until invalidation arrives.
- Transaction/cache boundary: MongoDB transactions keep session semantics, while cache invalidation is flushed after commit on a best-effort basis.
- Business critical sections: balance, inventory and payment flows still need application-level idempotency, fencing or explicit locks.
Architecture selection
1. Single instance deployment (✅ Recommended: small applications)
Features:
- ✅ All functions fully supported
- ✅ No Redis required
- ✅ Easy to configure
- ⚠️ No high availability
Applicable scenarios:
- Development/test environment
- Production environment with low traffic
- Single application
Configuration Example:
2. Multiple instances + independent local cache (🔴 not recommended)
RISK:
- 🔴 High Risk: Cache Inconsistency
- 🔴 Transaction isolation failure
- ❌ Not recommended for production environments
3. Multiple instances + Redis + distributed cache failure (🟢 Recommended)
Features:
- ✅ High availability
- ✅ Good cache consistency (millisecond latency)
- ✅Excellent performance
- ⚠️ Depends on Redis
Applicable scenarios:
- Production environment (recommended)
- High concurrency scenarios
- Tolerate short-term (millisecond level) data inconsistencies
Configuration Example:
4. Multiple instances + explicit business coordination (🟡 Finance/Trading)
Features:
- ✅ Shared cache invalidation across instances
- ✅ Explicit application/framework-level lock and idempotency choices
- ✅ Suitable for financial/trading scenarios when paired with durable business safeguards
- ⚠️ Cache invalidation remains best-effort and is not atomic with database commits
Applicable scenarios:
- financial system
- Payment/Transfer
- Inventory deductions
- Any scenario where the business layer already provides idempotency, fencing, or cache bypassing for strict reads
Configuration Example:
transaction.distributedLock is retained only as a compatibility placeholder and is not wired into transaction cache-lock interception. Disable cache on strict read paths or coordinate at the business/framework layer when cross-instance strict consistency is required.
5. Multiple instances + disable cache (🟡 Applicable: strong consistency requirements)
Features:
- ✅ 100% data consistency
- ✅ No external dependencies
- ❌ Performance degradation (all requests check the database)
Applicable scenarios:
- Low traffic applications
- Strong consistency requirements
- Unable to use Redis
Configuration Example:
Risks in distributed environments
Risk 1: Cache invalidation out of sync
Scenario:
Impact:
- Users see inconsistent balances -Business logic may go wrong
Solution: Enable Distributed Cache Invalidation Broadcast
Risk 2: Transaction cache lock does not take effect
Scenario:
Impact:
- Read the intermediate state of the transaction
- There may be dirty data in the cache
- Transaction isolation failure
Solution: Use explicit business coordination and bypass cache when strict freshness is required
Solution
Solution 1: Distributed cache invalidation broadcast (recommended)
Principle: Use Redis Pub/Sub to broadcast cache invalidation messages
Workflow:
Configuration:
Advantages:
- ✅ Real-time broadcast, low latency (millisecond level)
- ✅ Use existing Redis infrastructure
- ✅ Simple to implement and easy to maintain
Disadvantages:
- ⚠️ Depends on Redis
- ⚠️ May be inconsistent within a very short time window (network delay)
Solution 2: Explicit business lock and cache bypass
Principle: Keep cache invalidation best-effort, and protect critical side effects with an explicit business lock plus idempotency/fencing.
Workflow:
Configuration:
Advantages:
- ✅ The consistency contract is explicit at the business boundary
- ✅ Works with external effects such as payments, inventory, and fulfillment
- ✅ Suitable for financial/trading scenarios
Disadvantages:
- ⚠️ Requires application-level idempotency and recovery design
- ⚠️ Does not make cache invalidation transaction-atomic
- ⚠️ Depends on Redis availability when Redis locking is used
Configuration Guide
Complete configuration example
💡 Configuration instructions:
- ✅ Required: Must be configured, otherwise the function will not work
- ❌ Optional: You can not configure it, use the default value
- One Redis instance: used for remote cache and broadcasting; if you also use business locks, wire that path explicitly.
Configuration option description
distributed (distributed cache invalidation)
⚠️ IMPORTANT NOTE:
redisandredisUrl: choose one for distributed invalidation- Recommended: pass the same Redis instance as
cache.distributed.rediswhen you want cache and Pub/Sub to share connection ownership explicitly. - If you need to configure it separately: use the
redisparameter; the instance must exposeduplicate()so publish and subscribe use separate Redis connections - Not recommended: use
redisUrl(new connection will be created)
- Recommended: pass the same Redis instance as
instanceId: Optional, but strongly recommended to set manually- Default value format:
instance-${timestamp}-${random}(such asinstance-1732521234567-a2b3c4d5e) instanceIdmust be different for each instance, otherwise the cache invalidation broadcast will fail.- It is recommended to use environment variables:
process.env.INSTANCE_IDorprocess.env.HOSTNAME
- Default value format:
transaction.distributedLock (compatibility placeholder)
transaction.distributedLock is retained only as a compatibility placeholder and is not wired into transaction cache-lock interception. Transaction cache locks remain process-local. Use DistributedCacheLockManager explicitly for business critical sections, pair it with idempotency/fencing, or disable cache for strict read paths.
Runtime behavior for users
Distributed cache invalidation flow
When cache.distributed is enabled and Redis Pub/Sub is configured, monSQLize prepares a broadcast channel during connect(). The application-facing contract is:
- A write succeeds or fails according to MongoDB.
- If cache invalidation is enabled for that write, monSQLize attempts local cache invalidation and publishes an invalidation message for other instances.
- Other instances receive the message and invalidate their local cache entries for the matching namespace or pattern.
- Redis publish/subscribe failures are observable through logging/stats, but they do not roll back the already completed MongoDB write.
Operational notes
- Give every running instance a unique
instanceIdso it can ignore its own broadcasts and accept broadcasts from peers. - Keep strict-read paths explicit: bypass or disable cache where stale reads are not acceptable.
- Monitor cache invalidation warnings, Redis publish errors, and cache stats. A database write can be committed even if a later cache invalidation step fails.
- Treat distributed invalidation as an eventual-consistency helper. It narrows stale-cache windows; it is not a two-phase commit protocol and does not provide global strong consistency.
Best Practices
1. Environment detection
Automatically detect whether you are in a distributed environment:
2. Choose a plan based on your business
3. Monitoring and logging
Enable logs to view distributed component status:
4. Error handling
Degrade strategy when distributed components fail:
Performance considerations
1. Distributed cache invalidation performance
- Latency: ~1-5ms (Redis Pub/Sub)
- Bandwidth: Each failure ~100 bytes
- Impact: Negligible impact on overall performance
2. Explicit business lock performance
- Latency: ~2-10ms (Redis SET/DEL)
- Throughput: Slight decrease (~10-20%)
- RECOMMENDED: Use only around business critical sections that need cross-instance coordination
3. Comparison of caching strategies
Troubleshooting
Problem 1: Cache invalidation broadcast does not take effect
Symptoms: After instance A is updated, instance B still reads old data
Troubleshooting steps:
-
Check whether the Redis connection is normal
-
Check Pub/Sub subscriptions
-
View logs
-
Check the instance ID
Problem 2: transaction.distributedLock does not take effect
Symptom: Other instances still write to cache during transaction
Troubleshooting steps:
-
Confirm the runtime boundary
-
Use an explicit business lock for critical sections
-
Disable cache or bypass cache for strict freshness paths.
Problem 3: Redis connection failed
Symptoms: An error occurs when the application starts or the cache does not work
Solution:
Summary
Recommended configuration
Quick Start
The simplest distributed configuration (recommended):
⚠️ IMPORTANT:
instanceIdis optional and automatically generated by default (format:instance-${timestamp}-${random})- But strongly recommended to set it manually to facilitate debugging and log tracking
instanceIdmust be different for each instance- It is recommended to use environment variables:
instanceId: process.env.INSTANCE_ID - Set either
redisorredisUrl; the runtime does not infer Pub/Sub config fromcache.remote.
Related documents
- Cache Policy Document
- Cache consistency description
- Transaction Function Document
- Redis Cache Adapter