Redis-学习笔记

Redis-学习笔记

  • 其他
  • 重要脚本
  • Redis协议
  • Redis 的安装
    • Ubuntu安装Redis
    • Docker 安装 Redis
      • 1. docker拉取redis镜像
      • 2. 使用redis镜像,启动并运行redis容器
      • 3. 连接docker中的redis
        • 直接从Docker容器进入Redis
        • redis desktop manager 连接 docker 中的 redis
  • Redis配置文件解析
    • 注意事项
  • Redis 客户端
    • Jedis
    • Redission
  • Golang整合Redis
  • SpringBoot整合Redis
  • Redis有哪些数据类型?并分别说明其应用场景
    • String
    • Hash
    • List
    • Set
    • SortedSet
  • Redis 有哪些典型的应用场景?
    • 1. Redis 有哪些典型的应用场景?
    • 2. 如何用 Redis 实现分布式锁?
      • 2.1 如何用 Redis 实现分布式锁?
      • 2.2 如果在 setnx 之后、设置 expire 之前,redis 进程意外 crash 或者系统要重启维护,这时会发生什么情况?
      • 2.3 如何解决该问题?
    • 3. 如何用Redis实现消息队列?
      • 3.1 如何用Redis实现消息队列?
      • 3.2 当 lpop 没有消息时,如果不用 sleep 进行休眠,又该怎么处理?
      • 3.3 如何生产一次消费多次呢?
      • 3.4 Pub/Sub有什么缺点?
      • 3.5 Redis如何实现延时队列?
  • 缓存雪崩 vs 缓存穿透 vs 缓存击穿
    • 如果有大量的key需要设置同一时间过期,一般需要注意什么?
    • 缓存雪崩
      • 解决方案
    • 缓存击穿
      • 解决方案
        • 1. 加"互斥锁"
        • 2. 提前加"互斥锁"
        • 3. 设置"永不过期"
        • 4. 资源保护
    • 缓存穿透
      • 解决方案
  • MySQL里有2000W的数据,redis中只存20W的数据,如何保证Redis中的数据都是热点数据?
    • Redis 有哪些数据淘汰策略呢?你能详细说明一下吗?
    • 参考文档
  • 如何保证缓存与数据库双写时的数据一致性?
  • 如何解决Redis的并发竞争key问题?
  • 怎么理解Redis事务?
  • Redis事务?
  • Redis相比memcached有哪些优势?
  • Redis和memcached的区别?
  • Redis持久化机制(怎么保证Redis挂掉之后再重启数据可以进行恢复?)
  • 修改配置不重启Redis会实时生效吗?
  • 如何选择合适的持久化方式?
  • Redis提供哪几种持久化方式?
  • Redis常见性能问题和解决方案?
  • 一个Redis实例最多能存放多少的keys?List/Set/Sorted Set它们最多内存放多少元素?
  • Redis是单线程的,如何提高多核CPU的利用率?
  • Redis的内存用完了会发生什么?
  • 都有哪些办法可以降低Redis的内存使用情况呢?
  • Redis的内存占用情况怎么样?
  • Redis与其他key-value存储有什么不同?
  • 支持一致性哈希的客户端有哪些?
  • Twemproxy是什么?
  • 分布式Redis是前期做还是后期规模上来了再做好?为什么?
  • Redis持久化数据和缓存怎么做扩容?
  • Redis分区有什么缺点?
  • 你知道有哪些Redis分区实现方案?
  • 为什么要做Redis分区?
  • Redis如何做大量数据插入?
  • Redis回收进程如何工作的?
  • Redis如何做内存优化?
  • Redis事务相关的命令有哪几个?
  • Redis中的管道有什么用?
  • Redis集群之间是如何复制的?
  • Redis集群最大节点个数是多少?
  • Redis集群如何选择数据库?
  • Redis集群会有写操作丢失吗?为什么?
  • Redis集群的主从复制模型是怎样的?
  • 说说Redis哈希槽的概念?
  • Jedis和Redisson对比有什么优缺点?
  • Redis和Redisson有什么关系?
  • Redis支持的Java客户端都有哪些?官方推荐用哪个?
  • Redis集群方案什么情况下会导致整个集群不可用?
  • Redis集群方案应该怎么做?都有哪些方案?
  • Redis key的过期时间和永久有效分别怎么设置?
  • Redis中一个字符串类型的值能存储最大容量是多少?
  • Redis内存回收使用的是什么算法?
  • 为什么要用Redis而不用map/guava做缓存?
  • 为什么要用Redis/为什么要用缓存?
  • 缓存策略的设计
  • 如何利用Redis处理热点数据
  • 谈谈Redis哨兵、复制、集群
  • Redis中如何查看和修改配置?
  • 参考文档

