【精选】七天手撕分布式缓存之一

项目参考GitHub上的高分项目7days-golang,文章内不一定展示完整代码,文章的目的是分享自己在实现分布式缓存的过程中对具体代码实现的解释与见解,文章的编写的时间均是在项目实现之后,可放心参考,有些地方会加上自己对具体实现的想法,具体会有特殊的标识。

本章目录

  • (1)定义缓存结构体与实现底层功能函数
    • (1.1)前言
    • (1.2)确定实现逻辑
    • (1.3)确定数据结构
    • (1.4)代码实现逻辑

(1)定义缓存结构体与实现底层功能函数

(1.1)前言

这一节的内容主要实现了缓存的底层逻辑,比如:空间占满时如何清理历史数据的算法;插入数据与获取数据;以及结构体的定义等。并没有实现分布式的效果,但后续的功能扩展以性能优化均是基于本章的底层函数和算法进行实现。

(1.2)确定实现逻辑

项目源码中的缓存淘汰算法使用的是LRU(最近最少使用)淘汰策略,区别于LFU(最少使用)淘汰策略,LRU是不考虑历史的访问频率的,是从时间维度考虑最少访问的;LFU是考虑历史访问频率的,因此LFU受到历史数据的影响很大;比如一个key在很早之前经常被访问,但是最近没有访问,采用LFU算法很难将其淘汰,但是使用LRU算法很快就会将其淘汰掉。后续整个项目完成之后,可以多实现几个底层算法逻辑。LRU算法实现的关键在于如何去快速的查找最近最少使用的key,go的contains包提供了双向链表的数据结构,支持的函数功能可以满足之后的数据处理,比如:将数据移至链表头部(这里定义头部front的数据是最新访问的数据,因此尾部的数据就是最不经常访问的数据,在缓存空间用尽时可以直接删除处于尾部的数据)。通过源码可以得知双向链表的Value类型声明为any,因此我们为便于记录(比如空间满后,删除数据时可以获取到被删除数据的key和value),可以在双向链表的value字段中存储数据的key和value,并且存储的数据的value必须是实现了Len()函数的类型,这是因为缓存不仅需要记录数据的键值,也需要实时的更新当前缓存占用的空间大小,否则淘汰算法将无法启动。除了LRU算法的实现逻辑外,主要用于数据存储的数据结构是map,map中value的数据类型应该与双向列表的value的数据类型一致,否则通过map找到的值再去双向链表中定位时,还需要做一层数据转换。
综上: 我们的缓存结构就比较清晰了,分别是一个map,一个双向链表,一个包含key-value的已占用空间大小,一个规定的空间大小,除此之外,我们还可以做一些延伸,比如:源码里使用了删除数据时会触发的函数OnEvicted。

(1.3)确定数据结构

// 缓存整体的数据结构
type Cache struct {maxBytes int64nbytes   int64// list 是双向链表ll *list.List// cache 一个键值对 其中键是key,例如redis中的key,值是一个双向列表,相当于redis的一个key对应的值的列表值cache map[string]*list.Element// optional and executed when an entry is purged.OnEvicted func(key string, value Value)
}// 实际存储在list的element中的value的数据结构
type entry struct {key   stringvalue Value
}// entry中的value必须要实现的接口Len()
type Value interface {Len() int
}

(1.4)代码实现逻辑

注释很详细,有问题评论区友善发问(不是义务分享,请摆正态度)

