Local Cache要存对象还是序列化数据?

序言

偶然间登录掘金账号,想起了周末去咖啡店写文章的我,现在改为了健身(健康为主,力争满头秀发),还是觉得惭愧,既然路过就写一段吧。深度不深,只是通过一个小案例引发的一些思考,不喜勿喷~

背景

在日常工作中,我们经常会遇到需要使用缓存的场景,例如存一些临时数据,减少下游存储介质访问等。

首先,我们要抉择remote cache还是local cache, remote cache通常以中间件的形式在其mem中存储,服务集群中的各个节点都可以通过相同的key访问remote cache拿到数据;local cache则采用该服务的内存资源,服务集群的各个节点存储自己所需要的数据,各个节点的key分布各不相同(随着业务而定)。

其次,该以什么形式存储缓存数据,remote cache比较简单,像redis会规定存序列化数据;而local cache属于自由发挥,我们可以直接set一个对象进去,get时也不用反序列化。

那local cache存对象不是一劳永逸吗?既节省耗时又省序列化开销。

Local Cache存对象

简单用golang来释义(省略了error等其他逻辑),实际工作当中,看到了如下代码:

scss 复制代码
// lru cache实现
func (l *lruCache) Set(key string, val *Data) {
    l.lock.Lock()
    defer l.lock.Unlock()
    
    l.Set(key, val) 
}

func (l *lruCache) Get(key string) *Data {
    l.lock.Lock()
    defer l.lock.Unlock()
    
    return l.Get(key)
}

// 业务
data := l.Get(key)
// 拿到data,继续写逻辑
...

可以看到,local cache存了对象,看起来没啥问题,因为从cache里拿到对象继续写业务逻辑,也对并发场景用mutex进行了处理。

注意点:怎么保证从cache里拿到的对象是immutable?

如果仔细看就会发现,我虽然在cache实现里用锁做了控制,但我拿到的data指针是不可控的,其他人很可能就改了里面的数据。

kotlin 复制代码
// 业务
data := l.Get(key)
// 拿到data,我要改里面的value
...
data.value = b
...

这样的情况下,cache里的数据也被更改,在并发环境中甚至会热key会被频繁更改,导致线上问题。 当然,像C++/Java为对象和成员变量提供了些immutable语义,但这种设计是否把"锅"甩到了cache方法之外呢? 如果必须要改数据(很有可能过了一阵子有一个新需求),后续业务逻辑根据场景处理浅拷贝/深拷贝,保证cache里的数据不被变更。

Local Cache存序列化数据

存序列化数据就和remote cache实现方式差不多了(error处理等逻辑略过)。

scss 复制代码
// lru cache实现
func (l *lruCache) Set(key string, val *Data) {

    bytes, _ := marshal(&val)
    
    l.lock.Lock()
    defer l.lock.Unlock()
    
    l.Set(key, bytes) 
}

func (l *lruCache) Get(key string) *Data {
    l.lock.Lock()
    bytes, _ := l.Get(key)
    l.lock.Unlock()
    
    d, _:= unmarshal(bytes)
    return d
}

// 业务
data := l.Get(key)
// 拿到data,继续写逻辑
...

这样,后续业务逻辑就不会担心对对象做任何操作,因为相当于进行了一次深拷贝,拿到的就是新的对象。

总结

从上述小的例子可以看出,使用local cache也要注意场景,特别是关注cache中取出来的数据有无变更,导致影响业务逻辑。

相关推荐
2401_857622666 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589366 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没7 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch7 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
杨哥带你写代码9 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
AskHarries9 小时前
读《show your work》的一点感悟
后端
A尘埃9 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23079 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
Marst Code9 小时前
(Django)初步使用
后端·python·django
代码之光_19809 小时前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端