coderZoe的博客 - Redis
type: channel
link: https://coderzoe.com/category/Redis/
items: Redis笔记——Redis设计与实现
items: Linux部署Redis哨兵模式

Redis笔记——Redis设计与实现
type: item
date: 2022-06-21T01:53:00+00:00
description: Redis设计与实现0. 前言本文主要讲redis底层的实现细节，如redis提供的不同数据对象底层的数据结构是什么样，redis的RDB，AOF，事务是如何实现的。以及大家经常关心的redis为什么是单线程。还有多机数据库下redis是如何做到复制，多个redis是如何分配主从数据库进行交互，还有我们常见的哨兵和redis集群，redis如何实现的哨兵模式和redis集群的实现。文章适合对redis有一定了解，但想继续探究redis底层很多功能到底是如何实现的读者。本文大多内容摘自书籍《Redis设计与实现》，笔者认为这是本非常优秀的书，让人一读就爱不释手。作者真正做到了深入浅出，让很多编程水平一般的读者也能读懂redis的设计与实现，一窥redis的底层。1. 数据结构对redis有一定了解的知道，Redis提供了5种数据对象，分别为字符串对象（REDIS_STRING）、列表对象（REDIS_LIST）、哈希对象（REDIS_HASH）、集合对象（REDIS_SET）和有序列表对象（REDIS_ZSET）。这些对象的底层都是由一定数据结构实现，具体信息如下表：对象类型编码对象REDIS_STRINGREDIS_ENCODING_INT使用整数值实现的字符串对象REDIS_STRINGREDIS_ENCODING_EMBSTR使用embstr编码的简单动态字符串实现的字符串对象REDIS_STRINGREDIS_ENCODING_RAW使用简单动态字符串(SDS)实现的字符串对象REDIS_LISTREDIS_ENCODING_ZIPLIST使用压缩列表实现的列表对象REDIS_LISTREDIS ENCODING LINKEDLIST使用双端链表实现的列表对象REDIS_HASHREDIS_ENCODING_ZIPLIST使用压缩列表实现的哈希对象REDIS_HASHREDIS_ENCODING_HT使用字典实现的哈希对象REDIS_SETREDIS_ENCODING_INTSET使用整数集合实现的集合对象REDIS_SETREDIS_ENCODING_HT使用字典实现的集合对象REDIS_ZSETREDIS_ENCODING_ZIPLIST使用压缩列表实现的有序集合对象REDIS ZSETREDIS ENCODING SKIPLIST使用跳跃表和字典实现的有序集合对象因此，我们先从实现redis的几个数据结构入手，这些数据结构都是构成上述数据对象的基础。1.1 SDS字符串是redis中最基本最常用的一种数据格式，我们常见的数据库的键，部分数据结构的值，如字符串对象的值，字典每个元素的键和值等都是字符串数据格式。在redis中字符串对象一种重要的编码实现是SDS。SDS全称为simple dynamic string即简单动态字符串，redis使用它来存储字符串。在redis中SDS的结构如下：struct sdshdr{ //用于记录buf数组中已使用字节数量 //等于SDS结构所保存字符串的长度 int len; //记录buf数组中未使用字节数量 int free; //字节数组 用于保存字符串 char buf[]; }另外SDS遵循C字符串以空格字符结尾习惯，保存空字符的1字节空间不算在SDS的len属性里。相比于传统的C语言字符串，SDS结构的好处如下：常数复杂度获取字符串长度。C字符串不记录自身的长度信息，所以如果想获取长度需要遍历C字符串直到字符串结尾的空字符为止，时间复杂度O(n)。但SDS在len属性中记录了字符串长度，时间复杂度仅为O(1)。杜绝缓冲区的溢出。假设我们在对两个字符串执行如下函数：char *strcat(char *dest,const char *src);由于C字符串不记录自身长度，因此strcat假定调用者在执行这个函数时，dest分配了足够内存，否则就会造成内存溢出。但SDS的API会在SDS进行修改时先检查SDS空间是否满足修改需求，如果不满足会先将SDS的空间扩展至执行修改所需大小，然后才执行实际的修改。减少字符串修改时带来的内存重分配次数数组长度是固定的，因此在C语言中对一个C字符串增长或缩短都需要对这个新的C字符串进行一次内存重写分配。由于redis字符这一数据结构是数据库中十分基础重要的数据结构，经常被频繁的修改，因此SDS通过未使用空间解决了字符串长度和底层数组长度这一关联。通过未使用空间，SDS实现了空间预分配和惰性空间释放两种策略。空间预分配用于优化SDS字符串增长操作：当一个SDS的API需要对SDS进行修改且需要扩展SDS空间时，程序不仅会为SDS分配修改所必要的空间，还会额外分配一些未使用的空间。如果修改后的SDS长度小于1MB，那么程序分配和len属…

Linux部署Redis哨兵模式
type: item
date: 2022-05-22T05:48:00+00:00
description: Linux部署Redis哨兵模式Redis版本：6.0.6服务器版本：CentOS 7.61. 服务器资源及分配三台服务器，IP分别为：192.168.4.18192.168.4.43192.168.4.34采用一主两从三哨兵的部署模式，即6个Redis服务节点。其中初始时192.168.4.18作为Redis主节点，192.168.4.43与192.168.4.34作为从节点，三个哨兵平均分配在每个服务器上。因此最终服务器资源分配情况如下：192.168.4.18 一个master节点与一个sentinel192.168.4.43 一个slave节点与一个sentinel192.168.4.34 一个slave节点与一个sentinel2. 单机部署会从单机->主从->哨兵一步步的验证。本篇先来说下单机Redis的部署。2.1 下载Redis从Redis官网下载RedisDownload | Redis或者wget http://download.redis.io/releases/redis-6.0.6.tar.gz2.2 解压解压刚才下载的Redis安装包tar -zvxf redis-6.0.6.tar.gz2.3 编译安装进入刚才的解压路径cd redis-6.0.6编译make如果编译过程报了error，如下图这代表你的gcc版本过低，需要升级gcc（因为Redis是C语言写的）。可以参考CentOS 7升级gcc版本 - 姬无华 - 博客园 (cnblogs.com)(49条消息) CentOS升级gcc到高版本（全部版本详细过程）_乞力马扎罗の黎明的博客-CSDN博客_centos 升级gcc升级你的gcc版本，重新执行make指令编译，编译完成后大概如下图安装make PREFIX=/home/redis install关键字PREFIX的作用是编译的时候用于指定程序存放的路径。比如我们现在就是指定了redis必须存放在/home/redis目录。假设不添加该关键字Linux会将可执行文件存放在/usr/local/bin目录。==注：本文档以/home/redis来演示Redis的安装目录，实际用户可根据个人需求将redis的安装在任意目录。==安装完成后，切换到/home/redis目录下，应该可以看到一个bin目录里面都是Redis服务2.4 拷贝配置文件，启动测试将之前解压文件中的redis.conf与sentinel.conf配置文件拷贝到/home/redis下此时/home/redis目录如下：现在让我们启动单机版redis测试是否正常cd /home/redis/bin ./redis-server如果redis启动如下图所示则代表启动正常我们可以启一个redis客户端测试是否能连接正常与正常使用cd /home/redis/bin/ ./redis-cli上图指令若执行正常则代表单机版Redis部署成功3. 主从3.1 拷贝安装文件可以直接将上述/home/redis目录打包复制到其他两个服务器下，其他两从服务器的安装信息与主服务器相同。3.2 修改配置文件修改主节点配置文件，编辑/home/redis下的redis.conf将bind 127.0.0.1改为bind 0.0.0.0修改两个从节点的配置文件，编辑/home/redis下的redis.conf与主节点一样，将bind 127.0.0.1改为bind 0.0.0.0除此以外，从节点需要在配置文件最后加上slaveof 192.168.4.18 63793.3 启动主从并验证修改完成后，按顺序重新启动三个Redis服务192.168.4.18（主）cd /home/redis./bin/redis-server redis.conf192.168.4.43（从）cd /home/redis./bin/redis-server redis.conf192.168.4.34（从）cd /home/redis./bin/redis-server redis.conf此时各个节点的打印日志均应该有一些主从复制的日志信息打印（主从节点打印的日志不同）我们可以测试主从节点是否部署正常192.168.4.18（主）在主节点中使用redis-cli设置一个keycd /home/redis/bin ./redis-cli可以看到我们通过主节点设置了一个<k2,v2> 的一条信息192.168.4.43（从）在从节点中使用redis-cli获取刚才的keycd /home/redis/bin ./redis-cli可以看到我们可以通过从节点获得在主节点设置的k2的信息192.168.4.34（从）在从节点中使用redis-clii获取刚才的keyc…