Redis最全详细学习

📅 发布时间:2026/7/12 19:29:03 👁️ 浏览次数:
Redis最全详细学习
1. redis介绍1.1. 什么是redisRedis是用C语言开发的一个开源的高性能键值对key-value数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求Redis支持的键值数据类型字符串类型散列类型 (对应Java中的Object它主要用来存储对象)列表类型 List集合类型 (Set)有序集合类型。 (TreeSet)1.2. redis的应用场景缓存数据查询、短连接、新闻内容、商品内容等等。最多使用分布式集群架构中的session分离。聊天室的在线好友列表。任务队列。秒杀、抢购、12306等等应用排行榜。网站访问统计。数据过期处理可以精确到毫秒2. Redis的安装2.1 在Windows上安装Redis官方只提供了Linux和macos的版本并没有提供Windows安装包但是微软的github仓库中我们可以下载到Windows上可用的Redis程序包但已经很久没有更新建议仅用来作为开发练手不要用于实际的生产环境中。下载地址 https://github.com/microsoftarchive/redis/tags下载后直接解压就可以用了2.2 在Linux上安装redis是C语言开发建议在linux上运行示例使用CentOS7作为安装环境。安装redis需要先将官网下载的源码进行编译编译依赖gcc环境如果没有gcc环境需要安装gccyum install gcc-c阿里云的CentOS7默认已经内置了gcc可以跳过这一步下载redis从官网下载http://download.redis.io/releases/redis-5.0.5.tar.gz将redis-5.0.5.tar.gz拷贝任意路径下如 /home/john/opt/解压源码cd /home/john/opt/ tar -zxvf redis-5.0.5.tar.gz进入解压后的目录进行编译安装cd /home/john/opt/redis-5.0.5/src make # 编译源代码 make install # 安装 # 上面两步也可以直接通过 make make install两步并一步执行Redis默认的安装目录是/usr/local/bin 我们在执行make install命令时添加prefix参数可修改默认安装位置如 make PREFIX/usr/local/redis install3. redis单机启动redis.conf是redis的配置文件默认在redis源码包解压后的根目录有一份redis.conf文件我们可将其拷贝一份到上一步中redis的安装目录cp /home/john/opt/redis-5.0.5/src/redis.conf /usr/local/bin我们装完redis以后默认的安装路径是/usr/local/bin系统会自动来此目录寻找命令所以我们不需要在配置环境变量在任意目录都可以使用redis相关的命令如redis-server、redis-cli3.1. 前端模式启动启动命令redis-server /usr/local/bin/redis.conf通过上面的命令启动redis将以前端模式启动前端模式启动的缺点是ssh命令窗口关闭则redis-server程序结束不推荐使用此方法。3.2. 后端模式启动3.2.1 开启远程连接配置文件redis.conf注释掉 bind 127.0.0.1这行关闭保护模式 将protected-mode yes 改成 protected-mode no3.2.2 添加密码验证放开 # requirepass foobared 这行注释将后面的foobared改成你自己需要设置的密码客户端连接时需要添加-a 参数指定密码才能连上来。3.2.3 开启后台守护进程运行模式将 # daemonize no 这行放开注释 并且改成 yes Redis server将以后台方式运行。3.2.4 指定日志文件将 logfile “” 改成 logfile “你需要的redis日志文件名称” 默认的空字符串代表输出到前端控制台标准输出修改redis.conf配置文件 daemonize yes 以后端模式启动。3.2.5 启动启动命令和前端启动一样只不过控制台不会输出任何信息而且命令结束如果没有异常会马上退出。5. redis集群5.1. 集群原理5.1.1. redis-cluster架构图架构细节:所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.节点的fail是通过集群中超过半数的节点检测失效时才生效.客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node-slot-value Redis 集群中内置了 16384 个哈希槽当需要在 Redis 集群中放置一个 key-value 时redis 先对 key 使用 crc16 算法算出一个结果然后把结果对 16384 求余数这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽redis 会根据节点数量大致均等的将哈希槽映射到不同的节点5.1.2. redis-cluster投票:容错!投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.什么时候整个集群不可用(cluster_state:fail)如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态如果集群超过半数以上master挂掉无论是否有slave集群进入fail状态.当集群不可用时,所有对集群的操作做都不可用收到((error) CLUSTERDOWN The cluster is down)错误5.3. 创建集群5.3.1. 集群结点规划这里在同一台服务器用不同的端口表示不同的redis服务器(伪集群)如下主节点192.168.101.3:7001 192.168.101.3:7002 192.168.101.3:7003 从节点192.168.101.3:7004 192.168.101.3:7005 192.168.101.3:70065.3.2 修改配置修改redis.conf配置文件port 7001 # 将每个节点的端口号改成不一样的(因为同一台机器上一个端口只能被一个进程绑定) cluster-enabled yes #是否开启集群模式 cluster-config-file nodes.conf #集群配置文件名称 cluster-node-timeout 5000 #集群中节点间投票通信的超时时间 appendonly yes #配置集群中当前节点仅开启AOF持久化模式 pidfile /var/run/redis_7001.pid #将pid文件改成不同的名称建议和当前节点的端口号对应5.3.3 创建集群目录在/usr/local下创建redis-cluster目录其下创建7001、7002。。7006目录如下将redis安装目录bin下的文件拷贝到每个700X目录内并且将配置文件也拷贝一份到每个700X目录cp /usr/local/bin/redis/redis* /usr/local/redis-cluster/7001 cp /home/john/opt/redis-5.0.5/src/redis.conf /usr/local/redis-cluster/7001修改每个700X目录下的redis.conf配置文件中的端口号和pid文件路径5.3.4. 启动每个节点redis服务进入/usr/local/redis_cluster目录下编写启动集群脚本start_redis_cluster.shcd /usr/local/redis_clustervim start_redis_cluster.sh#!/bin/bash work_dirpwd echo 开始启动redis集群中的每个节点 for idx in {1..6} do cd $work_dir cd ./700$idx ./redis-server ./redis.conf if [ $? ! 0 ] then echo 启动700$idx节点失败停止启动集群 exit 1 fi echo 启动700$idx done echo 所有集群节点启动完成编辑完成后按ESC切换到命令模式 输入ZZ 或者 :wq保存退出。此处可能需要给此文件加权限启动Redis集群中所有节点./start_redis_cluster.sh查看redis进程ps aux | grep redis5.3.4. 执行创建集群命令Redis 5开始集群不需要依赖Ruby官方直接提供了集群管理支持redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006–cluster-replicas 1注意这里用127.0.0.1仅适用于在本机练习集群搭建真实环境下需要换成外公网IP否则无法远程连接到你的redis集群命令说明redis集群至少需要3个主节点每个主节点有一个从节点总共6个节点–cluster-replicas指定为1表示为集群中每个master都指定一个slave也就是说上面6个节点会有3个主节点和对应的3个从节点如果一切正常最后会看到如下输出[OK] All 16384 slots covered.可能会遇到的错误错误一如果创建redis集群的时候ip用的是127.0.0.1那么你在用Java客户端远程操作Redis集群的时候会死活连不上一直是报127.0.0.1:7001无法连接解决办法创建Redis集群时创建命令中传入的节点IP参数列表使用外部可以访问的IP错误二如果执行时报如下错误[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0解决方法是删除生成的配置文件nodes.conf如果不行则说明现在创建的节点包括了旧集群的结点信息需要删除redis的持久化文件后再重启redis比如appendonly.aof、dump.rdb5.4. 停止Redis集群在/usr/local/redis_cluster目录下创建脚本文件stop_redis_cluster.sh输入以下内容#!/bin/bash work_dirpwd count0 err_count0 echo 开始停止redis集群 for idx in {1..6} do cd $work_dir cd ./700$idx ./redis-cli -c -p 700$idx shutdown if [ $? ! 0 ] then echo 停止700$idx节点失败 let err_count fi echo 停止700$idx节点 let count done echo Redis集群一共有$count个节点成功停止expr $count - $err_count个节点有$err_count个节点停止失败.执行此脚本可以停止redis集群5.5. 查询集群信息集群创建成功登陆任意redis结点查询集群中的节点情况。客户端以集群方式登陆说明./redis-cli -c -h 192.168.101.3 -p 7001其中-c表示以集群方式连接redis-h指定ip地址-p指定端口号5.5.1 查看集群状态相关命令cluster nodes 查询集群结点信息cluster info 查询集群状态信息5.6. 添加主节点集群创建成功后可以向集群中添加节点下面是添加一个master主节点添加7007节点参考集群节点规划章节添加一个“7007”目录作为新节点。Redis 5 添加主节点命令语法redis-cli –cluster add-node 要添加节点的ip:端口 集群中当前存在的任何一个节点的ip和端口示例redis-cli --cluster add-node 10.10.14.166:7006 10.10.14.166:7000输出结果查看集群结点发现7007已添加到集群中注意新添加的master node有以下两个特征由于它没有分配hash槽所以该节点无法存储任何数据由于它没有分配hash槽所以在其他从节点要升级成主节点的过程中该节点不参与投票没有投票权5.6.1. hash槽重新分配添加完主节点需要对主节点进行hash槽分配这样该主节才可以存储数据。redis集群有16384个槽集群中的每个结点分配自已的槽通过查看集群结点cluster nodes命令可以看到槽占用情况。 可以看到新添加的7007节点并没有分配到hash槽给刚添加的7007结点分配槽第一步连接上集群redis-cli --cluster reshard 127.0.0.1:7001 #连接集群中任意一个可用结点就行第二步输入要分配的槽数量输入 500表示分配500个槽第三步输入接收槽的结点id这里准备给7007分配槽通过cluster nodes查看7007结点id为15b809eadae88955e36bcdbb8144f61bbbaf38fb输入15b809eadae88955e36bcdbb8144f61bbbaf38fb第四步输入源结点id这里输入all第五步输入yes开始移动槽到目标结点id至此新添加的7007 master节点的hash槽就分配完毕可以存储数据了关于Redis 集群的hash slots相关知识可以参阅redis hash slot虚拟桶Redis Cluster及hash slot 算法5.7. 添加从节点集群创建成功后可以向集群中添加节点下面是添加一个slave从节点。添加7008从结点将7008作为7007的从结点。Redis 5中添加从节点命令语法redis-cli –cluster add-node 要添加节点的ip:端口 集群中任意已有master的ip和端口 --cluster-slave [--cluster-master-id masterid]示例添加一个从节点不指定目标主节点redis-cli --cluster add-node 10.10.14.166:7008 10.10.14.166:7001 --cluster-slave注意该命令只是向集群中添加了一个从节点但并没有指名要作为哪个master node的从节点Redis集群会将其添加到集群中随机挑一个从节点较少的master node上作为其从节点添加一个从节点并指定所属主节点redis-cli --cluster add-node 10.10.14.166:7008 10.10.14.166:7001 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e我们通过增加了一个cluster-master-id参数指定从节点要添加到哪个主节点上。主节点的ID可以通过cluster nodes查看到注意如果原来该结点在集群中的配置信息已经生成cluster-config-file指定的配置文件中如果cluster-config-file没有指定则默认为nodes.conf这时可能会报错[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0解决方法是删除生成的配置文件nodes.conf删除后再执行添加从节点指令查看集群中的结点可以发现刚添加的7008为7007的从节点5.8. 删除结点Redis5以后删除节点命令语法redis-cli --cluster del-node ip:port node_id注上面的ip:port为集群中存在的任意节点node_id是你要删除的节点的id示例redis-cli --cluster del-node 10.10.14.166:7001 d3b977fd46386db84fd85b9240deb602087c8617删除已经占有hash槽的结点会失败报错如下[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.需要将该结点占用的hash槽分配出去参考hash槽重新分配章节。6. Redis持久化策略6.1 RDB快照模式缺省情况情况下Redis把数据快照存放在磁盘上的二进制文件中文件名为dump.rdb。你可以配置Redis的持久化策略例如数据集中每N秒钟有超过M次更新就将数据写入磁盘或者你可以手工调用命令SAVE或BGSAVE。6.1.1 工作步骤Redis forks子进程开始将数据写到临时RDB文件中当子进程完成写RDB文件用新文件替换老文件当RedisServer重新启动时读取RDB文件恢复到内存中。6.1.2 配置参数save 900 1 #在900秒(15分钟)之后如果至少有1个key发生变化则dump内存快照。 save 300 10 #在300秒(5分钟)之后如果至少有10个key发生变化则dump内存快照。 save 60 10000 #在60秒(1分钟)之后如果至少有10000个key发生变化则dump内存快照。 # save # 将上面三个配置注释掉只保留一个save 代表禁用RDB快照模式6.2 AOF模式快照模式并不十分健壮当系统停止或者无意中Redis被kill掉最后写入Redis的数据就会丢失。这对某些应用也许不是大问题但对于要求高可靠性的应用来说Redis就不是一个合适的选择。Append-only-file 模式是另一种选择。你可以在配置文件中打开AOF模式6.2.1 工作步骤Redis客户端发送读写命令RedisServer接收并执行命令同时同步记录命令到AOF文件中Redis重新启动时读取AOF文件执行其中每一条指令完成数据恢复6.2.2 配置参数# appendfsync always # 命令过来后立刻写入AOF文件会强制flush操作系统IO缓冲 appendfsync everysec # 默认策略 每秒钟将缓存的命令写入到AOF文件中 # appendfsync no # 关闭AOF备份6.3 RDB模式与AOF模式的对比6.3.1 RDB模式的优点一旦采用该方式那么你的整个Redis数据库将只包含一个文件这对于文件备份而言是非常完美的。比如你可能打算每个小时归档一次最近24小时的数据同时还要每天归档一次最近30天的数据。通过这样的备份策略一旦系统出现灾难性故障我们可以非常容易的进行恢复。对于灾难恢复而言RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。性能最大化。对于Redis的服务进程而言在开始持久化时它唯一需要做的只是fork出子进程之后再由子进程完成这些持久化的工作这样就可以极大的避免服务进程执行IO操作了。相比于AOF机制如果数据集很大RDB的启动效率会更高。6.3.2 RDB模式的缺点如果你想保证数据的高可用性即最大限度的避免数据丢失那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象此前没有来得及写入磁盘的数据都将丢失。由于RDB是通过fork子进程来协助完成数据持久化工作的因此如果当数据集较大时可能会导致整个服务器停止服务几百毫秒甚至是1秒钟。6.3.3 AOF模式的优点该机制可以带来更高的数据安全性即数据持久性。Redis中提供了3中同步策略即每秒同步、每修改同步和不同步。事实上每秒同步也是异步完成的其效率也是非常高的所差的是一旦系统出现宕机现象那么这一秒钟之内修改的数据将会丢失。而每修改同步我们可以将其视为同步持久化即每次发生的数据变化都会被立即记录到磁盘中。可以预见这种方式在效率上是最低的。至于无同步无需多言我想大家都能正确的理解它。由于该机制对日志文件的写入操作采用的是append模式因此在写入过程中即使出现宕机现象也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题不用担心在Redis下一次启动之前我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。如果日志过大Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上我们也可以通过该文件完成数据的重建。6.3.4 AOF模式的缺点对于相同数量的数据集而言AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。根据同步策略的不同AOF在运行效率上往往会慢于RDB。总之每秒同步策略的效率是比较高的同步禁用策略的效率和RDB一样高效。二者选择的标准就是看系统是愿意牺牲一些性能换取更高的缓存一致性aof还是愿意写操作频繁的时候不启用备份来换取更高的性能待手动运行save的时候再做备份rdb。rdb这个就更有些 eventually consistent的意思了。如果RDB文件和AOF同时存在当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件完整7. 通过SpringBoot操作redis注 下面的教程以最新的SpringBoot版本 2.2.0为例parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.2.0.RELEASE/version /parent7.1. SringBoot操作单机版Redis7.1.1 引入依赖!-- SpringBoot2以后默认的redis客户端已经由jedis改成了lettuce下面依赖会把lettuce-core也添加进来 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency !-- 如果项目中用到了redis连接池需要添加如下依赖 -- dependency groupIdorg.apache.commons/groupId artifactIdcommons-pool2/artifactId /dependency7.1.2 SpringBoot配置application.ymlspring: redis: host: www.taotao.com # port: 6379 # 如果端口号不是默认端口需要制定 # password: xxx # 如果redis服务端开启了口令验证需要添加 lettuce: pool: # 如果使用redis连接池需要添加apche的common-pool2依赖 max-idle: 2 max-wait: 1000ms7.1.3. Java代码通过创建单实例jedis对象连接redis服务如下代码Slf4j SpringBootTest public class TestRedisClient { Autowired private StringRedisTemplate redisTemplate; Test public void testRedis() { SetString keys redisTemplate.keys(*); log.info(操作前存在的keys: keys); String key lanou_F4; redisTemplate.opsForList().rightPushAll(key, new String[]{宋超, 国胜, 国伟, 高飞}); long size redisTemplate.opsForList().size(key); log.info(当前key值的数量 size); ListString values redisTemplate.opsForList().range(key, 0, size); log.info(当前 key 的值 values); keys redisTemplate.keys(*); log.info(操作后存在的keys: keys); } }7.2. SpringBoot操作Redis集群7.2.1. 引入依赖dependencies !-- 添加spring-boot-starter-data-redis依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId !-- 排除掉lettuce客户端相关依赖 -- !-- lettuce客户端连接阿里云上自建的redis集群会有连接超时的问题 -- exclusions exclusion groupIdio.lettuce/groupId artifactIdlettuce-core/artifactId /exclusion /exclusions /dependency !-- 替换成jedis客户端 -- dependency groupIdredis.clients/groupId artifactIdjedis/artifactId /dependency !-- redis连接池依赖 -- dependency groupIdorg.apache.commons/groupId artifactIdcommons-pool2/artifactId /dependency /dependencies7.2.2. SpringBoot配置application.ymlspring: redis: jedis: pool: # 配置redis连接池相关参数 max-idle: 2 max-active: 10 min-idle: 1 cluster: nodes: teacher.lanou.com:7001,teacher.lanou.com:7002,teacher.lanou.com:7003,teacher.lanou.com:7004,teacher.lanou.com:7005,teacher.lanou.com:70067.2.3. Java代码SpringBootTest class SpringbootRedisApplicationTests { Autowired private StringRedisTemplate redisTemplate; Test public void testPutKV() { ValueOperationsString, String ops redisTemplate.opsForValue(); ops.set(name, 张三); String name ops.get(name); Assertions.assertEquals(张三, name, 应该返回张三); } Test public void testOpsForList() { ListOperationsString, String ops redisTemplate.opsForList(); ops.rightPush(yanfa3, 王康健); ops.leftPush(yanfa3, 于漫漫); ops.rightPushAll(yanfa3, 李光, 星辰, 鹏杰, 士军); Assertions.assertEquals(6, ops.size(yanfa3), 应该是由6个元素才对); ListString stuNames ops.range(yanfa3, 0, -1); stuNames.forEach((v) - { System.out.println(v); }); } }集群模式只是依赖和配置不同在代码中使用的API没有什么区别7.3. 外部连接不上redis的解决方法由于linux防火墙默认开启redis的服务端口6379并不在开放规则之内所有需要将此端口开放访问或者关闭防火墙。查看防火墙状态sevice iptables status关闭防火墙命令sevice iptables stop如果是修改防火墙规则可以修改/etc/sysconfig/iptables文件8. 系统添加缓存逻辑示例添加缓存逻辑的原则缓存逻辑不能影响正常的业务逻辑执行。8.1. 添加缓存后系统架构