其他

Linux因Redis服务导致关机慢
CentOS 因为 Redis 导致关机异常慢问题解决方法

重要脚本

  • 可通过执行utils/install_server.sh脚本,将redis安装为系统服务,主要配置如下:
6379                                	# 端口
/usr/local/redis-5.0.3/redis.conf   	# 配置文件所在路径
/usr/local/redis-5.0.3/redis.log      	# 日志文件所在路径
/usr/local/redis-5.0.3/data           	# 数据文件所在路径

Redis协议

go-redis源码分析(一):redis协议
Redis协议:RESP
用Go实现Redis之四实现Redis的协议交互

Redis 的安装

Ubuntu安装Redis

sudo apt-get install redis-server

Ubuntu安装redis教程
在Ubuntu中安装Redis

Docker 安装 Redis

1. docker拉取redis镜像

sudo docker pull redis						# docker拉取redis镜像

2. 使用redis镜像,启动并运行redis容器

# -p: 端口映射,格式为 宿主机端口:容器端口;-p 6699:7379,将本机6679端口映射到redis容器的6379端口(默认端口);
# --name: 容器名称;--name docker-redis,设置容器名称为docker-redis;
# -v: 变量设置;-v $PWD/redis.conf:/etc/redis/redis.conf,将本机当前目录的redis.conf文件传递到容器的/etc/redis/redis.conf目录
# -v: 变量设置;$PWD/data:/data,将本机当前目录的/data目录传递到容器的/data目录
# -d: 后台运行容器并打印容器id;-d redis:latest,后台运行并打印容器id,redis:latest为要运行的镜像
# redis-server /etc/redis/redis.conf --appendonly yes: 在容器中执行redis-server启动命令,并打开redis持久化配置,使用的配置文件为/etc/redis/redis.conf

sudo docker run \
	-p 6699:6379 \
	--name docker-redis \
	-v $PWD/redis.conf:/etc/redis/redis.conf \
	-v $PWD/data:/data \
	-d redis:latest \
	redis-server /etc/redis/redis.conf --appendonly yes

docker安装redis 指定配置文件且设置了密码

3. 连接docker中的redis

直接从Docker容器进入Redis

sudo docker exec -it redis /bin/bash		# 进入docker容器, redis为容器名
redis-cli									# 使用redis-cli进入redis
auth 123456									# 登录redis,密码为123456
		
redis-cli -h 127.0.0.1 -p 6379 -a 123456    # 通过redis-cli连接redis, 主机为127.0.0.1, 端口为6379, 密码123456

Redis (error) NOAUTH Authentication required.解决方法

redis desktop manager 连接 docker 中的 redis

在这里插入图片描述

Redis配置文件解析

  • requirepass password:设置 redis 的登录密码
requirepass 123456							# 设置redis密码

# 默认情况下,redis 在 server 上所有有效的网络接口上监听客户端连接。
# 你如果只想让它在一个网络接口上监听,那你就绑定一个IP或者多个IP。
#
# 示例,多个IP用空格隔开:
#
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1
bind 0.0.0.0								# 在所有网络接口上监听客户端连接,也就是允许远程连接

redis.conf配置详细解析

注意事项

  • 修改redis.conf后一定要重启redis

Redis 客户端

漂亮又好用的Redis可视化客户端汇总,总有一款你需要的
Redis可视化工具

Jedis

Redis学习笔记(五)jedis(JedisCluster)操作Redis集群 redis-cluster

Redission

Redisson实现分布式锁(2)—RedissonLock
分布式锁(3)-Redisson实现
redis分布式锁RedissonLock的实现细节

Golang整合Redis