// 初始化Cache的结构体
func New(maxBytes int64, onEvicted func(string, Value)) *Cache {return &Cache{maxBytes:  maxBytes,ll:        list.New(),cache:     make(map[string]*list.Element),OnEvicted: onEvicted,}
}// Add insert key-value pair into map and push it front of freqList
// 1. how to solve repeat key?
// cover it.
// 2. how to define front and back?
// people define it, in this, the most frequently visited key move to front, vice versa
func (c *CacheLRU) Add(key string, value Value) {// existif ele, ok := c.meMap[key]; ok {// move value to frontc.freqList.MoveToFront(ele)// bind it typeoe := ele.Value.(*Entity)// resizec.occupyLength += int64(value.Len()) - int64(oe.value.Len())// revalueoe.value = value} else {// pushFrontele := c.freqList.PushFront(&Entity{key: key, value: value})// acc sizec.occupyLength += int64(value.Len()) + int64(len(key))// insert elec.meMap[key] = ele}//	 delete the key-value, if list oversizefor c.occupyLength >= c.maxLength {c.Remove()}
}// Remove if the key exist, remove it. if success finish it, return true
func (c *CacheLRU) Remove() bool {ele := c.freqList.Back()if ele != nil {c.freqList.Remove(ele)oe := ele.Value.(*Entity)delete(c.meMap, oe.key)c.occupyLength -= int64(len(oe.key)) + int64(oe.value.Len())if c.onEvicted != nil {c.onEvicted(oe.key, oe.value)}}return true
}// Get if you don't hit the key, response is erred
func (c *CacheLRU) Get(key string) (Value, bool) {// existif ele, ok := c.meMap[key]; ok {// put the key to frontc.freqList.MoveToFront(ele)oe := ele.Value.(*Entity)return oe.value, true}return nil, false
}// Len() calculate the list's length
func (c *CacheLRU) Len() int {return c.freqList.Len()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/174615.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java LeetCode篇-深入了解关于数组的经典解法

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 轮转数组 1.1 使用移位的方式 1.2 使用三次数组逆转法 2.0 消失的数字 2.1 使用相减法 2.2 使用异或的方式 3.0 合并两个有序数组 3.1 使用三指针方式 3.2 使用合…

Spring Cache(缓存框架)

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…

vue 中 js 金额数字转中文

参考:js工具函数之数字转为中文数字和大写金额_js封装工具类函数金额大写-CSDN博客 我使用的框架vol.core。 客户需求要将录入框的金额数字转换成中文在旁边显示,换了几种函数,最终确定如下函数 function changeToChineseMoney(Num) {//判断…

Android Termux SFTP如何实现远程文件传输

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP(SSH File Transfer Protocol)是一种基于SSH(Secure Shell)安全协议的文件传输协议。与FTP协议相比,SFTP使用了…

【24届校招】c++选手还有机会吗?如何选择更好的出路?

一、今年为什么c选手就业形势如此艰难? 去年c岗位的火热,不少c选手拿到高薪offer,今年转c的人群变多,内卷加剧,高学历大佬多如牛毛,很多比较好的c岗位多人投递,僧多肉少。 从行情来说&#xf…

Selenium-Unittest单元测试框架

1、Unittest介绍 为什么要学习单元测试框架 测试用例的组织与运行需要单元测试框架的参与,从而满足不同测试场景的需要,单元测试框架提供了丰富的比较方法:实际结果与预期结果的对比测试结果 单元测试框架提供了丰富的日志:给出测…

livox 半固体激光雷达 gazebo 仿真 | 安装与验证

livox 半固体激光雷达 gazebo 仿真 | 安装与验证 livox 半固体激光雷达 gazebo 仿真 | 安装与验证livox 介绍安装验证 livox 半固体激光雷达 gazebo 仿真 | 安装与验证 livox 介绍 览沃科技有限公司(Livox)成立于2016年。为了革新激光雷达行业&#xf…

MySQL特点和基本语句

MySQL MySQL是一种流行的关系型数据库管理系统,由瑞典MySQL AB公司开发,现属于甲骨文公司(Oracle)旗下产品。MySQL是基于C语言开发的,它具有高性能、可扩展性、易用性等特点,并且支持大量的用户访问。 My…

使用 Kafka 和 Cassandra 构建实时异常检测实验

异常检测是一种跨行业方法,用于发现事件流中的异常情况 - 它适用于物联网传感器、金融欺诈检测、安全、威胁检测、数字广告欺诈和许多其他应用。此类系统检查流数据以检查是否存在异常或违规行为,并在检测到时发送警报以处理这些异常并确定它们是否确实代…

C语言重点编程题——11-20

目录 ★★★★★11.编一个程序,将磁盘中当前目录下名为“ccwl. txt"的文本文件复制在同一目录下,文k件名改为“ccw2. txt 12.编一个名为countc的函数,要求如下:(1)形式参数: array 存放字符串的字符型数组名(2)功能:统计array数组中大写字母的数目;(3)返回值:字符串中…

web:[NPUCTF2020]ReadlezPHP

题目 打开页面显示如下 没发现其他的线索,查看源代码 发现一个网址,访问这个页面查看 进行代码审计 这段代码是一个简单的 PHP 类,名为 HelloPhp。它有两个公共属性 $a 和 $b,并在构造函数中将它们分别初始化为字符串 "Y-m-…

Java 设计模式之命令模式

命令模式 介绍 命令模式是一种行为类设计模式,核心是将每种请求或操作封装为一个独立的对象,从而可以集中管理这些请求或操作,比如将请求队列化依次执行、或者对操作进行记录和撤销。 命令模式通过将请求的发送者(客户端&#x…

Failed to load resource: the server responded with a status of 404 ()

路径问题: 路径省略前面的http://localhost:8080/ 就行了。

中兴交换机:DHCP的配置

一、配置说明 拓扑图 S1是中兴三层核心交换机,作为DHCP Server使用,同时作为网关,PC通过自动获取IP地址接入网络 注意事项: S1全局下需要配置:IP Pool,DHCP Policy,打开DHCP功能 S1接口下需…

Leetcode700 二叉搜索树中的搜索

题意理解: 首先明确二叉搜索树的定义: 根节点的值大于左子树所有节点值,小于右子树所有节点值。 二叉搜索树有其自己的顺序,不需要刻意强调遍历顺序。 解题方法: 递归和遍历都可以用。因为是在树里按照一定的规律找一个…

工大智信智能听诊器的演化及其在现代医疗中的角色

听诊器的演化及其在现代医疗中的角色 听诊器发展史传统听诊器发展背景: 1816年,法国医生勒内拉乐内克为了避免直接将耳朵放在病人身上进行听诊,发明了初代听诊器。 从此,在长达200多年的历史当中,传统听诊器几乎都是按…

Springboot实现增删改差

一、包结构 二、各层代码 (1)数据User public class User {private Integer id;private String userName;private String note;public User() {super();}public User(Integer i, String userName, String note) {super();this.id i;this.userName userName;this.note note;…

2.前端--HTML标签基本概念【2023.11.25】

1.基本语法规范 HTML 标签是由尖括号包围的关键词&#xff0c;例如 <html>。HTML 标签通常是成对出现的&#xff0c;例如 和 &#xff0c;我们称为双标签。有些特殊的标签必须是单个标签&#xff08;极少情况&#xff09;&#xff0c;例如 <br />我们称为单标签。 …

大数据-之LibrA数据库系统告警处理(ALM-37012 MPPDBServer实例双机监听SOCKET异常)

告警解释 当操作系统的其它进程占用双机监听端口号时&#xff0c;产生该告警。 告警属性 告警ID 告警级别 可自动清除 37012 严重 是 告警参数 参数名称 参数含义 ServiceName 产生告警的服务名称 RoleName 产生告警的角色名称 HostName 产生告警的主机名 Ins…

深度学习之基于YoloV3杂草识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习在图像识别领域已经取得了显著的成果&#xff0c;其中基于YOLO&#xff08;You Only Look Once&#xff09…