能否将Memcache与Cloudant/NoSQL搭配?Node.js生产场景求优化方案
Can Memcached be paired with any NoSQL database? (Node.js + Cloudant example)
Absolutely! Memcached is a flexible, general-purpose key-value cache that plays nicely with nearly any NoSQL database—including Cloudant. Given your scenario (millions of users, way more reads than writes leading to high Cloudant costs), a read-through caching pattern is perfect here. Let’s walk through exactly how to implement this in Node.js.
Core Concept: Read-Through Caching
The idea is straightforward:
- When a read request comes in, first check Memcached for the data.
- If it’s there (a "cache hit"), return it immediately—no Cloudant call needed.
- If not (a "cache miss"), fetch the data from Cloudant, store it in Memcached for future requests, then return it.
- When data is updated, invalidate the corresponding cache entry to avoid serving stale data.
Step-by-Step Node.js Implementation
1. Install Dependencies
First, grab the necessary packages:
npm install memcached @ibm-cloud/cloudant
2. Initialize Clients
Set up connections to both Memcached and Cloudant (replace placeholders with your actual credentials):
const Memcached = require('memcached'); const { CloudantV1 } = require('@ibm-cloud/cloudant'); // Memcached client (use your production Memcached address/port) const memcached = new Memcached('your-memcached-host:11211', { retries: 10, retry: 1000, timeout: 500 }); // Cloudant client const cloudant = CloudantV1.newInstance({ url: 'your-cloudant-instance-url', authenticator: new CloudantV1.IamAuthenticator({ apikey: 'your-cloudant-api-key' }) });
3. Cached Read Function
Wrap your Cloudant read logic with cache checks:
async function getDocumentWithCache(dbName, docId, ttl = 3600) { const cacheKey = `cloudant:${dbName}:${docId}`; // Check Memcached first const cachedResult = await new Promise((resolve, reject) => { memcached.get(cacheKey, (err, data) => { err ? reject(err) : resolve(data); }); }); if (cachedResult) { console.log(`Cache hit for ${cacheKey}`); return JSON.parse(cachedResult); } // Cache miss: fetch from Cloudant console.log(`Cache miss for ${cacheKey} — pulling from Cloudant`); const cloudantResponse = await cloudant.getDocument({ db: dbName, docId: docId }); const document = cloudantResponse.result; // Store result in Memcached (TTL in seconds; 3600 = 1 hour) await new Promise((resolve, reject) => { memcached.set(cacheKey, JSON.stringify(document), ttl, (err) => { err ? reject(err) : resolve(); }); }); return document; }
4. Cache Invalidation on Write
When you update or delete a document, clear its cache entry to prevent stale data:
async function updateDocumentAndInvalidateCache(dbName, docId, updates) { // First update Cloudant const existingDoc = await cloudant.getDocument({ db: dbName, docId }); const updatedDoc = { ...existingDoc.result, ...updates }; await cloudant.putDocument({ db: dbName, docId: docId, document: updatedDoc }); // Invalidate the cache const cacheKey = `cloudant:${dbName}:${docId}`; await new Promise((resolve, reject) => { memcached.del(cacheKey, (err) => { err ? reject(err) : resolve(); }); }); console.log(`Cache invalidated for ${cacheKey}`); return updatedDoc; }
5. Usage Example
async function main() { try { // Fetch a user with cache const user = await getDocumentWithCache('users', 'user_12345'); console.log('Fetched user:', user); // Update user and invalidate cache await updateDocumentAndInvalidateCache('users', 'user_12345', { last_login: new Date().toISOString() }); } catch (error) { console.error('Error:', error); } finally { // Clean up connections (adjust for production) memcached.end(); } } main();
Best Practices to Optimize
- Adjust TTL Wisely: Set time-to-live based on how often your data changes. For static data, use longer TTLs (e.g., 24 hours); for frequently updated data, use shorter ones (e.g., 15 minutes).
- Cache Key Naming: Use a consistent pattern like
service:resource:idto avoid key collisions. - Fail-Safe Fallback: Add error handling for Memcached failures—if the cache is down, your app should still fetch directly from Cloudant instead of crashing.
- Monitor Hit Rate: Use
memcached statsto check your cache hit rate. Aim for 90%+; if it’s lower, revisit your TTL or key strategy. - Batch Operations: For bulk reads, fetch all cached keys first, then only pull missing documents from Cloudant to minimize database calls.
内容的提问来源于stack exchange,提问作者BalajiK
相关产品推荐
相关产品推荐