参考代码: redis_test.go
《尚硅谷_韩顺平_Go语言核心编程》19.5 Golang 操作 Redis
Go连接需要密码的Redis执行Lua脚本

SpringBoot整合Redis

Spring Data Redis中的事务陷阱
Sping Data Redis 使用事务时,不关闭连接的问题
Spring Boot 整合 Redis 实现缓存操作
spring boot 集成redis版本说明
spring boot 1.5.9 整合redis
springboot集成redis详解
spring boot使用redisTemplate存储键值出现乱码
Spring boot Redis 乱码
redis 集合设置过期时间
spring data redis RedisTemplate操作redis相关用法
RedisTemplate访问Redis数据结构(二)——List

Redis有哪些数据类型?并分别说明其应用场景

Go全栈面试题(4) -数据库面试题 Redis的数据结构有哪些,以及实现场景?
史上最全Redis面试题及答案 3、Redis支持哪几种数据类型?
一文搞定Redis五大数据类型及应用场景

String

常用命令: set, get, decr, incr, mget等
String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字.常规key-value缓存应用;常规计数:微博数,粉丝数等;

Hash

常用命令: hget, hset, hgetall等
Hash是一个String类型的field和value的映射表,hash特别适合用于存储对象;后续操作的时候,你可以仅仅修改这个对象中的某个字段的值.比如我们可以用Hash数据结构来存储用户信息,商品信息等等

List

常用命令: lpush, rpush, lpop, rpop, lrange等
List就是链表,redis list的应用场景非常多,也是redis最重要的数据结构之一,比如微博的关注列表, 分析列表, 消息列表等功能都可以用redis的list结构来实现
redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销.
另外可以通过lrange命令,就是从某个元素开始读取多少个元素,可以基于list实现分页查询,这是一个很棒的功能,基于redis实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高

Set

常用命令: sadd, spop, smembers, sunion等
set对外提供的功能与list类似,是一个列表的功能,特殊之处在于set是可以自动去重的.
当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的.可以基于set轻易实现交集,并集,差集的操作.
比如,在微博应用中,可以将一个用户所有的关注人存在于一个集合中,将其所有粉丝存在于一个集合.redis可以非常方便的实现如共同关注,共同粉丝,共同喜好等功能,这个过程也是求交集的过程,命令如下:

sinterstore key1 key2 key3 将交集存在key1内

SortedSet

常用命令: zadd, zrange, zrem, zcard等
和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。
举例: 在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 SortedSet 结构进行存储。

Redis 有哪些典型的应用场景?

1. Redis 有哪些典型的应用场景?

史上最全Redis面试题及答案 13、Redis有哪些适合的场景?

  • 会话缓存
    会话缓存(Session Cache)——存储用户token、购物车
  • 全页缓存
    全页缓存(Full Page Cache)——静态页面缓存
  • 排行榜/计数器
    排行榜——使用 set / sortedSet 进行实现
  • 发布/订阅
  • 分布式锁
  • 消息队列
    利用 list(底层为双端队列)数据类型实现,右进左出

2. 如何用 Redis 实现分布式锁?

Go全栈面试题(4) -数据库面试题 Redis分布式锁是什么回事?

2.1 如何用 Redis 实现分布式锁?

使用 setnx 来争抢锁,抢到以后,使用 expire 命令给锁设置一个过期时间,防止忘记释放锁;

2.2 如果在 setnx 之后、设置 expire 之前,redis 进程意外 crash 或者系统要重启维护,这时会发生什么情况?

使用 setnx 设置的锁永远不会得到释放;

2.3 如何解决该问题?

setnx 指令有非常复杂的参数,可以同时把 setnx 和 expire 两个指令合成一个指令来使用

3. 如何用Redis实现消息队列?

Go全栈面试题(4) -数据库面试题 Redis异步队列是怎么用的?

3.1 如何用Redis实现消息队列?

使用 List 数据类型作为消息队列容器,rpush 生产消息,lpop 消费消息;
当 lpop 没有消息时,redis 要适当 sleep 一会再进行重试;

3.2 当 lpop 没有消息时,如果不用 sleep 进行休眠,又该怎么处理?

List 还有个指令 blpop(block left pop),在没有消息的时候,会阻塞 list,直到有消息到来;

3.3 如何生产一次消费多次呢?

