redis入门到高级

    xiaoxiao2025-01-20  7

    什么是redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。底层采用Nio中的多路IO复用的机制。 为什么使用redis 减轻数据库访问压力性能极高 – Redis能读的速度是110000/s,写的速度是81000/s 丰富的数据类型 支持事务可持久化 linux下安装redis 下载 cd /usr/local wget http://download.redis.io/releases/redis-5.0.4.tar.gz 解压 tar -zxvf redis-5.0.4.tar.gz  编译 && 安装 cd redis-5.0.4 make cd src make install PREFIX=/usr/local/redis 移动redis.conf  // 复制redis.conf配置 cp /usr/local/redis-5.0.4/redis.conf /usr/local/redis/bin // 复制sentinel.conf配置文件 --配置redis哨兵机制 cp /usr/local/redis-5.0.4/sentinel.conf /usr/local/redis/bin 配置redis后台启动 // 编辑配置文件 vi /usr/local/redis/bin/redis.conf // 修改配置文件内容 daemonize no 改成 daemonize yes 配置redis可远程连接 // 编辑配置文件 vi /usr/local/redis/bin/redis.conf // 修改配置文件内容 将 bind 127.0.0.1 注释掉 #bind 127.0.0.1 配置redis连接的密码 // 编辑配置文件 vi /usr/local/redis/bin/redis.conf // 修改文件内容如下 在 # requirepass foobared 下一行新增配置: requirepass 123456 如图 :    启动redis // 进入目录 /usr/local/redis/bin // 启动redis ./redis-server /usr/local/redis/bin/redis.conf 查看redis是否启动成功 ps aux | grep redis

     

    redis的常用命令 启动redis  // 启动redis ./redis-server // 启动并加载配置文件 ./redis-server /usr/local/redis/bin/redis.conf // 设置后台启动并指定端口号 ./redis-server /usr/local/redis/bin/redis.conf  --daemonize yes --port 1111    查看是否启动成功  // 查看进程 ps -ef |grep redis // 查看端口号 lsof -i:6379 停止redis // 没密码停止 ./redis-cli shutdown // 有密码停止 ./redis-cli -a 123456 shutdown

     

    客户端密码登录 ./redis-cli auth 123456

     

    查看redis的配置信息 // 登录redis客户端 ./redis-cli auth 123456 // 输入info命令 info 查看密码 //登录客户端后,再获取密码 redis 127.0.0.1:6379> config get requirepass

     

    redis的基本数据类型 字符串类型(String) set aa 123        // 存值 set aa 123 ex 10   // 设置有效期10秒 get aa             // 取值 del aa             // 删除 keys *             // 获取所有 列表类型(List) lpush list aa       // 存值 lpush list aa       // 存值 lrange list 0 10  // 按下标取值 无序集合(Set) 无序,且唯一 sadd aa java    // 存值 sadd aa php     // 存值 smembers aa    // 取值 有序集合(sorted set) 有序,且唯一 zadd cc 1 java    // 存值 zadd cc 2 php    // 存值 zrange cc 0 10 withscores   // 取值 哈希(Hash) hmset person name "admin" age 18 phone "13111111111"   // 存值 hgetall person                                        // 取值 命令文档参考:   https://www.runoob.com/redis/redis-strings.html   

     

    Redis默认的情况下分为16个库

             db0-db15  默认使用db0库

    springboot集成redis 创建springboot项目在pom.xml中引入依赖 <!-- 引入redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>

     

    在application.properties配置redis ###Redis配置 spring.redis.database=0 spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=123456 # 连接池中的最大空闲连接 spring.redis.pool.max-idle=8 # 连接池中的最小空闲连接 spring.redis.pool.min-idle=0 # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active=8 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=-1 # 连接超时时间(毫秒) spring.redis.timeout=5000

     

    创建RedisService.java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * Create by wangxb * 2019-05-27 17:40 */ @Service public class RedisService { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private RedisTemplate redisTemplate; // 存String public void saveString(String key, String value){ stringRedisTemplate.opsForValue().set(key, value); } // 获取String public String getString(String key){ return stringRedisTemplate.opsForValue().get(key); } // 删除 public void delByKey(String key){ stringRedisTemplate.delete(key); } // 存String设置时间 public void saveStringAndTime(String key, String value, Long timeOut){ stringRedisTemplate.opsForValue().set(key, value, timeOut , TimeUnit.SECONDS); } }

     

    mybatis如何使用redis作为缓存    使用@Cacheable注解 // 数据库查询接口 @Mapper public interface EmpMapper { @Select("select * from emp") List<EmpEntity> findAll(); } // controller @RequestMapping("/findAll") @Cacheable(cacheNames = "emp", key = "'findAll'") public List<EmpEntity> findAll() { return empMapper.findAll(); } @Cacheable(cacheNames = "emp", key = "'findAll'")   将从数据库查询的数据保存到redis中,后面都是从redis中查询。 emp表示文件夹  findAll表示 key, 如下图:   

     

    redis过期事件通知 修改服务器redis配置    // 修改配置文件 vi redis.conf // 修改配置文件内容,默认注释掉的 将 # notify-keyspace-events Ex 改成 notify-keyspace-events Ex  开启事件通知,  重启redis创建spingboot项目并整合redis  创建redis监听类 RedisListenerConfig.java  import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.listener.RedisMessageListenerContainer; @Configuration public class RedisListenerConfig { @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); return container; } } RedisKeyExpirationListener.java  import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.stereotype.Component; @Component public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener { public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } /** * Redis的key过期通知事件 */ @Override public void onMessage(Message message, byte[] pattern) { String key = message.toString(); System.out.println("该key: "+key+" 到期失效了!!!"); } }   启动项目测试  提前保存数据并设置时间,查看控制台信息:        原理:        底层是基于发布订阅实现。可以通过配置在集群环境、多个消费者情况下:  不会产生重复监听失效的问题。

     

    redis实现分布式锁 思路 通过redis的setnx命令实现  // 如何当前key没被使用返回1 127.0.0.1:6379> setnx name admin (integer) 1 // 如何当前key已被使用返回0 127.0.0.1:6379> setnx name admin (integer) 0 127.0.0.1:6379> setnx name ben (integer) 0   redis如何存java对象    使用json实现序列化和反序列化 使用StringRedisTemplate.java // 保存 String str = JSONObject.toJSONString(userEntity); redisService.saveString(key, str); // 获取 String str = redisService.getString(key); UserEntity userEntity = JSONObject.parseObject(str, UserEntity.class); 保存的是json字符串将对象实现Serializable.java进行序列化和反序列化  // 使用 RedisTemplate<k, v> // 将UserEntity对象实现Serializable接口 保存二进制文件Resi的主从复制 什么是redis的主从复制    就是多个Redis数据库之间的数据同步优点   实现数据库的读写分离提高服务器的负载能力,主数据库主要进行写操作,而从数据库负责读操作。图解 如图所示:  136作为主库,具有读写功能,从数据库137、138只能读不能写。 当136数据库写入数据时,会同步更新到从数据库137、138中。   配置主从复制  在从数据库137、138的redis.conf配置信息如下:    // 编辑137、138服务器的redis.conf slaveof 192.168.33.136 6379    // 设置136为主数据库   masterauth 123456              // 主数据库如果要密码,这里就需要配置主数据库的密码

     

    配置完成后,可以在136、137、138的redis.cli中输入: info  命令,查看配置的信息配置成功:我们测试在136主数据库,存值时,137、138从数据库去取值 redis的哨兵机制 什么是哨兵机制如图:          当哨兵检测到Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将其中一个Slave升级为新的Master(并更新你的哨兵配置文件), 并让其他的Slave数据库改为复制新的Master; 当客户端试图连接失效的Master,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。    可以在从redis中选择一个服务器作为哨兵。建议配置多台哨兵。哨兵不能实现数据的同步如何配置哨兵机制,我们将137从数据库配置哨兵 // 编辑redis的sentinel.conf配置文件。 vi sentinel.conf ##########修改配置文件的内容, 如下: ############ // 哨兵启动模式为后台启动 默认no daemonize yes // 设置监听主redis的ip、端口 1: 表示多台哨兵的话,只要1台确认主redis宕机则就重新选举 sentinel monitor mymaster 192.168.33.136 6379 1 // 设置主redis密码 sentinel auth-pass mymaster 123456 // 设置等待的超时时间  该改为5000(5秒) sentinel down-after-milliseconds mymaster 30000  // 最多多少个从节点 sentinel parallel-syncs mymaster 2  保存启动redis // 启动redis ./redis-server redis.conf // 启动哨兵 ./redis-sentinel sentinel.conf 

     

    redis事务 Redis 事务可以一次执行多个命令redis事务相关命令

    序号

    命令及描述

    1

    DISCARD 取消事务,放弃执行事务块内的所有命令。

    2

    EXEC 执行所有事务块内的命令。 提交事务

    3

    MULTI 标记一个事务块的开始。  开始事务

    4

    UNWATCH 取消 WATCH 命令对所有 key 的监视。

    5

    WATCH key [key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

    redis的持久化 什么是持久化 就是将内存数据保存到硬盘。 Redis 持久化存储 (AOF 与 RDB 两种模式)   RDB: 以数据文件的形式进行保存备份。  redis默认使用RDBAOF: 以日志文件的形式进行保存备份。    RDB持久化 配置RDB持久化 ################以下为redis.conf的默认配置###################### #持久化数据保存到本地的文件名 dbfilename dump.rdb #持久化数据保存到本地的文件路径 ./表示当前路径 dir ./ #如下为900秒内,有1次变更操作,就会生成rdb数据文件。 #如下为300秒内,有10次变更操作,就会生成rdb数据文件 save 900 1 save 300 10 save 60 10000 #当出现错误时,是否阻塞客户端的操作 默认: yes stop-writes-on-bgsave-error yes #是否启用压缩文件形式保存rdb文件,默认: yes rdbcompression yes

    如上: RDB是以时间进行周期性全量保存dump.rdb数据文件。  默认时间为: 900秒、300秒 、60秒 redis每次启动时,都会自动加载dump.rdb数据文件。    缺点:安全性不高,如果操作了9次且时间还未到,redis挂了,那么之前9次的数据就不会保存。

    AOF AOF即: Append-only file      将每次的操作命令和数据保存到日志文件(不包括查询命令),redis在还原数据时,就会读取该日志文件的所有操作命令和数据在内部重新执行一次。 就和mysql中bin.log类似虽然AOF会造成磁盘 IO 的负荷加重,但是相对可靠安全,所以一般都是使用aof,配置AOF持久化 ##开启aof功能, 默认no appendonly yes ##指定aof文件名称 appendfilename appendonly.aof ##指定aof的同步策略,有三种:always everysec no, 默认为everysec appendfsync everysec

    AOF的同步策略 :   appendfsync always        #表示每次有数据修改时就写入AOF文件,能够保证数据不丢失,但是效率低。   appendfsync everysec     #表示每秒钟同步一次,可能会丢失1s内的数据,但是效率非常高。推荐  appendfsync no               #从不同步

    AOF与RDBAOF 更加安全,可以将数据更加及时的同步到文件中,但是 AOF 需要较多的磁盘 IO 开支,AOF 文件尺寸较大,文件内容恢复数度相对较慢。RDB安全性较差,它是正常时期数据备份以及 master-slave 数据同步的最佳手段,文件尺寸较小,恢复数度较快。 redis的淘汰策略  应用场景  redis在使用内存不足的情况下,就会采用策略清除部分数据,释放部分内存。   redis的六种淘汰策略  noeviction:当内存使用达到阈值的时候,执行命令直接报错  allkeys-lru:在所有的key中,优先移除最近未使用的key。(推荐) volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。 allkeys-random:在所有的key中,随机移除某个key。 volatile-random:在设置了过期时间的键空间中,随机移除某个key。 volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。  配置redis的淘汰策略   默认没有配置,是根据redis申请到的物理空间大小来决定 // 1、编辑redis.conf vi redis.conf // 在配置文件中修改内容 将 # maxmemory <bytes> 比如修改成 maxmemory 100mb 将 # maxmemory-policy noeviction 修改成 maxmemory-policy allkeys-lru    redis如何解决缓存穿透问题    什么是缓存穿透          比如订单查询功能。用一个不存在的订单Id,在redis和数据库中都不存在,这样缓存就是去了意义。 如果用大量不存在的id并发访问,导致缓存无法命中,数据库也查询不,但是每次请求还是要穿透到后端数据库,这样就会造成你的数据库 压力。  如何解决缓存穿透   a. 接口限流  b. 使用布隆过滤器 布隆过滤器原理         采用的是bit(0/1)数组和哈希函数。通过key生成3个hash值,再将hash值锁对应的bit位置改为1。  代码实现    依赖  <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>20.0</version> </dependency> 伪代码 import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import java.util.ArrayList; import java.util.List; /** * @author xiaobo * @Description Bloom * @createTime 2020-03-16 20:58 */ public class Bloom { BloomFilter<Integer> bloomFilter = null; // 获取所有订单id private List<Integer> getAllOrderId(){ List<Integer> orderList = new ArrayList<Integer>(); for (int i = 0; i< 1000000; i++) { orderList.add(i); } return orderList; } public void initBloomFilter(){ // 提前获取所有订单id List<Integer> orderIds = getAllOrderId(); // 将订单id存在布隆过滤器容器中 0.01数据越小,数组越大,误判概率也就越小 bloomFilter = BloomFilter.create(Funnels.integerFunnel(), orderIds.size(), 0.01); for (Integer orderId : orderIds) { bloomFilter.put(orderId); } } public void findOrder(Integer id) { // 布隆过滤器判断容器内是否有这个订单id if (!bloomFilter.mightContain(id)) { System.out.println("伪造的订单id...."+id); return ; } System.out.println("开始从redis、mysql查询订单......"+id); } } 测试 public static void main(String[] args) { Bloom bloom = new Bloom(); bloom.initBloomFilter(); bloom.findOrder(1); bloom.findOrder(10000000); }      代码思路:   1) 提前将数据库所有的订单号存在布隆过滤器容器内,这里我是伪造的订单:  1~1000000   2) 在查询时,先判断容器内是否存在,如果不存在,则判断为伪造订单号。否则执行查询.....   布隆过滤器产生的问题          因为布隆过滤器底层采用的时二进制[0 1]数据,会根据key计算hash值的出存放的位置,这样就会导致新的key计算出的hash值与容器内已存放的元素hash产生冲突,这样就会产生误判可能存在。    如何解决这个问题:二进制数组长度设置比较大,可以减少布隆误判的概率。   Redis如何解决缓存雪崩问题 产生原因        如果我们缓存在redis数据过期时间是相同的。这就就会导致在这段时间内,这些缓存同时过期失效,全部请求到数据库中。增加数据库压力。   解决思路   对不同类型的数据,设置不同的有效期。     Redis如何解决缓存击穿问题 产生原因         缓存击穿,就是说某个 key对应的数据访问非常频繁,属于高并发式访问,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,造成数据库访问压力大。解决思路         可以将热点数据设置为永不过期        使用分布式锁,当缓存失效时,只允许一个线程去访问,在缓存到redis中。   Redis Cluster集群 RedisCluster集群的原理         Redis哨兵机制在同步中,要求每个redis节点服务器都要保存master节点的全量数据,冗余的数据比较多;  Redis3.0开始官方推出了集群模式 RedisCluster,采用分片集群模式,可以减少冗余数据。          采用hash槽的原理,预先设定16384个卡槽,并将卡槽分配各个master服务器;通过key进行crc16(key)384 获取余数,余数就是对应的卡槽的位置,然后将数据存放在卡槽对应的服务器上。一个卡槽可以存放多个值,从而将读或者写转发到该卡槽的服务的节点。   缺点:   就是构建该集群模式需要服务器多、成本高。  优点:动态实现服务器的扩容、缩容。 redis的发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。例子:有A、B数据库:启动A的redis-cli输入:SUBSCRIBE redisChat                 // 表示A订阅了redisChat这个频道的消息启动B的redis-cli输入:PUBLISH redisChat "message1"   // 表示B向redisChat这个频道的发送消息 A可以实时获取往redisChat这个频道发送的消息发布订阅相关方法

    序号

    命令及描述

    1

    PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道。

    2

    PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态。

    3

    PUBLISH channel message 将信息发送到指定的频道。

    4

    PUNSUBSCRIBE [pattern [pattern ...]] 退订所有给定模式的频道。

    5

    SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。

    6

    UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道。

    redis的卸载 查看redis服务器  ps aux | grep redis停止进程a kill -9 PID删除相关文件 rm -rf /usr/local/redis                     // 删除安装目录 rm -rf /usr/bin/redis-*                     // 删除所有redis相关的命令脚本
    最新回复(0)