提升性能,内存缓存是关键,经典LRU根据访问频率更新,不能完全满足需求,通常业务更需要基于时间或事件触发更新。针对要求实时更新(用户信息、配置)和可以延迟更新(评论、动态列表)的数据,需要设计不同的缓存更新策略。
即每个缓存key在put时记录有效期,当有效期到达时清理key(一般语言都有对应的库实现)
当get时,key存在则说明缓存有效,使用该缓存,否则查询db并更新缓存
即每次存储数据被修改时,发出事件通知
所有读数据的服务监听该事件通知(可通过redis或消息队列实现),收到修改事件时更新对应缓存key
在get缓存数据时进行校验,缓存有效即使用,缓存无效查询db并更新
有效检查策略1:
数据添加版本号字段(可选用修改点的时间戳或数据的md5),db和缓存同时记录该版本号。
db更新的同时修改版本号,查询时缓存的版本号和db的做比较(从db拉去版本号效率远高于拉所有数据)

x
package main
// LRUCache 结构体type LRUCache struct { size int capacity int cache map[int]*DLinkedNode head, tail *DLinkedNode}
type DLinkedNode struct { key, value int prev, next *DLinkedNode}
func initDLinkedNode(key, value int) *DLinkedNode { return &DLinkedNode{ key: key, value: value, }}
func NewLRUCache(capacity int) LRUCache { l := LRUCache{ cache: map[int]*DLinkedNode{}, head: initDLinkedNode(0, 0), tail: initDLinkedNode(0, 0), capacity: capacity, } l.head.next = l.tail l.tail.prev = l.head return l}
func (lru *LRUCache) Get(key int) int { if _, ok := lru.cache[key]; !ok { return -1 } node := lru.cache[key] lru.moveToHead(node) return node.value}
func (lru *LRUCache) Put(key int, value int) { if _, ok := lru.cache[key]; !ok { node := initDLinkedNode(key, value) lru.cache[key] = node lru.addToHead(node) lru.size++ if lru.size > lru.capacity { removed := lru.removeTail() delete(lru.cache, removed.key) lru.size-- } } else { node := lru.cache[key] node.value = value lru.moveToHead(node) }}
func (lru *LRUCache) addToHead(node *DLinkedNode) { node.prev = lru.head node.next = lru.head.next lru.head.next.prev = node lru.head.next = node}
func (lru *LRUCache) removeNode(node *DLinkedNode) { node.prev.next = node.next node.next.prev = node.prev}
func (lru *LRUCache) moveToHead(node *DLinkedNode) { lru.removeNode(node) lru.addToHead(node)}
func (lru *LRUCache) removeTail() *DLinkedNode { node := lru.tail.prev lru.removeNode(node) return node}
func main() { lRUCache := NewLRUCache(2) lRUCache.Put(1, 1) // 缓存是 {1=1} //spew.Dump(lRUCache.cache) lRUCache.Put(2, 2) // 缓存是 {1=1, 2=2} //spew.Dump(lRUCache.cache) lRUCache.Get(1) // 返回 1 lRUCache.Put(3, 3) // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} //spew.Dump(lRUCache.cache) lRUCache.Get(2) // 返回 -1 (未找到) lRUCache.Put(4, 4) // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} //spew.Dump(lRUCache.cache) lRUCache.Get(1) // 返回 -1 (未找到) lRUCache.Get(3) // 返回 3 lRUCache.Get(4) // 返回 4}
选取合适的hash算法,将目标字符串映射到对应的比特位上
比如:
"baidu": 1、4、7
"tencent": 3、4、8
查询 google:
查询app le:
注意: 传统的布隆过滤器并不支持删除操作
缓存和数据库都没有的数据,被大量请求
Filter缓存突然失效了,这时候如果有大量用户请求该数据
大量的缓存的数据,在同一个时间点过期