使用 Pub/Sub 主题-订阅者模式,可以实现 1:N 的消息队列

3.4 Pub/Sub有什么缺点?

在消费者下线的情况下,生产者生产的消息会丢失,此时必须使用专业的消息队列如RabbitMQ等;

3.5 Redis如何实现延时队列?

使用 sortedSet,用时间戳作为 score,消息内容作为 key;
生产者使用 zadd 来生产消息,消费者使用 zrangebyscore 指令获取 N 秒之前的数据进行处理。

缓存雪崩 vs 缓存穿透 vs 缓存击穿

如果有大量的key需要设置同一时间过期,一般需要注意什么?

Go全栈面试题(4) -数据库面试题 如果有大量的key需要设置同一时间过期,一般需要注意什么?

如果大量key的过期时间设置的过于集中,到过期的那个时间点,Redis会出现短暂的卡顿现象;
另外,短期内大量 key 过期,可能会导致大量请求落到数据库上,造成缓存雪崩的问题;
解决方案是,在给 key 设置过期时间时,给 key 加上一个随机值,避免 key 的过期时间集中分布;

缓存雪崩

缓存穿透,缓存击穿,缓存雪崩解决方案分析
短期内缓存大面积失效,导致大量请求落到数据库上,造成数据库短时间内因承受过大压力而崩掉

解决方案

  • 事前:保证 redis 集群的高可用
  • 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免MySQL崩掉
  • 事后:利用redis持久化机制保存的数据尽快恢复缓存
    Redis-学习笔记_第1张图片

缓存击穿

缓存击穿:对于设置了过期时间的热点数据,如果在其过期的时间点,正好过来大量请求,这个时候大量请求由于在缓存中查询不到对应缓存,就会去查询数据库,导致数据库因短期内承受大量请求而崩掉

解决方案

1. 加"互斥锁"

在查询缓存数据时,如果没有查询到对应缓存,线程会直接去请求数据库;
为了避免大量的请求落到数据库,会对查询数据库并设置缓存的操作加"互斥锁",当前线程查询数据并更新缓存成功后,释放互斥锁,其他的线程再去请求更新好的缓存;
具体做法为:使用 setnx 指令抢占锁并设置锁的过期时间,避免死锁;在抢占锁成功后进行数据库查询及缓存的更新操作;
在 redis 2.6.1 及其之前的版本中,setnx 指令不支持设置过期时间的操作,需要手动设置过期时间,代码如下:

// 2.6.1前单机版本锁
String get(String key) {
       
   String value = redis.get(key);  
   if (value  == null) {
       
    if (redis.setnx(key_mutex, "1")) {
       
        // 3 min timeout to avoid mutex holder crash  
        redis.expire(key_mutex, 3 * 60)  		// 设置锁的过期时间
        value = db.get(key);  
        redis.set(key, value);  
        redis.delete(key_mutex);				// 删除锁  
    } else {
       
        //其他线程休息50毫秒后重试  
        Thread.sleep(50);  
        get(key);  
    }  
  }  
}

在 redis 2.6.1 之后的版本中,setnx 指令支持设置过期时间的操作,代码如下:

public String get(key) {
     
      String value = redis.get(key);
      if (value == null) {
      //代表缓存值过期
          //设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
		  if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {
       //代表设置成功
               value = db.get(key);
               redis.set(key, value, expire_secs);
               redis.del(key_mutex);
          } else {
       //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
               sleep(50);
               get(key);  //重试
          }
     } else {
     
         return value;      
     }
 }

memcache 代码:

if (memcache.get(key) == null) {
       
    // 3 min timeout to avoid mutex holder crash  
    if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
       
        value = db.get(key);  
        memcache.set(key, value);  
        memcache.delete(key_mutex);  
    } else {
       
        sleep(50);  
        retry();  
    }  
}

2. 提前加"互斥锁"

3. 设置"永不过期"

4. 资源保护

缓存穿透

缓存穿透,缓存击穿,缓存雪崩解决方案分析
一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,数据库因短时间内承受大量压力而崩掉

解决方案

有很多种方法可以有效的解决缓存穿透问题;
最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力;
另外一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过5分钟

MySQL里有2000W的数据,redis中只存20W的数据,如何保证Redis中的数据都是热点数据?

