MST

星途 面试题库

面试题:缓存设计之Memcached数据过期策略优化

Memcached有多种数据过期策略,假设在一个高并发且数据更新频繁的系统中,你如何优化Memcached的数据过期策略,以避免缓存雪崩和缓存穿透问题,同时保证系统的高性能和数据一致性?请详细说明思路和具体实现方法。
40.4万 热度难度
后端开发缓存设计

知识考点

AI 面试

面试题答案

一键面试

避免缓存雪崩思路及方法

  1. 思路:缓存雪崩是指大量缓存同时过期,导致大量请求直接打到数据库,引起数据库压力骤增甚至崩溃。解决思路是分散缓存过期时间,避免集中过期。
  2. 具体实现方法:在设置缓存过期时间时,添加一个随机值。例如原本过期时间是60分钟,可以设置为55 - 65分钟之间的随机值。在Python中使用pymemcache库示例如下:
import pymemcache
import random

client = pymemcache.client.base.Client(('localhost', 11211))
expiry_time = 60 * 60  # 1小时
random_offset = random.randint(-5 * 60, 5 * 60)  # 随机 -5到5分钟
total_expiry = expiry_time + random_offset
client.set('key', 'value', expire=total_expiry)

避免缓存穿透思路及方法

  1. 思路:缓存穿透是指查询一个不存在的数据,由于缓存不命中,每次都去数据库查询,导致数据库压力增大。解决方法有布隆过滤器和空值缓存。
  2. 具体实现方法
    • 布隆过滤器:在查询数据前,先通过布隆过滤器判断数据是否存在。若布隆过滤器判断不存在,则直接返回,不再查询数据库。以Python的bitarraymmh3库实现简单布隆过滤器示例:
import bitarray
import mmh3


class BloomFilter:
    def __init__(self, num_items, false_positive_rate):
        self.false_positive_rate = false_positive_rate
        self.num_items = num_items
        self.num_bits = int(-(num_items * \
            (math.log(false_positive_rate))) / (math.log(2) ** 2))
        self.hash_count = int((self.num_bits / num_items) * math.log(2))
        self.bit_array = bitarray.bitarray(self.num_bits)
        self.bit_array.setall(0)

    def add(self, item):
        for i in range(self.hash_count):
            index = mmh3.hash(item, i) % self.num_bits
            self.bit_array[index] = 1

    def check(self, item):
        for i in range(self.hash_count):
            index = mmh3.hash(item, i) % self.num_bits
            if not self.bit_array[index]:
                return False
        return True


# 使用示例
bf = BloomFilter(num_items=10000, false_positive_rate=0.01)
bf.add('example_key')
if bf.check('example_key'):
    # 这里可以接着查Memcached和数据库
    pass
else:
    # 直接返回,数据不存在
    pass
- **空值缓存**:当查询数据库发现数据不存在时,也将这个空值缓存起来,并设置一个较短的过期时间,下次查询相同数据时,直接从缓存返回空值,避免查询数据库。例如:
client = pymemcache.client.base.Client(('localhost', 11211))
result = client.get('key')
if result is None:
    # 查询数据库
    db_result = get_from_db('key')
    if db_result is None:
        # 缓存空值,设置短过期时间
        client.set('key', None, expire=60)
        return None
    else:
        client.set('key', db_result, expire=3600)
        return db_result
else:
    return result


def get_from_db(key):
    # 实际数据库查询逻辑
    pass

保证高性能和数据一致性思路及方法

  1. 思路:高性能要求减少缓存操作的耗时,数据一致性要确保缓存数据和数据库数据保持同步。
  2. 具体实现方法
    • 高性能:优化网络连接,例如采用长连接方式减少连接建立开销;合理设置Memcached服务器的内存分配,避免频繁内存交换;批量操作缓存,减少客户端与服务端交互次数。如在Python中批量设置缓存:
client = pymemcache.client.base.Client(('localhost', 11211))
data = {'key1': 'value1', 'key2': 'value2'}
for key, value in data.items():
    client.set(key, value)
- **数据一致性**:采用读写锁机制,在更新数据时,先获取写锁,更新数据库后再更新缓存,更新完成后释放写锁;读数据时获取读锁,确保在读取过程中数据不被修改。或者采用缓存失效机制,当数据库数据更新时,立即让对应的缓存失效。例如在数据库更新操作后,执行`client.delete('key')`删除对应的缓存数据。