Redis
远程字典服务
内存存储,持久化,rdb,aof
高速缓存
发布订阅信息
地图信息分析
计时器,计数器
集群,事务,持久化,多种多样的数据类型
Nosql
Nosql:Not Only SQL(不仅仅是sql)
数据之间没有关系,键值对存储,列存储
大数据高性能
数据类型多样性,不需要设计数据库
大数据的3V:
海量Volume
多样Variety
实时Velocity
大数据的3高:
高并发
高可拓
高性能
阿里巴巴数据架构演进:
安装:
使用docker安装
默认安装最新版
docker pull redis
挂载配置文件:
建立以下目录 /home/redis/myredis/data
复制以下文件到 /home/redis/myredis/redis.conf
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6379:6379 --name myredis -v /home/redis/myredis/myredis.conf:/etc/redis/redis.conf -v /home/redis/myredis/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 000000
-v 数据挂载地址(就是上面的文件地址)
redis-server /etc/redis/redis.conf 以配置文件启动redis,加载容器内的conf文件,最终找到的是挂载的目录 /etc/redis/redis.conf
-requirepass 000000 设置密码 (不然会被当成矿机)
进入容器命令:
docker exec -it myredis redis-cli
输入密码:
auth 000000
000415
使用测试例:
get s1
本教程基于http://t.csdn.cn/OpzpC创建,修改为快速上线版
进入容器内部
docker exec -it myredis bash
退出容器
exit
使用通过docker进行测压(本人测试出现了问题)
docker exec -it myredis redis-benchmark -h localhost -p 6379 -c 100 -n 100000
redis基本知识
redis有16个数据库
默认使用的第0个
大小写无所谓
select 5 表示切换到第5个数据库
DBSIZE 可以查看这个数据库的大小,如果没有存key值(数据),则所占大小默认为0,
keys * 查看当前数据库所有的key
flushdb 清除当前数据库数据
FLUSHALL 清除所有数据库的数据
不同数据库数据不互通
查看所有的key
redis是单线程的,CUP不是redis的性能瓶颈,内存,和带宽才是,所以可以用单线程就够了,还能防止并发问题还有产生切换开销,(但是redis4用了多线程处理异步任务,reids6正式使用IO多线程)
因为redis是内存怪物,只用单线程就不用切换上下文,效率最高
五大数据类型
String
List
Hash
Set
Zset(有序集合)
Redis-Key命令
可以使用Tab进行命令提示(例如输入getr 按下Tab会变成GETRANGE)
常用基础命令
//检查key_name是否存在
exists key_name
//将key_name移动到第num个数据库
move key_name num
//设置num秒之后过期
expire key_name num
//查询key_name的过期剩余时间
ttl key_name
//查看数据类型
type name
String
//在key_name后面追加一个字符串"value"//不存在就是新建
append key_name "value"
//查看长度
strlen
//让String类型的数字自增//++操作
incr key_name
//人String类型的数字增加了num//+=num操作
incrby views 10
//自减操作//--操作
decr key_num
//-=num操作
decrby key_num 10
//截取0到5范围内的String
getrange key_name 0 5
//截取全部String(相当于get key_name)
getrange key_name 0 -1
//替换,把位置1后面的String替换成newstr
setrange key_name 1 newstr
//setex(set with expire) 设置过期时间
setex key_name 10 "hello"
//setnx(Set if not exist) 不存在再进行设置(分布式锁常用)
setnx key_name "hello"
//批量赋值操作
mset k1 v1 k2 v2 k3 v3
//批量获取
mget k1 k2 k3
//原子操作赋值
msetnx k1 v1 k2 v2
//设置对象(json)
set user:1 {name:zhangsan,age:3}
//进行拆分//查询就是更细分
mset user:1:name zhangsan user:1:age 3
List
所有的list是用L开头
//left push //从左边推入
Lpush list_name value
//列出全部
Lrange list_name 0 -1
//列出0到2的值
Lrange list_name 0 2
//从左边移出
Lpop list_name
//从右边移出
Rpop list_name
//查询列表长度
Llen list_name
//移出指定个数的值(取关)
Lrem list_name num value
//截断,剩下1到3的段
Ltrim list_name 1 3
//套娃操作//list1的末尾移到list2的头部
RpopLpush list1_name list2_name
//元素替换//要确保存在(不然会被判越界)
Lset list_name 1 value
//搜索性插入//在value1之后插入value2
Linsert list_name after value1 value2
//搜索性插入//在value1之前插入value2
Linsert list_name before value1 value2
Set
set是集合,里面的值不能重复,唯一性
//添加值
sadd set_name value
//检查是否有这个值
Sismember set_name value
//列出所有元素
Smembers set_name
//移除元素
srem set_name value
//获取set集合里的个数
scard set_name
//随机选出一个元素
Srandmember set_name
//随机选出num个元素
Srandmember set_name num
//移出元素
Spop set_name
//从set1_name移动value元素到set2_name集合
Smove set1_name set2_name value
//以前一个set的不同部分作为返回
Sdiff set1_name set2_name
//相同部分作为返回
Sinter set1_name set2_name
//合并,取并集
Sunion set1_name set2_name
Hash
Map集合
更时候对象的存储
set多个key-value
与String类似
//存入
Hset hash_name key value
//获取
Hget hash_name key
//批量存入
Hmset hash_name key1 value1 key2 value2
//批量获取
Hmget hash_name key1 key2
//所有获取 返回的是一个key跟一个value
Hgetall hash_name
//删除key(value也没了)
Hdel hash_name key
//获取长度
Hlen hash_name
//判断key是否存在
Hexists hash_name key
//获取所有的key
Hkeys hash_name
//获取所有的value
Hvals hash_name
//让对应的hash的对应的key自增
incr hash_name key
//让对应的hash的对应的key自减
decr hash_name key
//让对应的hash的对应的key加num
Hincrby hash_name key num
//让对应的hash的对应的key减num
Hdecrby hash_name key num
//存在不设置,不存在才设置
Hsetnx hash_name key value
Zset
有序集合
存入
//按照num排序存入
Zadd set_name score value
//普通打印所有集合
Zrange set_name 0 -1
//普通打印num1到num2的所有集合
Zrange set_name num1 num2
//获取-inf(负无穷)到+inf(正无穷)排序
Zrangebyscore set_name -inf +inf
//获取排序(在后面加scores)
Zrangebyscore set_name -inf +inf withscores
//获取负无穷到200的排序(在后面带score)
Zrangebyscore set_name -inf 200 withscores
//降序排列(在后面带score)
Zrevrangebyscore set_name -inf 200 withscores
//移出元素
Zrem set_name value
//获取个数
Zcard set_name
Zcount set_name num1 num2
事务
redis单条命令保证原子性,事务不保证原子性
开启事务(multi)
命令入队(许多的Redis命令)
执行事务(exec) / 放弃事务(discard)
编译型异常(类似代码有误)
比如说同一个事务赋值再读取,会出现错误
运行时异常(类似1/0)
比如说插入一个命令失败了,但是其他命令还能正常运行
乐观锁
很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断下,在此期间是否有人修改过这个数据,
获取version
更新的时候比较version
//监控
watch
//取消监控
unwatch
秒杀系统用的
Jedis
java与redis的中间件
新建项目
项目里建立maven包
依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.3</version>
</dependency>
链接模板
package com.lkw;
import redis.clients.jedis.Jedis;
public class TestPing {
public static void main(String[] args) {
Jedis jedis=new Jedis("192.168.199.131",6379);
jedis.auth("000415");
System.out.println(jedis.get("key" ));
}
}
事务模拟:
package com.lkw;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class TestTX {
public static void main(String[] args) {
Jedis jedis=new Jedis("192.168.199.131",6379);
jedis.auth("000415");
//创建json
JSONObject jsonObject=new JSONObject();
jsonObject.put("hello","world");
jsonObject.put("name","lkw");
String josn2str=jsonObject.toJSONString();
//创建事务
Transaction multi = jedis.multi();
try{
multi.set("user1",josn2str);
multi.set("user2",josn2str);
//模拟异常事务
int i=1/0;
}catch (Exception e){
//放弃事务
multi.discard();
e.printStackTrace();
}finally {
System.out.println(jedis.get("user1"));
System.out.println(jedis.get("user2"));
jedis.close();
}
}
}
Springboot整合
在spring-data
spring-data也是类似于springboot一样的整合怪
在Springboot2.x之后jedis换成了lettuce
jedis采用的直连,多线程是不安全的,如果要避免就要选择jedis pool
lettuce:采用netty,可以在多个线程共享
略
Redis.conf
略
Redis持久化
数据保存在硬盘(快照)
RDB:
AOF操作
类似命令日志记录
默认不开启
大数据形式效率低
这个命令用于修复
redis-check-aof --fix appendonly.aof
修复后数据丢失
Redis发布订阅
可以用消息队列代替
消息发送者:
频道:
消息接收者:
Redis主从复制
主从复制读写分离,主redis处理写请求,从redis处理读请求
作用:
数据冗余
故障恢复
负载均衡
高可用(集群)基石
默认自己是主库,所以只用配置从库就行,
查看当前库的信息
info replication
伪集群:复制配置文件,然后改端口,改pidfile,改日志服务名
对于docker可以重新创建容器,改端口,改映射文件,之类的
slaveof host_name port_name
//要认谁当老大
//slave奴隶
或者在配置文件配置
然后配置文件配置老大机 密码
全量复制:全部复制
增量复制:只复制后继内容
slaveof no one
//设置成没有老大,然后自己变成老大
这个是手动
哨兵可以自动转移
哨兵模式
自动选举老大的模式
多哨兵模式,(哨兵的集群)
哨兵的配置文件:sentinel.conf
基本内容:
sentinel monitor myredis 127.0.0.1 6379 1
1代表主挂掉了会进行投票
主机掉线再回来,就只能当奴隶了
如果有哨兵集群,就要记得改变哨兵的端口
配置主机从机密码
故障转移时间也能设置
通知脚本:可以启动sh脚本,传输什么什么信息
缓存穿透缓存击穿和雪崩
面试高频
缓存穿透
布隆过滤器:一种数据结构,对有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
导致的问题:
1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键
2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一-段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
缓存穿透与缓存击穿的区别
缓存穿透:查询不存在的数据,缓存和存储都没有命中,
缓存击穿:不小心某个热点key过期,导致大量请求传到存储层(mysql)
雪崩
缓存集中过期
redis宕机