热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用Go实现Redis之五持久化

写在前面本文实现的Godis代码版本为:v0.1Redis持久化方式RDB持久化BGSAVE和SAVE命令生成RDB文件,存储数据库信息。当服务器启动,RDB文件也会作为原始数据,

写在前面

本文实现的Godis代码版本为:v0.1

Redis持久化方式

RDB持久化

BGSAVE和SAVE命令生成RDB文件,存储数据库信息。当服务器启动,RDB文件也会作为原始数据,加载近服务内存。这里存在一个优先级问题——当AOF持久化是打开状态,优先从AOF文件加载数据、还原数据库状态。

SAVE命令会阻塞服务,而BGSAVE派生独立进程,不会阻塞。同时可以通过选项配置自动执行RDB持久化的周期。

Redis服务端通过记录几个参数(如第一篇提到的server.dirty字段记录了上一次SAVE后经历了多少次数据库修改)维护数据库的修改情况。当周期性的后台操作serverCon执行时,会检查数据库的更新状态是否满足RDB持久化条件,依此保存数据库状态。
注意:RDB的文件对数据库数据的存储,采用的方式是存储键值对。

AOF持久化

前文提到RDB文件保存的是数据本身,而AOF文件存储的是执行的命令转成的协议。可以通过开启Redis的AOF持久化,操作若干命令后,查看appendonly.aof文件了解。
因为是对数据的备份操作,读命令无需记录,只需记录修改型操作。

如果AOF持久化对每次修改命令都计入文件,会多记录一些无效命令。如:

set alpha 123
set alpha 1
set alpha 321
set alpha 123

四条命令是过程,数据库记录的最终值123才是过程的最终结果。
为了避免对同一个key的操作的“无效命令”的记录,Redis有AOF重写机制——读取当前数据状态作为AOF文件要追加的命令记录。

Godis实现AOF持久化

Godis只实现AOF持久化,并且不对命令进行重写归并操作,所有修改操作都会记录进AOF文件。这也意味着,在数据保存阶段,会有很多无效I/O操作;加载阶段,会有很多无效的命令被执行。

数据持久化到磁盘

在Godis的编码中没有使用Redis类似的事件循环,我们在此依赖server.dirty字段作为标识。dirty变化即为持久化的时机。

首先,在命令调用处添加AOF持久化判断,如果dirty变化,则进行持久化:

func call(c *Client, s *Server) {
dirty := s.Dirty
c.Cmd.Proc(c, s)
dirty = s.Dirty - dirty
if dirty > 0 {//dirty变化 进行持久化
AppendToFile(s.AofFilename, c.QueryBuf)
}
}

执行持久化操作的函数AppendToFile也很简单,对文件追加写,并且即刻关闭:

func AppendToFile(fileName string, content string) error {
// 以只写的模式,打开文件
f, err := os.OpenFile(fileName, os.O_WRONLY|syscall.O_CREAT, 0644)
if err != nil {
log.Println("log file open failed" + err.Error())
} else {
n, _ := f.Seek(0, os.SEEK_END)
_, err = f.WriteAt([]byte(content), n)
}
defer f.Close()
return err
}

最后,在修改型命令(如set命令)的实现处,添加对server.dirty的更新。

func SetCommand(c *Client, s *Server) {
···
s.Dirty++
···
}

我们来测试下效果,重新编译godis-server.go,并执行set alpha 123

《用Go实现Redis之五持久化》

已经成功在文件中写入了命令协议。

服务启动加载数据

持久化数据从文件加载进内存的方式是模拟客户端执行命令,逐条将AOF文件命令发送给服务端。

func LoadData() {
c := godis.CreateClient()
pros := core.ReadAof(godis.AofFilename)
for _, v := range pros {
c.QueryBuf = string(v)
err := c.ProcessInputBuffer()
if err != nil {
log.Println("ProcessInputBuffer err", err)
}
godis.ProcessCommand(c)
}
}

core.ReadAof将AOF文件读入内存,分条存储。而后的ProcessCommand在set/get命令实现处有介绍,不再说明。

集成测试

关闭服务端,重新启动服务端,直接在客户端执行get alpha,查看是否能获取之前set的值:

《用Go实现Redis之五持久化》

查验AOF文件,没有读命令get相关的记录。

本篇问题

伪客户端执行时不要执行持久化操作,对Client结构增加伪终端标志位,用于持久化判断:

func LoadData() {
c := godis.CreateClient()
c.FakeFlag = true
···
}

小结

没有下集预告了。
这五篇短文的初衷是记录在学习GO时写的小demo,结果花在其他语言之前的精力超出了预算,所以在那以后也没有再继续开发Godis的新feature。

明天在公司的工作迎来忙碌的项目改造期,趁着今天端午小长假最后一天,了解了V0.1版本。
不过,在不久的将来,也许下个小长假,会将前文提到过的key过期、网络优化、API开发、Stream等新的feature和优化公之于众。
欢迎讨论。


推荐阅读
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了Windows Vista操作系统中的用户账户保护功能,该功能是为了增强系统的安全性而设计的。通过对Vista测试版的体验,可以看到系统在安全性方面的进步。该功能的引入,为用户的账户安全提供了更好的保障。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • phpcomposer 那个中文镜像是不是凉了 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
四海承风2502893247
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有