一、Redis介绍
1.1 引言
- 由于用户量增大,请求数量也随之增大,数据压力过大。
- 多台服务器之间,数据不同步。
- 多台服务器之间的锁,已经不存在互斥性了。
1.2 NoSQL
Redis就是一个NoSQL
NoSQL->非关系型数据库
1.key -value :Redis
2.文档型: ElaticSearch,Solr,Mongodb
3.面向列:Hbase,Cassandra
4.图形化:Neo4j
除了关系型数据库就是菲关系型数据库
NoSQL只是一种概念
1.4 介绍
有一位意大利人,在开发一款LL00GG的统计页面,因为MySQL的性能不好,Salvatore自己研发了-款非关系型数据库,并命名为Redis。
Redis (Remote Dictionary Server)即远程字典服务,Redis是由C语言去编写:基于Key-value,而且Redis是基于内存存储数据,Redis提供了多种持久化机制,性能可以达到110000/s读取,81000/s写入数据。Redis提供了主从,哨兵以及集群的搭建方式,更加方便的横向扩展以及垂直扩展
2.1 安装Redis
version: '3.1'
services:
redis:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis
environment:
- TZ=Asia/Shanghai
ports:
- 6379:6379
进入redis容器
docker exec -it id bash
执行redis-cli进入
2.3 使用图形化界面连接Redis
在github上下载redis–manager
三、redis常用命令
3.1 Redis存储数据的结构
key:string :一个key对应一个值
key-hash:一个key对应一个Map
key-list:一个key对应一个列表
key-set:一个key对应一个集合
key-zset:一个key对应一个有序集合
另外三种
HyperLogLog:计算近似值的
GEO:地理位置
BIT:一般存储的也是一个字符串,存储的是一个byte[]
key-string:最常用的,一般用于存储一个值
key-hash:存储一个对象数据
key-list:使用list结构实现站和队列结构
key-set:交集,差集,并集等操作
key-zset:排行榜
3.2 string常用命令
1.#添加值
set key value
#2.取值
get key
#3.批量操作
mset key value key value…
mget key key…
#4.自增命令(点赞)
incr key
#5.自减命令
decr key
#6.自增或自建
incrby key increment
decrby key increment
#8.设置值的同时,指定生存时间(每次向Redis中添加数据时,尽量设置生存时间)
setex key second value
#9.设置值,如果当前key不存在的话,如果key存在,什么事都不做,不存在的话,会set
setnx key value
#10.在key对应的value后,追加内容
append key value
#11.查看value字符串的长度
strlen key
3.3 hash常用命令
#1.存储数据
hset key field value
#2.获取数据
hget key field
#3.批量操作
hmset key field value field value …
hmget key field field…
#4.自增(指定自增/减值)
hinerby key field increment#
#5.设置值(如果key-field不存在,那么就正常添加,如果存在,什么事都不做)
hsetnx key field value
#6.检查field是否存在
hexists key field
#7.删除key对应的某一个field
hdel key field field …
#8.获取当前hash结构中的全部field和value
hvals key
#9.获取当前hash结构中的全部field
hkeys key
#10.获取当前hash结构中全部value
hvals key
#11.获取当前bash结构总field的数量
hlen key
3.4 list常用命令
#1.存储数据(从左/右侧插入数据)
lpush key value …
rpush key value …
#2.存储数据(如果key不存在,什么事都不做,如果key存在,但不是list结构的话,什么都不做)
lpushx key value
rpushx key value
#3.存储数据(存储数据时,指定好你的索引位置,覆盖之前的索引位置的数据)
lset key index value
#4.弹栈方式获取数据(左/右侧弹出数据,)
lpop key
rpop key
#5.查看获取指定索引范围的数据(start 从0开始,stop输入-1,代表最后一个,-2代表倒数第二个)
lrange key start stop
#6.获取指定索引位置的数据
lindex key index
#7.获取整个列表的长度
llen key
#8.删除列表中的数据(他是删除当前列表中的count个value值,count>0)从左侧向右侧删除,count<0从右向左删除,count==0删除列表中全部value)
lrem key count value
#9.保留列表中的数据(保留你指定索引范围内的数据,超过整个索引范围被移除掉)
ltrim key start stop
#10.将一个列表中最后的一个数据,插入到另一个列表的头部位置
rooplpush list1 list2
3.5 set常用命令
#1.存储数据
sadd key member …
#2.获取数据
smembers key
#3.随机获取数据(会覆盖)
spop key
#4.交集
sinter set1 set2…
#5.并集(获取全部集合中的数据)
sunion set1,set2
#6.差集(获取多个集合中不一样的数据)
sdiff set1 set2 …
#7.删除数据
srem key member member …
#8.查看当前的set集合中是否包含这个值
sismember 可以memver
3.6 zset的常用命令
#1. 添加数据(score必须是一个数值 ,member不允许重复)
zadd key score member [score member …]
#2.修改member的分数(如果member是存在与key中的,正常增加分数,如果member不存在,这个命令相当于zadd)
zincrby key increment member
#3. 查询指定的member分数
zscore key member
#4. 获取zset中数据的数量
zscard key
#5. 根据score的范围查询member的数量查询
zcount key min max
#6. 删除zset中的成员
zrem key member member …
#7. 根据分数从小到大排序、获取指定范围内的数据(withscore如果添加这个参数,那么会返回member对应的分数)
zrange key start stop [withscores]
#8. 根据分数从大到小排序、获取指定范围内的数据(withscore如果添加这个参数,那么会返回member对应的分数)
zrevrange key start stop [withscores]
#9. 根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL一样)
zrangebyscore key min max [withscores] [limit offset count]
#10.根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL一样)
zrangebyscore key max min [withscores] [limit offset count]
3.7 key常用命令
#1. 查看Redis中全部的key (pattern : .xxx. *xxx)
keys pattern
#2. 查看某一个key是否存在
exists key
#3. 删除key
del key key …
…查看官方文档
四、Java连接Redis
Jedis连接Redis或者Lettuce连接Redis
4.1 Jedis连接Redis
1.创建MAVEN
2.导入jar包
jedis
junit
lombok
3.测试
@Test public void test1(){ //1.连接Redis Jedis jedis=new Jedis("192.168.56.100",6379); //2.操作Redis ,因为Redis的命令是什么,Jedis方法就是什么 //jedis.set("name","lisi"); String name = jedis.getrange("start",0,-1) ; System.out.println(name); //3.释放资源 jedis.close(); }
4.2 Jedis如何存储一个对象到Redis
准备一个User实体类
导入spring-context依赖
写测试类
4.3 Jedis存储对象到Redis以string形式
导入JSON包
4.4 Jedis连接池
//1.创建连接池配置信息 GenericObjectPoolConfig poolConfig=new GenericObjectPoolConfig(); poolConfig.setMaxTotal(100);//最大连接对象 poolConfig.setMaxIdle(10); //最大空闲数 poolConfig.setMinIdle(3); //最小 poolConfig.setMaxWaitMillis(3000); //时间超过则超时 //2.创建连接池 JedisPool jedisPool=new JedisPool(poolConfig,"192.168.56.100",6379); //3.获取Jedis Jedis jedis = jedisPool.getResource(); //3.操作 String stringUser = jedis.get("stringUser"); System.out.println(stringUser); //4.释放 jedis.close();
4.5 Redis管道操作(提高并发能力)
因为在操作Redis的时候,执行一个命令需要先发送请求到Redis服务器,这个过程需要经历网络的延迟,Redis
还需要给客户端一个响应。
如果我需要一次性执行很多个命令,上述的方式效率很低,可以通过Redig的管道,先将命令放到客户端的一
个Pipeline中,之后一次性的将全部命令都发送到Redi服务,Redis服务一次性的将全部的返回结果响应给客
户端。
package com.it.test; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.Pipeline; public class Demo5 { //Redis管道操作 @Test public void popeline(){ //1.创建连接池 long start = System.currentTimeMillis(); JedisPool pool=new JedisPool("192.168.56.100",6379); //2.获取一个连接对象 //Jedis jedis = pool.getResource(); 3.限制性incr -10000次 //for (int i=0;i<10000;i++){ // jedis.incr("pp"); //} 4.释放 //jedis.close(); //39909 //------------------- //2.获取一个连接对象 Jedis jedis = pool.getResource(); //3.创建管道 Pipeline pipelined = jedis.pipelined(); //4.执行incr -10000次放到管道中 for (int i=0;i<10000;i++){ pipelined.incr("qq"); } //5.执行 pipelined.syncAndReturnAll(); //6.释放 jedis.close(); //242 long end = System.currentTimeMillis(); System.out.println("所用时间:"+(end-start)); } }
五、Redisc其他配置及集群
5.1 修改yml (映射配置文件,方便修改配置)
version: '3.1'
services:
redis:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis
environment:
- TZ=Asia/Shanghai
ports:
- 6379:6379
volumes:
- ./conf/redis.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
5.2 Redis的AUTH
5.3 Redis的事务
5.4 Redis持久化机制
5.5 Redis主从架构
单机版Redis存在读写瓶颈的问题
version: "3.1"
services:
redis1:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis1
environment:
- TZ=Asia/Shanghai
ports:
- 7001:6379
volumes:
- ./conf/redis1.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
redis2:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis2
environment:
- TZ=Asia/Shanghai
ports:
- 7002:6379
volumes:
- ./conf/redis2.conf:/usr/local/redis/redis.conf
links:
- redis1:master
command: ["redis-server","/usr/local/redis/redis.conf"]
redis3:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis3
environment:
- TZ=Asia/Shanghai
ports:
- 7003:6379
volumes:
- ./conf/redis3.conf:/usr/local/redis/redis.conf
links:
- redis1:master
command: ["redis-server","/usr/local/redis/redis.conf"]
#从节点(redis2 , redis3)配置 (redis1.conf不用配置)
replicaof master 6379
docker-compose up -d
进入redis1.conf容器 执行info(查看), 可以进行读/写
进入redis2.conf容器 执行info(查看), 可以进行读
进入redis3.conf容器 执行info(查看), 可以进行读
5.6 哨兵 sentinel
哨兵可以帮助我们解决主从架构中的单点故障问题
准备哨兵的配置文件,并且在容器内部手动启动哨兵即可
修改docker-compose.yml
version: "3.1"
services:
redis1:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis1
environment:
- TZ=Asia/Shanghai
ports:
- 7001:6379
volumes:
- ./conf/redis1.conf:/usr/local/redis/redis.conf
- ./conf/sentinel1.conf:/data/sentine.conf #添加的内容
command: ["redis-server","/usr/local/redis/redis.conf"]
redis2:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis2
environment:
- TZ=Asia/Shanghai
ports:
- 7002:6379
volumes:
- ./conf/redis2.conf:/usr/local/redis/redis.conf
- ./conf/sentinel2.conf:/data/sentine.conf #添加的内容
links:
- redis1:master
command: ["redis-server","/usr/local/redis/redis.conf"]
redis3:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis3
environment:
- TZ=Asia/Shanghai
ports:
- 7003:6379
volumes:
- ./conf/redis3.conf:/usr/local/redis/redis.conf
- ./conf/sentinel3.conf:/data/sentine.conf #添加的内容
links:
- redis1:master
command: ["redis-server","/usr/local/redis/redis.conf"]
redis1.conf redis2.conf redis3.conf 配置文件
#代表哨兵需要后台启动
daemonize yes
#指定Master节点的ip和端口(主)
sentinel monitor master localhost 6379 2
#指定Master节点的ip和端口(从)
sentinel monitor master master 6379 2
#哨兵每隔多久监听一次redis架构
sentinel down-after-milliseconds master 10000
重启:docker-compose down
docker-compose up -d
进入所有的Redis容器开启哨兵
执行 redis-sentinel sentinel.conf
5.7 Redis集群
Redis集群在保证主从加哨兵的基本功能之外,还能够提升Redis存储数据的能力。
#docker-compose.yml
version: "3.1"
services:
redis1:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis1
enviroment:
- TZ=Asia/Shanghai
ports:
- 7001:7001
- 17001:17001
volumes:
- ./conf/redis1.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
redis2:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis2
enviroment:
- TZ=Asia/Shanghai
ports:
- 7002:7002
- 17002:17002
volumes:
- ./conf/redis2.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
redis3:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis3
enviroment:
- TZ=Asia/Shanghai
ports:
- 7003:7003
- 17003:17003
volumes:
- ./conf/redis3.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
redis4:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis4
enviroment:
- TZ=Asia/Shanghai
ports:
- 7004:7004
- 17004:17004
volumes:
- ./conf/redis4.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
redis5:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis5
enviroment:
- TZ=Asia/Shanghai
ports:
- 7005:7005
- 17005:17005
volumes:
- ./conf/redis5.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
redis6:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis6
enviroment:
- TZ=Asia/Shanghai
ports:
- 7006:7006
- 17006:17006
volumes:
- ./conf/redis6.conf:/usr/local/redis/redis.conf
command: ["redis-server","/usr/local/redis/redis.conf"]
#redis.conf
#指定redis的端口号
port 7001
#开启Redis集群
cluster-enabled yes
#集群信息的文件
cluster-config-file nodes-7001.conf
#集群对外ip地址
cluster-announce-ip 192.168.56.100
#集群对外的port
cluster-announce-port 7001
#集群对外的总线端口
cluster-announce-bus-port 17001
启动了6个Redis节点。
随便跳转到一个容器内部,使用redis-cli管理集群
redis-cli --cluster create 192.168.56.100:7001 192.168.56.100:7002 192.168.56.100:7003 192.168.56.100:7004 192.168.56.100:7005 192.168.56.100:7006 --cluster-replicas 1
5.7 Java连接Redis集群
使用JedisCluster连接
/**
* 连接Redis集群
*/
public class Demo6 {
@Test
public void test1(){
//创建Set<HostAndPort>
Set<HostAndPort> nodes=new HashSet<>();
nodes.add(new HostAndPort("192.168.56.100",7001));
nodes.add(new HostAndPort("192.168.56.100",7002));
nodes.add(new HostAndPort("192.168.56.100",7003));
nodes.add(new HostAndPort("192.168.56.100",7004));
nodes.add(new HostAndPort("192.168.56.100",7005));
nodes.add(new HostAndPort("192.168.56.100",7006));
//创建JedisCluster对象
JedisCluster jedisCluster=new JedisCluster(nodes);
String value = jedisCluster.get("b");
System.out.println(value);
}
}
六、Redis常见问题
6.1 key的生存时间到了,Redis会立即删除吗?
回答:不会立即删除
1.定期删除:
Redis每隔一段时间就去会去查看Redis设置了过期时间的key,会在100ms间隔中默认查看3个key
2.惰性删除:
如果当你去查询一个已经过了生存时间的key时,Redis会先查看当前key的生存时间,是否已经到 了,直接删除当前key,并且给用户返回一个空值。
6.2 Redis的淘汰机制
在Redis内存已经满的时候,添加了一个新的数据,执行淘汰机制。
1.volatile-lru:
在内存不足时,Redis会再设置过了生存时间的key中干掉一个最近最少使用(lru)的key。
2.allkeys-lru:
在内存不足时,Redis会再全部的key中干掉一个最近最少使用(lru)的key。
3.volatile-lfu:
在内存不足时,Redis会再设置过了生存时间的key中干掉一个最近最少频次使用(lfu)的key。
4.allkeys-lfu
在内存不足时,Redis会再全部的key中干掉一个最近最少频次使用(lfu)的key。
5.volatile-random
在内存不足时,Rddis会再设置过了生存时间的key中随机干掉一个。
6.allkeys-random
在内存不足时,Redis会再全部的key中随机干掉一个。
7.volatile-ttl
在内存不足时,Rddis会再设置过了生存时间的key中干掉一个剩余时间最少的
8.noeviction (Default)
在内存不足时,直接报错。
指定淘汰机制的方式:
maxmemory-policy noeviction 具体策略
设置Redis的最大内存:
maxmemory
6.3 缓存问题
缓存穿透
缓存击穿
缓存雪崩
缓存倾斜
latile-lru:
在内存不足时,Redis会再设置过了生存时间的key中干掉一个最近最少使用(lru)的key。
2.allkeys-lru:
在内存不足时,Redis会再全部的key中干掉一个最近最少使用(lru)的key。
3.volatile-lfu:
在内存不足时,Redis会再设置过了生存时间的key中干掉一个最近最少频次使用(lfu)的key。
4.allkeys-lfu
在内存不足时,Redis会再全部的key中干掉一个最近最少频次使用(lfu)的key。
5.volatile-random
在内存不足时,Rddis会再设置过了生存时间的key中随机干掉一个。
6.allkeys-random
在内存不足时,Redis会再全部的key中随机干掉一个。
7.volatile-ttl
在内存不足时,Rddis会再设置过了生存时间的key中干掉一个剩余时间最少的
8.noeviction (Default)
在内存不足时,直接报错。
指定淘汰机制的方式:
maxmemory-policy noeviction 具体策略
设置Redis的最大内存:
maxmemory
6.3 缓存问题
缓存穿透
缓存击穿
缓存雪崩
缓存倾斜