2.3.1Redis主要作用
说明:缓存主要的目的是降低客户访问物理设备的频次.保护了真实的后台数据库.
2.3.2缓存设计原理
1.缓存的数据结构采用k-v K必须唯一
2.要想让缓存执行的速度更快,采用C语言编程.
3.缓存应该运行在内存中.
4.为了防止缓存数据的丢失,应该将数据定期持久化到磁盘中
5.为了防止内存泄露,定期清理内存空间. LRU算法 LFU算法
2.3.3Redis介绍
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
执行速度: 读速度 11.2万次/秒 写速度8.6万/次 平均10万次/秒
2.3.4Redis安装和下载
http://www.redis.cn/
2.3.4.1上传安装文件
2.3.4.2解压Redis文件
命令:tar -xvf redis-5.0.4.tar.gz
2.3.4.3修改文件名称
2.3.4.4编译和安装
说明:在redis的根目录中执行下列命令
命令: make
安装:make install
2.3.5修改redis.conf
1.修改IP绑定
2.关闭保护模式
3.开启后台启动
2.3.6Redis入门命令
1.启动redis指令
redis-server 当前控制台会被占用,用户体验不友好.
redis-server redis.conf
redis.conf中需要进行后台启动的配置.
2.客户端操作
进入客户端 redis-cli -p 6379
退出客户端 exit 或者 ctrl+c 或者 quit
3.关闭redis redis-cli -p 6379 shutdown
1Redis常规命令
1.1Redis客户端安装
1.双击rdm文件运行.
2.链接服务器
3.链接测试
1.2Redis命令
1.1.1String类型
命令 说明 案例
set 添加key-value set username admin
get 根据key获取数据 get username
strlen 获取key的长度 strlen key
exists 判断key是否存在 exists name
返回1存在 0不存在
del 删除redis中的key del key
Keys 用于查询符合条件的key keys * 查询redis中全部的key
keys n?me 使用占位符获取数据
keys nam* 获取nam开头的数据
mset 赋值多个key-value mset key1 value1 key2 value2 key3 value3
mget 获取多个key的值 mget key1 key2
append 对某个key的值进行追加 append key value
type 检查某个key的类型 type key
select 切换redis数据库 select 0-15 redis中共有16个数据库
flushdb 清空单个数据库 flushdb
flushall 清空全部数据库 flushall
incr 自动加1 incr key
decr 自动减1 decr key
incrby 指定数值添加 incrby 10
decrby 指定数值减 decrby 10
expire 指定key的生效时间 单位秒 expire key 20
key20秒后失效
pexpire 指定key的失效时间 单位毫秒 pexpire key 2000
key 2000毫秒后失效
ttl 检查key的剩余存活时间 ttl key
persist 撤销key的失效时间 persist key
1.1.2Hash类型
说明:可以用散列类型保存对象和属性值
例子:User对象{id:2,name:小明,age:19}
命令 说明 案例
hset 为对象添加数据 hset key field value
hget 获取对象的属性值 hget key field
hexists 判断对象的属性是否存在 HEXISTS key field
1表示存在 0表示不存在
hdel 删除hash中的属性 hdel user field [field ...]
hgetall 获取hash全部元素和值 HGETALL key
hkyes 获取hash中的所有字段 HKEYS key
hlen 获取hash中所有属性的数量 hlen key
hmget 获取hash里面指定字段的值 hmget key field [field ...]
hmset 为hash的多个字段设定值 hmset key field value [field value ...]
hsetnx 设置hash的一个字段,只有当这个字段不存在时有效 HSETNX key field value
hstrlen 获取hash中指定key的长度 HSTRLEN key field
hvals 获取hash的所有值 HVALS user
1.1.3List类型
说明:Redis中的List集合是双端循环列表,分别可以从左右两个方向插入数据.
List集合可以当做队列使用,也可以当做栈使用
队列:存入数据的方向和获取数据的方向相反
栈:存入数据的方向和获取数据的方
命令 说明 案例
lpush 从队列的左边入队一个或多个元素 LPUSH key value [value ...]
rpush 从队列的右边入队一个或多个元素 RPUSH key value [value ...]
lpop 从队列的左端出队一个元素 LPOP key
rpop 从队列的右端出队一个元素 RPOP key
lpushx 当队列存在时从队列的左侧入队一个元素 LPUSHX key value
rpushx 当队列存在时从队列的右侧入队一个元素 RPUSHx key value
lrange 从列表中获取指定返回的元素 LRANGE key start stop
Lrange key 0 -1 获取全部队列的数据
lrem 从存于 key 的列表里移除前 count 次出现的值为 value 的元素。 这个 count 参数通过下面几种方式影响这个操作:
count > 0: 从头往尾移除值为 value 的元素。
count < 0: 从尾往头移除值为 value 的元素。
count = 0: 移除所有值为 value 的元素。 LREM list -2 “hello” 会从存于 list 的列表里移除最后两个出现的 “hello”。
需要注意的是,如果list里没有存在key就会被当作空list处理,所以当 key 不存在的时候,这个命令会返回 0。
Lset 设置 index 位置的list元素的值为 value LSET key index value
1.1.4Redis事务命令
说明:redis中操作可以添加事务的支持.一项任务可以由多个redis命令完成,如果有一个命令失败导致入库失败时.需要实现事务回滚.
命令 说明 案例
multi 标记一个事务开始 127.0.0.1:6379>
MULTI
OK
exec 执行所有multi之后发的命令 127.0.0.1:6379>
EXEC
OK
discard 丢弃所有multi之后发的命令
1.3Redis入门案例
1.3.1添加jar包
spring整合redis
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
1.3.2编辑测试类
/**
* redis入门案例
* host: redis的IP地址
* port: redis的端口号
*/
@Test
public void testString() {
Jedis jedis = new Jedis("192.168.226.128", 6379);
jedis.set("name","小鸡吃米图");
String value1 = jedis.get("name");
System.out.println(value1);
jedis.set("name", "小鸡炖蘑菇");
String value2 = jedis.get("name");
System.out.println(value2);
}
//测试数据是否允许修改
@Test
public void testString2() {
Jedis jedis = new Jedis("192.168.226.128", 6379);
//如果key已经存在.则不允许赋值.
jedis.setnx("1909", "今天周三!!!");
jedis.setnx("1909", "今天周四!!!");
System.out.println(jedis.get("1909"));
}
/**
* 为数据添加超时时间并且支持原子性操作
* @throws InterruptedException
*/
@Test
public void testString3() throws InterruptedException {
Jedis jedis = new Jedis("192.168.226.128", 6379);
jedis.set("eat", "随便!!!!!");
//int a = 1/0; 违反了原子性操作!!!!
jedis.expire("eat", 10);
Thread.sleep(2000);
System.out.println(jedis.ttl("eat"));
//为数据添加超时时间,并且同时完成赋值操作.
jedis.setex("eat", 10, "吃 ..... 随便吧!!!!");
System.out.println(jedis.get("eat"));
}
/**
* 1.保证数据不被修改
* 2.赋值操作与添加超时时间的操作是原子性的
*
* 问题: nx方法和ex方法 不能同时执行.
*
* params:
* XX:允许覆盖
NX:不允许覆盖
PX:毫秒
EX:秒
*/
@Test
public void testString4() {
SetParams setParams = new SetParams();
setParams.nx().ex(10);
Jedis jedis = new Jedis("192.168.226.128", 6379);
jedis.set("1909","您好redis", setParams);
jedis.set("1909","XXXXXXXXX", setParams);
System.out.println(jedis.get("1909"));
}
1.3.3测试Hash类型
private Jedis jedis;
@BeforeEach
public void init() {
jedis = new Jedis("192.168.226.128", 6379);
}
//一般使用hash存储对象.
@Test
public void testHash() {
jedis.hset("person", "id", "200");
jedis.hset("person", "name", "tomcat");
Map<String,String> map = new HashMap<>();
map.put("id", "2000");
map.put("name", "伊朗你很厉害");
map.put("age", "180");
jedis.hset("student", map);
System.out.println(jedis.hvals("person"));
System.out.println(jedis.hgetAll("student"));
}
1.3.4编辑测试List集合
@Test
public void testList() {
jedis.lpush("list", "1","2","3");
System.out.println(jedis.rpop("list"));
}
1.3.5测试事务控制
@Test
public void testTx() {
//1.开启事务
Transaction transaction = jedis.multi();
try {
//2.进行业务操作
transaction.set("a", "aa");
transaction.set("b", "bb");
transaction.set("c", "cc");
//3.事务提交
transaction.exec();
} catch (Exception e) {
//4.事务回滚
transaction.discard();
}
}
1.1Redis持久化策略
1.1.1发现现象
说明:redis的数据运行在内存中,如果服务器宕机.则内存数据全部丢失.
但是发现.redis重启之后数据依然存在.redis自身有持久化机制.
1.1.2Redis持久化策略
说明:redis根据配置文件中指定的持久化策略,定期将内存数据保存到磁盘中.当服务器重启时,首先会根据配置文件中持久化文件的名称,实现内存数据的恢复.
1.1.3RDB模式
特点说明:
1.RDB模式是Redis的默认的持久化策略.
2.RDB模式可以实现"定期"持久化. 可能会丢失数据.
3.RDB模式持久化时,记录的是内存数据的快照,每次只保留最新的记录. 持久化文件相对较小. 恢复数据速度更快.
1.1.3.1持久化命令
命令1: save 立即持久化,程序可能会陷入阻塞.
命令2: bgsave 后台持久化, 当程序不忙时,进行持久化操作.
1.1.3.2持久化操作配置文件
1.持久化策略
save 900 1 900秒内,如果更新1次redis时,持久化一次
save 300 10 300秒内,如果更新10次,则持久化一次.
save 60 10000 60秒 更新了10000次.
save 1 1 该配置性能较低.
2.持久化文件名称
dbfilename dump.rdb 253行
3.持久化文件目录
dir ./ 程序运行的当前目录. 目录公用的.
1.1.4AOF模式
特点:
1.AOF模式是关闭的,如果使用,需要手动的开启.
2.AOF模式可以实现实时持久化操作. 可以保证数据不丢失.
3.AOF模式持久化时,记录用户的操作过程.并且将过程追加到持久化文件中.AOF持久化文件相对较大.实现数据恢复速度较慢.
4.如果AOF模式和rdb模式同时存在,以aof模式为主.
1.1.4.1AOF模式的配置
1.开启持久化方式
2.配置持久化文件名称
1.1.4.2持久化策略
appendfsync always 实时异步持久化.
appendfsync everysec 每秒持久化一次.
appendfsync no 自己不主动持久化.
1.1.5持久化文件实际使用策略
使用redis集群模式.
Redis主机使用RDB模式(效率高).从机使用AOF模式(保证数据安全).
1.2Redis中内存策略
1.2.1需求说明
Redis中的数据都保持在内存中,如果不定期清理则必然会导致内存溢出.
必然使用算法实现定期清理内存.
1.2.2LRU算法
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
1***.2.3LFU算法***
说明: redis5.0以后的版本才有LFU算法.
LFU(least frequently used (LFU) page-replacement algorithm)。即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。
1.2.4Redis内存策略设置
1.volatile-lru 设定超时时间的数据采用lru
2.allkeys-lru 所有数据采用lru算法删除数据
3.volatile-lfu 设定超时时间的数据采用lfu算法
4.allkeys-lfu 所有数据采用lfu算法.
5.volatile-random 设定超时时间的数据采用随机算法
6.allkeys-random 所有数据采用随机算法.
7.volatile-ttl 设定超时时间数据采用ttl算法
8.noeviction 默认策略 不删除数据.如果内存溢出则报错通知使用者.
内存优化策略的修改:
1.3Redis分片机制
1.3.1单台redis存在问题
1.如果redis服务器宕机,则整体运行出现问题.
2.由于业务需要,需要使用大量的内存空间 来实现数据的缓存.
1.3.2redis分片说明
业务说明:由于单台redis不能保存海量的内存数据,可以使用多台redis共同保持数据.并且每台redis的内存数据都不相同.
1.3.3Redis分片实现
搭建策略: 6379/6380/6381
复制多个配置文件:
2.修改端口号 各自修改对应的端口号
3.启动redis
redis-server 6379.conf
redis-server 6380.conf
redis-server 6381.conf
1.3.4Redis分片入门案例
/**
* 1.实现redis分片操作
*/
@Test
public void testShards() {
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
shards.add(new JedisShardInfo("192.168.226.128", 6379));
shards.add(new JedisShardInfo("192.168.226.128", 6380));
shards.add(new JedisShardInfo("192.168.226.128", 6381));
ShardedJedis jedis = new ShardedJedis(shards);
//用户操作redis
jedis.set("1909", "您好Redis分片");
System.out.println(jedis.get("1909"));
}
1.4Hash 一致性算法
1.4.1Hash一致性说明
一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系 [1] 。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题 [2] 。
概念: 对相同的数据进行hash ,那么值必然相同.
知识回顾: 给定未知数x 经过F(x) 得到唯一确定的y的工程
取值范围:
1.4.2均衡性
说明:当节点出现负载不均的现象时,采用虚拟节点方式实现数据的平衡.
1.4.3单调性
说明:当节点修改时,节点中的数据可以实现自动的数据迁移.
Redis特殊情况: redis中的节点只能新增.尽量不要减少节点.否则出现数据丢失现象.
1.4.4分散性
分散性是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据
了解:由于分布式的部署,程序不能使用全部的内存空间.原来一个key只有一个位置.但是由于分散性.可能导致 一个key有多个位置.
A: 3倍内存
B: 2倍内存
以后使用服务器时,最好使用全部的内存空间.
1.4.5关于分片说明
说明:使用redis分片机制,主要的目的实现内存的扩容.
1.5SpringBoot整合redis分片
1.5.1编辑Properties配置文件
#配置redis分片
redis.nodes=192.168.226.128:6379,192.168.226.128:6380,192.168.226.128:6381
1.5.2编辑RedisConfig配置类
//标识配置类信息
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {
@Value("${redis.nodes}")
private String nodes; //node,node,node
//配置redis分片功能.
@Bean
@Scope("prototype")
public ShardedJedis shardedJedis() {
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
String[] arrayNode = nodes.split(",");
//node=ip:port
for (String node : arrayNode) {
String host = node.split(":")[0];
int port =
Integer.parseInt(node.split(":")[1]);
JedisShardInfo info =
new JedisShardInfo(host, port);
shards.add(info);
}
return new ShardedJedis(shards);
}
}
1.5.3修改AOP配置
1.6Redis哨兵机制
1.6.1哨兵机制说明
说明:可以引入哨兵机制,实现redis服务器高可用.但是实现高可用的前提条件实现数据的主从同步.
1.6.2部署哨兵服务器
说明:准备3台redis,并且分别修改各自端口号信息.
分别启动3台redis.
1.6.3实现主从配置
1.检查默认条件下 主机状态
1.6.4挂载策略定义
规定: 6379主机 6380/6381当从机.
命令: slaveof 主机IP 主机端口
Slaveof 192.168.226.128 6379
结果:
最终将6380/6381 挂载到6379上.在主机中执行set指令.检查从机是否正常同步数据.
检查主机状态:
1.6.5哨兵工作原理.
实现原理:
1.当哨兵服务启动时,首先监控主机的状态.同时获取主机的详细信息.
2.哨兵会通过心跳检测机制,定期检查主机的状态.
3.如果发现主机超过3次没有响应.则断定主机宕机.开启推选机制.
4.当哨兵推选一台从机当选主机时.其他的服务器都当该主机的从机.
1.6.6编辑哨兵的配置文件
复制哨兵的配置文件
命令: cp sentinel.conf sentinel
1.6.6.1关闭保护模式
1.6.6.2开启后台启动
1.6.6.3配置哨兵监听
1.监听主机的IP地址 端口 选举的票数
1.6.6.4修改哨兵宕机选举的时间
1.6.6.5修改哨兵选举失效的时间
1.6.7哨兵高可用测试
1.命令: redis-sentinel sentinel.conf
2.检查哨兵服务项:
3.高可用测试
当主机宕机之后,检查哨兵是否会选举新的主机.
2.重启主机.测试是否正常
1.6.8问题说明
如果哨兵配置有误,按照下列步骤执行.
1.将redis的全部的服务关闭.
ps -ef |grep redis
kill -9 PID PID PID PID
2.将redis根目录中的sentinel文件删除 之后重新配置即可.
1.6.9Redis入门案例
/**
* 哨兵测试
* 1.配置redis的节点数据集合
* 2.利用哨兵机制连接redis节点.
* 3.用户通过哨兵 实现缓存操作.
*
* 参数1: masterName
*/
@Test
public void testSentinel() {
//配置哨兵的信息
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.226.128:26379");
JedisSentinelPool pool =
new JedisSentinelPool("mymaster", sentinels);
Jedis jedis = pool.getResource();
jedis.set("1909","哨兵搭建成功!!!!");
System.out.println(jedis.get("1909"));
}