redis中内存数据集上升到一定大小的时候,就会自动施行数据淘汰策略。

Redis 有哪些数据淘汰策略呢?你能详细说明一下吗?

  • volatile-lru: 从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • volatile-ttl: 从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  • volatile-random: 从已设置过期时间的数据集中(server.db[i].expires)选择任意数据淘汰
  • allkeys-lru: 从数据集中选择最近最少使用的数据移除(这个是最常用的)
  • allkeys-random: 从数据集(server.db[i].dict)中选择任意数据淘汰
  • no-eviction: 禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错

参考文档

史上最全Redis面试题及答案 12、MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?
史上最全Redis面试题及答案 Redis有哪几种数据淘汰策略?

如何保证缓存与数据库双写时的数据一致性?

【原创】分布式之数据库和缓存双写一致性方案解析

如何解决Redis的并发竞争key问题?

怎么理解Redis事务?

Redis事务?

Redis相比memcached有哪些优势?

Redis和memcached的区别?

Redis持久化机制(怎么保证Redis挂掉之后再重启数据可以进行恢复?)

修改配置不重启Redis会实时生效吗?

如何选择合适的持久化方式?

Redis提供哪几种持久化方式?

Redis常见性能问题和解决方案?

一个Redis实例最多能存放多少的keys?List/Set/Sorted Set它们最多内存放多少元素?

Redis是单线程的,如何提高多核CPU的利用率?

Redis的内存用完了会发生什么?

都有哪些办法可以降低Redis的内存使用情况呢?

Redis的内存占用情况怎么样?

Redis与其他key-value存储有什么不同?

支持一致性哈希的客户端有哪些?

Twemproxy是什么?

分布式Redis是前期做还是后期规模上来了再做好?为什么?

Redis持久化数据和缓存怎么做扩容?

Redis分区有什么缺点?

你知道有哪些Redis分区实现方案?

为什么要做Redis分区?

Redis如何做大量数据插入?

Redis回收进程如何工作的?

Redis如何做内存优化?

Redis事务相关的命令有哪几个?

Redis中的管道有什么用?

Redis集群之间是如何复制的?

异步复制
史上最全Redis面试题及答案 21、Redis集群之间是如何复制的?

Redis集群最大节点个数是多少?

16384 个。
史上最全Redis面试题及答案 22、Redis集群最大节点个数是多少?

Redis集群如何选择数据库?

Redis集群无法选择数据库,默认在数据库0
史上最全Redis面试题及答案 23、Redis集群如何选择数据库?

Redis集群会有写操作丢失吗?为什么?

Redis集群的主从复制模型是怎样的?

说说Redis哈希槽的概念?

Jedis和Redisson对比有什么优缺点?

Redis和Redisson有什么关系?

Redis支持的Java客户端都有哪些?官方推荐用哪个?

Redis集群方案什么情况下会导致整个集群不可用?

Redis集群方案应该怎么做?都有哪些方案?

Redis key的过期时间和永久有效分别怎么设置?

设置过期时间: EXPIRE 命令
设置永久有效: PERSIST 命令

expire hello 10						# 设置 key 为 hello 的记录的过期时间为 10s

史上最全Redis面试题及答案 28、Redis key的过期时间和永久有效分别怎么设置?

Redis中一个字符串类型的值能存储最大容量是多少?

512M
史上最全Redis面试题及答案 8、一个字符串类型的值能存储最大容量是多少?

Redis内存回收使用的是什么算法?

LRU(Latest Recently Used)算法
史上最全Redis面试题及答案 31、Redis回收使用的是什么算法?

为什么要用Redis而不用map/guava做缓存?

为什么要用Redis/为什么要用缓存?

缓存策略的设计

  • 先更新缓存,后更新数据库,避免读写并发造成的缓存脏数据

高性能网站设计之缓存更新的套路

如何利用Redis处理热点数据

谈谈Redis哨兵、复制、集群

Redis中如何查看和修改配置?

参考文档

Redis–各个数据类型最大存储量
处理redis连接数过多
史上最全Redis面试题及答案
Redis 相关面试题(下)
面试前必须要知道的Redis面试题

你可能感兴趣的:(数据库,redis)