You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否将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:id to 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 stats to 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:47:47