文章目录
1. Redis的简介
- Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理
- 它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型
- 内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
- 简言之,Redis是一种面向“键/值”对数据类型的内存数据库,可以满足我们对海量数据的快速读写需求。
2 Redis的特点
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用
- Redis不仅仅支持简单的k-v类型的数据,同时还提供list,set,zset,hash等数据结构的存储
- Redis支持数据的备份,即master-slave主从模式的数据备份
3 Redis的优势
- 性能极高-Redis读的速度为11W/s,写的速度为8.1w/s。
- 丰富的数据类型(String,Lists,Hashes,Sets及OrderedSets)。
- 原子性-Redis所有的操作都是原子性的,同时Redis还支持对几个操作进行合并后的原子性执行。
- 丰富的特性-支持publish/subscribe,通知,key过期等特性。
4 常用的NoSql数据库
- hbase:存储海量的数据(数十亿行,百万列)
- redis:基于内存的NoSql数据库,一般使用Redis做缓存或者队列
- mogodb:在结构化数据比较简单的情况下,可以使用mogodb代替mysql,作为一个高性能的数据库
5 Redis的安装
5.1 Redis单机版的安装
- 准备源码安装包 redis-5.0.10.tar.gz
- 安装GCC编译器、lsof(lists openfiles)列出打开文件
- 解压
tar -zxvf redis-5.0.10.tar.gz -C /opt
- 重命名
cd /opt
mv redis-5.0.10/ redis
- 编译安装源码
cd redis/
make && make install
- 添加环境变量
vim /etc/profile
export REDIS_HOME=/opt/redis
export PATH=$PATH:$REDIS_HOME/src
- 重新执行刚修改的初始化文件,使之立即生效
source /etc/profile
- 修改redis.conf的配置项
cd src
vim redis.conf
bind 0.0.0.0 (默认是127.0.0.1,这是本地回环地址,只能本地应用程序之间进行通信)
daemonize yes(后台运行)
logfile /opt/redis/logs/redis.log(日志文件,目录必须存在)
- 新建日志文件目录
mkdir -p /opt/redis/logs
- 启动Redis-Server
redis-server /opt/redis/redis.conf
- 启动redis客户端
redis-cli -h 10.10.10.21 -p 6279
5.2 Redis的集群安装
node1 master
node2 slave
node3 slave
- 把前面安装好的单机版的redis拷贝到node2 node3
- 再给节点(node2 node3) redis.conf 末尾追加
slaveof node1 6379
ps:注意启动集群时尽量先启动主节点再启动从节点
6 Redis中配置的查看
Redis的配置文件位于Redis的安装目录之下,文件名为redis.conf。可以通过config命令来查看或设置配置项
config get confName: 获取配置的值
config set confName confVal: 设置配置的值
使用config配置的模式,只是在当前的会话中有效,如果redis重新启动则失效了
7 Redis中的数据类型
- string(字符串)
- hash(哈希)
- list(列表)
- set(集合)
- zset(sorted set)有序的集合
8 数据类型之String(字符串)
- string是redis中最基本的数据类型
- 一个key对应一个value
- string类型的value是基于二进制存储的,所以完全可以存储图片和影音等二进制数据
- string类型的value大小最大512mb
- 存储数据:
set key value
- 一次性存储多个数据
mset key value [key value...]
- 读取数据:
get key
- 删除redis中的key说对应的value:
del key
- 计数器操作
set mage 20 #添加一个value
incr mage #自增1
decr mage #自减1
incrby mage 100 #自增指定的值
decrby mage 55 #自减指定的值
- 添加具有过期时间的键值对
setex key seconds value
- 查看过期时间
ttl key
- 给value追加字符串
append key value
9 数据类型之Hash(哈希)
- Redis hash 是一个键值对集合。Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象object
- 存储一个数据:
hset key field value
- 获取数据:
hget key field
- 设置多个数据:
hmset key field value[key field value...]
- 获取多个数据:
hmget key value[value...]
- 删除hash中的多个个键值对:
hdel key value[value...]
- 删除redis中的key说对应的value:
del key [key...]
- 获取指定的key的全部键值对:
HGETALL key
- 获取指定的key对应的元素的个数:
HLEN key
10 数据类型之List(列表)
- Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
- 首部添加数据:
lpush key value[value...]
- 尾部添加元素:
rpush key value[value...]
- 查看数据:
lrange key start stop
- 首部移除元素:
LPOP key
- 尾部移除元素:
RPOP key
列表最多可存储 2^32-1元素 (4294967295, 每个列表可存储40多亿)
11 数据类型之Set(集合)
12 数据类型之ZSet(有序集合)
13 Redis中的常用命令
13.1 键值对相关
keys *
取出当前所有的key
exists name
查看redis是否有name这个key
del name
删除key name
expire confirm 100
设置confirm这个key100秒过期
ttl confirm
获取confirm 这个key的有效时长
persist confirm
移除confirm这个key的过期时间
select 0
(在redis中总共有16个数据库,默认是0号数据库)
move confirm 1
将当前数据库中的key移动到其他的数据库中
randomkey
随机返回数据库里面的一个key
rename key2 key3
重命名key2 为key3
type key2
返回key的数据类型
SHUTDOWN
关闭redis数据库
13.2 服务器相关
select 0~15
编号的数据库
quit /exit
退出客户端
dbsize
返回当前数据库中所有key的数量
info
返回redis的相关信息
flushdb
删除当前选择数据库中的所有key
flushall
删除所有数据库中的数据
14. Redis中的API操作
-
pom依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
-
常用操作
package com.uplooking.bigdata.redis; import org.junit.Test; import redis.clients.jedis.Jedis; public class RedisTest { @Test public void testString() { //创建Jedis Jedis jedis = new Jedis("uplooking03"); jedis.select(0); jedis.set("name", "value"); System.out.println(jedis.get("name")); } @Test public void testHash() { //创建Jedis Jedis jedis = new Jedis("uplooking03"); jedis.select(0); jedis.hset("info", "name", "admin"); jedis.hset("info", "age", 12 + ""); System.out.println(jedis.hget("info", "name")); } @Test public void testList() { //创建Jedis Jedis jedis = new Jedis("uplooking03"); jedis.select(0); jedis.rpush("loves", "java", "c++", "python"); jedis.lpop("loves"); System.out.println(jedis.lrange("loves", 0, 10000)); System.out.println(jedis.rpop("loves")); System.out.println(jedis.lrange("loves", 0, 10000)); } }
15. Redis设置密码
requirepass root #配置密码为root
登录redis:
redis-cli -h node1
auth root
16. Redis可视化工具
RedisDesktopManager
17.SpringBoot集成Redis
-
引入依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> </project>
-
注入redisTemplate
package com.up; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; @SpringBootApplication public class Application implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(Application.class); } @Autowired private StringRedisTemplate redisTemplate; @Override public void run(String... args) throws Exception { // redisTemplate.opsForValue().set("name123", "xiaohua"); // redisTemplate.opsForList().leftPush("loves", "java"); redisTemplate.opsForHash().put("score", "java", String.valueOf(30)); } }
18. Redis的持久化策略
reids是一个key-value存储系统,为了保证效率,缓存在内存中,但是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,以保证数据的持久化;
所以:redis是一个支持持久化的内存数据库,可以将内存中的数据同步到磁盘保证持久化;
Redis的持久化策略:2种
rdb: rdb数据快照形式,是直接把内存中的数据保存到一个dump文件中,定时保存;
aof:把所有的对redis的服务器进行'写操作'的命令都存到一个文件里,命令的集合
默认redis只开启的是rdb策略,我们可以手动开启aof策略,当开启aof策略时,服务器启动时优先使用aof策略;
18.1 rdb策略
原理: 当redis需要做持久化时,redis会fork一个子进程;子进程将数据写到磁盘上一个临时RDB文件中;当子进程完成写临时文件后,将原来的RDB替换掉,这样的好处就是可以copy-on-write(写时复制技术)
redis.conf
配置:
save 900 1
save 300 10
save 60 10000
默认是如上配置:
900秒之内,如果超过1个key被修改,则发起快照保存;
300秒内,如果超过10个key被修改,则发起快照保存
1分钟之内,如果1万个key被修改,则发起快照保存
注意:以上的配置只要触发任意一个操作都会执行备份rdb快照的操作 'BGSAVE'
这种方式不能完全保证数据持久化,因为是定时保存,所以当redis服务down掉,
就会丢失一部分数据,而且数据量大,写操作多的情况下,会引起大量的磁盘IO操
作,会影响性能;
所以,如果这两种方式同时开启,如果对数据进行恢复,不应该用rdb持久化方式对数据库进行恢复
18.2 AOF策略
AOF持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集,它可以实现每次操作都持久化;
AOF文件中的命令全部以redis协议的格式来保存,新命令会被追加到文件的末尾。 redis还可以在后台对AOF文件进行重写(rewrite),使得AOF文件的体积不会超出保存数据集状态所需的实际大小。redis还可以同时使用AOF持久化和RDB持久化。在这种情况下,当redis重启时,它会优先使用AOF文件来还原数据集, 因为AOF文件保存的数据集通常比RDB文件所保存的数据集更完整。也可以关闭持久化功能,让数据只在服务器运行时存在。
配置方式:启动aof持久化的方式
appendonly yes
AOF文件刷新的方式,有三种
appendfsync everysec
appendfsync always:每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用
appendfsync everysec:每秒钟都调用fsync刷新到AOF文件,很快,但可能会丢失一秒以内的数据;(推荐)
appendfsync no:依靠OS进行刷新(一般30s左右一次刷新),redis不主动刷新AOF,但安全性就差。
默认并推荐每秒刷新,这样在速度和安全上都做到了兼顾。
18.3 redis持久化策略优先级
AOF优先于RDB
RDB性能优于AOF,因为里面没有重复
Redis一次性将数据加载到内存中,一次性预热
18.4 生产环境的备份
为以防万一(机器坏掉或磁盘坏掉),最好定期把使用filesnapshotting 或 Append-only 生成的*rdb *.aof文件备份到远程机器上,然后可以用crontab定时(比如每半小时)scp一次。如果没有使用redis的主从功能 ,半小时备份一次应该是可以了;并且如果应用数据量不大的话,可以单机部署,做主从有点浪费。具体还是要根据应用而定。
18.5 生产环境恢复数据
1)确保redis是未启动状态
2)把备份的rdb或者aof文件放入redis的安装路径 /opt/redis
3)启动redis,会主动加载rdb或者aof备份文件,加载哪个文件取决于是否开启aof,没开启默认加载rdb,开启了优先加载aof;
19. 缓存穿透是什么?
-
缓存穿透指查询不存在的数据,缓存层和存储层都不会命中,导致不存在的数据每次请求都要到存储层查询,可能会使后端负载增大。
-
解决:
① 缓存空对象,如果一个查询返回结果为 null,仍然缓存,为其设置很短的过期时间。
② 布隆过滤器,将所有可能存在的数据映射到一个足够大的 Bitmap 中,在用户发起请求时首先经过布隆过滤器的拦截,一个一定不存在的数据会被拦截。
20 缓存击穿是什么?
对于热数据的访问量非常大,在其缓存失效的瞬间,大量请求直达存储层,导致服务崩溃。
解决:
① 加锁互斥,当一个线程访问后,缓存数据会被重建。
② 永不过期,为热点数据不设置过期时间。
21 缓存雪崩是什么?
如果缓存层因为某些问题不能提供服务,所有请求都会到达存储层,对数据库造成巨大压力。
解决:
① 保证高可用性,使用集群。
② 依赖隔离组件为后端限流并降级,降级机制在高并发系统中使用普遍,例如在推荐服务中,如果个性化推荐服务不可用,可以降级补充热点数据,避免前端页面空白。
③ 构建多级缓存,增加本地缓存,降低请求直达存储层概率。