redis基本原理介绍
点击上方“技术支持联盟”,选择“置顶公众号”
第一时间了解程序员大小事儿
作者: 液态区,没有固定形态,压力越大 喷发越高。
简介:Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。目前redis已经成为系统的标配,本文主要介绍redis相关基本原理。
01Redis基础数据结构
Redis有5中基本数据结构,分别为:string,list,set,hash,zset
String
键值对:set key value
get key
exists key
del key
get key
批量键值对:可以批量对多个字符串进行读写,节省网络消耗开销
mset key value key1 value1
mget key key1
过期和set命令扩展:可以对key设置过期时间,到点自动删除,这个功能常用来控制缓存的实效时间
set key value
expire key seconds
等价于setex key seconds value
setex是具有原子性
setnx key value :如果key不存在就执行set创建,并返回1,如果存在则返回0
原子计数器:如果value值是一个整数,还可以对它进行自增操作,自增是有范围的,范围是signed long的最大最小值,超过这个值,Redis会报错。
set key value 1
incr key
List(列表)
Redis的列表相当于java中的LinkedList,注意它是链表而不是数组,这意味着list的插入和删除操作非常快,时间复杂度为O(1),但是索引定位很慢,时间复杂度为O(n),当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收。
Redis的列表结果常用来做异步队列使用,将需要延后处理的任务结构体序列化成字符串塞进Redis的列表,另一个线程从这个列表中轮询数据进行处理。
rpush key value1 value2 value3
llen key
lpop key
rpop key
hash(字典)
Redis的字段相当于java中的HashMap,它是无序字典,内部实现结构上同java的HashMap一致,同样的数组+链表二维结构。hash也有缺点,hash结构的存储消耗要高于单个字符串。hash字段可以存对象实体类,一个field对应一个value
hset key value
hgetall key
hlen key
hget key filed
User:
Name
Password
usercode
set(集合)
Redis的集合相当于java中的HashSet,它内部的键值对是无序的唯一的,它的内部实现相当于一个特殊的字典,字典中所有的value都是一个值null,当集合中最后一个元素移除之后,数据结构自动删除,内存被回收。
zset(有序集合)
zset相当于java中的SortedSet和HashMap的结合体,一方面它是一个set,保证了内部value的唯一性,另一方面它可以给每个value赋予一个score,代表这个value的排序权重。
模糊查找key命令
keys
全量遍历键,用来列出所有满足特定正则字符串规则的key,当Redis数据量比较大的时候,性能比较差,要避免使用。
scan
渐进式遍历键,scan参数提供了三个参数,第一个是cursor整数值,第二个是key的正则,第三个是遍历的limit,第一次遍历时,cursor值为0,查询的结果第一行为下一次查询遍历的cursor,一直遍历到返回的cursor值为0时结束。
Redis键值对的数据结构
Redis存储键值对实际使用的是hashtable的数据结构
02Redis持久化
RDB快照(snapshot)
在默认情况下,Redis将内存数据库快照保存在名字为dump.rdb的二进制文件中。
也可以对Redis进行设置,让它在N秒内数据集至少有M个改动这个条件被满足,自动保存一次数据集。
AOF(append-only file)
将修改的每一条指令记录进文件,打开以后,每当Redis执行了一个改变数据集的命令时(比如set),这个命令就会被追加到AOF文件的末尾,这样的话,当Redis重新启动时,程序就可以通过重新执行AOF文件中的命令来达到数据的恢复。
Redis4.0混合持久化
混合持久化aof文件结构
03缓存淘汰策略
Redis提供了配置参数maxmemory来限制内存超出期望大小。
当实际内存超出maxmemory时,可以使用一下集中策略。
lru:最久没有使用
lfu:使用频率最少的
ttl:过期时间
04Redis的单线程和高性能
Redis单线程为什么还能这么快呢?因为它所有的数据都在内存中操作,所有的运算都是内存级别的运算,时间基本上在纳秒级别,而且单线程避免了多线程的上下文切换而带来的性能消耗问题,正因为Redis是单线程,所以要小心使用Redis的特定命令(比如比较耗时的keys)。
Redis单线程如何处理那么多并发客户端连接?Redis使用的是IO多路复用,Redis使用epoll来实现IO多路复用,将连接信息和事件放到队列中,一次放到文件事件分派器,事件分派器将事件分发给事件处理器。Nginx也是采用IO多路复用原理。
05Redis缓存高可用集群
Redis主要的两种集群方式
哨兵模式
Redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来控制master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个主节点内存也不宜设置的过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。
高可用集群模式
Redis集群是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片的特性。
Redis高可用集群搭建
Redis集群搭建
修改redis.conf配置文件
daemonize yes#修改为后台运行
port port#分配Redis服务端口
dir path #指定数据文件存放位置,必须要指定不同的目录,不然会丢失数据
cluster-enabled yes #启动集群模式
cluster-config-file nodes-port.conf#集群节点信息文件,此处的数据最好与port一致
cluster-node-timeout 5000 #Redis群集节点不可用的最长时间(不将其视为失败)。如果主节点无法访问的时间超过指定的时间量,则其主节点将对其进行故障转移。此参数控制Redis Cluster中的其他重要事项。值得注意的是,在指定的时间内无法到达大多数主节点的每个节点都将停止接受查询
bind:不配置的话,是所有机器都可以对Redis实例进行访问,如果配置的话,只能是配置的ip可以对Redis实例进行访问
protected-mode no:设置密码的话,需要将保护模式关闭
appendonly yes #开启aof持久化模式
requirepass password#设置Redis访问密码
masterauth password#设置集群节点间访问密码
Redis集群原理分析
Redis cluster将所有数据划分为16384个slots(槽位),每个节点负责其中一部分槽位。当Redis cluster的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将在客户端进行缓存。这样当客户端要查找某个key时,可以直接定位到目标节点,同时因为槽位的信息可能会保存在客户端看与服务端不一致的情况,还需要纠正机制来实现槽位信息的校验调整。
槽位定位算法
cluster默认会对key值使用crc16算法进行hash得到一个整数值,然后用这个整数值对16384进行取模来得到具体槽位。HASH_SLOT=CRC16(key) mod 16384
跳转重定位
客户端向一个错误的节点发送指令,该节点会发现指令的key所在的槽位并不归自己管理,这时它会向客户端发送给一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连接这个节点来获取数据,客户端 指令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有key将使用新的槽位映射表。
网络抖动
网络抖动,突然之间部分连接变得不可使用后很快又恢复正常,为了解决这种问题,Redis cluster提供了一种选项cluster-node-timeout,表示当某个节点持续timeout的时间失联时,才可以认定该节点出现故障,主从切换,如果没有这个选项,网络抖动会导致主从频繁切换
06Redis高可用集群及水平扩展
查看Redis集群的命令帮助
1)create:创建一个集群环境
2)call:可以执行Redis命令
3)add-node:将一个节点添加到集群中,第一个参数为新节点的ip:port,第二个参数为集群中任意一个已经存在的节点的ip:port
4)del-node:移除一个节点
5)reshard:重新分片
6)check:检查集群状态
7)rebalance:平衡节点,参数ip:host为集群中任意一个已经存在的节点
增加Redis实例
1、配置redis.conf
2、启动redis实例
3、添加主节点
4、分配槽位信息
5、添加从节点
删除Redis实例
1、需要先删除从节点
2、分配需要删除主节点的槽位信息
3、删除主节点
Redis集群选举原理分析
当slave发现自己的master变为fail状态时,便尝试进行Failover,希望成为新的master,由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点的过程,其过程如下:
1、slave发现自己的master为fail
2、将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST信息
3、其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack
4、尝试failover的slave收集FAILOVER_AUTH_ACK
5、超过半数后变成新的master
6、广播Pong通知其他集群节点
从节点并不是主节点已进入FAIL状态马上尝试发起选举,而是有一定的延迟,一定的延迟保证我们等待fail状态在集群中传播,slave如果立即尝试选举,其他master获取尚未意识到fail状态,可能会拒绝投票
延迟公式:DELAY=500ms+random(0~500ms)+SLAVE_RANK*1000ms
SLAVE_RANK标识slave已经从master复制数据的总量的rank,rank越小代表已经复制的数据越新,这种方式下,持有最新数据的slave将会首先发起选举。
历史文章
解决方案:
spring-session集成redis问题
通过分析Nginx服务器日志统计用户流量并预警
加密与认证技术
【双十一钜惠:科技人的专属保障】移动端交互速度保证 ——影像上传优化
【双十一钜惠:科技人的专属保障】移动端认证保障 ——非对称加密及jwt应用
系统安全建设小经验
公共组件-需求自动录入TAPD
Python初体验
HTML5实现自定义键盘及使用
Sentinel限流
基于公有云实时音视频通道的构建音视频组件方法与实战经验
分布式定时任务调度探讨
阿里云OSS JavaAPI分享
Jmeter压测的使用
API接口安全优化浅谈
基于idea将传统应用maven化改造实践
安全漏洞预扫小工具
Nacos作为注册中心,配置中心部署方案
Rancher+K8S简化学习环境搭建方案
Excel大数据量解析优化方案
Sharding-JDBC个性化分表方案
基于JWT的接口权限认证
Spring Cloud Gateway实现限流
公网发布的通用技术解决方案
Nginx结合Lua实现限流
Mysql数据同步Canal方案
Weblogic部署基于Spring Cloud项目应用实例
智能验证码解析java语言实现
数据库的演绎与变迁-下架最后一台小型机
关于struts架构通过引入spring包实现dubbo调用测试的未来式
架构系列:
双十一钜惠:科技人的专属保障】如何保障移动端活动的稳定运转?——移动端基础平台建设的经验分享
【双十一钜惠:一个有温度的技术公众号】科技人需要什么样的保障
架构师入门系列:架构三板斧“缓存,消息,异步”
监控&运维
redis监控工具-redislive
微服务链路追踪工具 Apache SkyWalking部署与实践
快速发现生产环境SQL问题
Grafana-业务数据监控实践
自动化运维能力提升
服务器监控及问题定位排除
基于Spring Boot Admin告警之应用状态告警
Ansible在自动化运维中的使用
自助迁发分支工具
大数据
基于CDH集群的大数据项目的优化总结
Oracle实时同步大数据平台解决方案
实时流关联维表解决方案
中间件
浅谈Elasticsearch的资源分配
Apache Kafka使用规范Elasticsearch安装及使用
SSDB介绍及使用
RabbitMq使用简单介绍
Spring Cloud常用组件介绍
前端
ESLint + Prettier 规范前端代码
Vue.js对WinXP系统对兼容性
关于采集操作系统、浏览器版本的设计方案及一些浏览器兼容性问题处理
安卓动态加载SO文件
对浏览器的理解及兼容移动端H5本地化方案调研和实践
自适应网页设计
短信/浏览器唤起APP方案
基础知识
Sonar简介
JVM基础系列1:JVM内存模型介绍
JVM基础系列2:JVM配置参数和Java内存模型
JVM基础系列3 虚拟机字节码执行引擎
开发规范
Java异常处理规范
战略方向
金融保险系统开源浪潮下机遇与挑战
项目实战
运维工作要学会“偷懒”
“用户思维+中台架构”快速搭建金融宝app
多维分保的应用探索
用文化指引自身的成长之路 -2020年技术成长心得分享
从工作中探寻自身的成长之路
从《平凡的荣耀》到记一次兼容性改造优化后的技术感悟
客户为中心,统筹协调,把控风险
让我们的管理看的见
END请识别下方二维码,关注 技术支持联盟
欢迎加入redis技术交流,请扫码进群