关于缓存的反思

目前缓存的解决方案一般有两种:

内存缓存(如 Ehcache) —— 速度快,进程内可用

集中式缓存(如 Redis)—— 可同时为多节点提供服务

使用内存缓存时,一旦应用重启后,由于缓存数据丢失,缓存雪崩,给数据库造成巨大压力,导致应用堵塞

使用内存缓存时,多个应用节点无法共享缓存数据

使用集中式缓存,由于大量的数据通过缓存获取,导致缓存服务的数据吞吐量太大,带宽跑满。现象就是 Redis 服务负载不高,但是由于机器网卡带宽跑满,导致数据读取非常慢

在遭遇问题1、2 时,很多人自然而然会想到使用 Redis 来缓存数据,因此就难以避免的导致了问题3的发生。

当发生问题 3 时,又有很多人想到 Redis 的集群,通过集群来降低缓存服务的压力,特别是带宽压力。

但其实,这个时候的 Redis 上的数据量并不一定大,仅仅是数据的吞吐量大而已。

个人觉得: 可以使用2级缓存,优先使用本地,再使用redis或者memcache的缓存,本地防止OOM可以做一些淘汰机制,刷新到redis或者memcahe中,当然这种情况就需要一些精巧的机制保证2级缓存的一致性。

节点间数据同步的方案 —— Redis Pub/Sub 和 JGroups 。当某个节点的缓存数据需要更新时,会通过 Redis 的消息订阅机制或者是 JGroups 的组播来通知集群内其他节点。当其他节点收到缓存数据更新的通知时,它会清掉自己内存里的数据,然后重新从 Redis 中读取最新数据。

为什么不用 Ehcache 的集群方案?

对 Ehcache 比较熟悉的人还会问的就是这个问题,Ehcache 本身是提供集群模式的,可以在多个节点同步缓存数据。但是 Ehcache 的做法是将整个缓存数据在节点间进行传输。如咱们前面的说的,一个页面需要读取 50K 的缓存数据,当这 50K 的缓存数据有更新时,那么需要在几个节点间传递整个 50K 的数据。这也会造成应用节点间大量的数据传输,这个情况完全不可控。

补充:当然这个单个数据传输量本身没有差别,但是 ehcache 利用 jgroups 来同步数据的做法,在实际测试过程中发现可靠性还是略低,而且 jgroups 的同步数据在云主机上无法使用。

订阅和通知模式传输的仅仅是缓存的 key 而已,因此相比 Ehcache 的集群模式,使用通知机制要传输的数据极其小,对节点间的数据通信完全不会产生大的影响。

发表评论

电子邮件地址不会被公开。 必填项已用*标注