关注功能实现 | 青训营笔记

374 阅读3分钟

关注功能需求分析

关注功能板块可以对别的用户点击关注于取消关注,同时可以看到自己的关注列表以及粉丝列表,与小伙伴共同探讨了一下这个功能该如何实现,首先考虑的是“关注功能”是否是一个高频操作,关注貌似并不像点赞操作这样高频但又是一个常使用的功能,所以我们还是觉得考虑了 主流的实现方法 : 缓存 + 数据库。

关注功能具体实现

关于如何实现关注板块的功能,一开始是使用 :

  • 读取:读缓存,缓存没有则查询数据库,查完数据库更新缓存
    
  • 写入:直接更新数据库,然后删掉缓存
    

这个实现也保证了并发安全和数据的实时性,缓存也成功起到了分担查询数据库压力的功能。但后来我查阅资料加上自己的一些想法 决定去实现一个别的方案(总是实现别人的方案太过无趣):

  • 读取:查缓存,缓存没有查数据库,同时更新缓存(保证其中一个必有数据)
  • 写入:直接更新缓存,数据库由定时任务持久化
  • 持久化:定时持久化进数据库,同时删除持久化进数据库的缓存

写入的更新操作 只有 增加和删除由于redis中我使用的数据类型是 set 同时增加(并发)不会新增同样的记录,同时删除 也不会有问题。这样也保证了并发安全。同时该方案几乎完全是在缓存中获取数据查询数据库的时候相对比较少,所以速度非常快。

缺点:数据不能保证安全,如果在未持久化数据库的时候服务器挂了,那么redis中数据丢失,就没办法持久化进数据库了。而且持久化数据库也可能对服务器造成一定的压力(这个在闲时持久化就行)。最重要的一点其实是 持久化时不分数据的新旧 全部持久化一遍,这样如果在一段时间数据没有更新的情况下 ,持久化操作仍然会全部执行一遍,新增了非常多的不必要操作。

后来查阅资料发现这个方法其实是操作系统 使用的一个方案。但操作系统解决了 多次执行不必要操作 的缺点。操作系统会标记数据的新旧,只去持久化更新过的数据而不持久化旧数据。这样就解决了其中最大的缺点。但这个实现比较难,我就没有实现了。

需要注意的地方

为了保证 数据的实时性缓存中不能仅仅存 关注的id 或 粉丝的id,还需要知道名字 其关注数和粉丝数等信息 所以缓存需要存一个 完备的信息 保证功能的可用性。那么set如何 存一个 JSON 数据呢??以及如何取得这个JSON数据之中需要的字段呢??

这里用到了go-redis包:

// 给go-redis 包自动调用的 序列号与反序列化 函数

func (l *ListUserMsg) MarshalBinary() ([]byte, error) {
   return json.Marshal(l)
}

func (l *ListUserMsg) UnmarshalBinary(data []byte) error {
   return json.Unmarshal(data, l)
}

go-redis会自动调用 这两个方法完成序列化和反序列化 这样就可以set进去 。值得注意的是 get出来的数据还需要进行一次json的反序列化得到其中的字段!!!