Redis
Redis
远程连接使用参数 -h
Redis是一个开源的key-value存储系统
Redis的名字是Remote Dictionary Server的缩写。
数据类型
数据类型 | 应用场景 |
---|---|
string | 分布式Session存储 分布式数据库ID 计数器:统计网站访问量 |
hash | 存储对象信息(购物车中的商品信息) 存储表的信息 |
list | 实现队列、栈操作 汇总日志 粉丝列表 关注的人列表 |
set | 签到 打卡 点赞 |
zset | 排行榜 百度热点搜索 |
geospatial | 获取地理位置信息 两地之间的距离 |
hyperloglogs | 基数统计 |
bitmaps | 统计用户访问次数 |
操作都是原子性的
- String
- 二进制安全,可以包含任何数据,最大容量是512M
- list,技巧, l开头
- 底层是双向链表
- 有序可以重复的数据类型
- 值在键在,值光键亡
- set类型,技巧,s开头
- string类型的无序集合
- 它底层其实是一个value为null的hash表
- 会自动去重
- hash类型,h开头
- 可以当做Java中的Map<String,String>对待
- 特别适合用于存储对象
- zset类型
- string类型元素的集合,且不允许重复的成员
- 关联一个double类型的分数
- 通过分数从小到大的排序
- 分数(score)却可以重复
数据类型使用
- KEY操作
- 多个单词用“:”分开。例如:“user:token:session:id”
- Redis命令不区分大小写,Key区分大小写
- keys *查看当前库所有key
- exists key判断某个key是否存在
- type key 查看你的key是什么类型
- del key 删除指定的key数据--------重点
- unlink key 根据value选择非阻塞删除
- EXPIRE KEY SECONDS(多少秒过期) 重点,过期会被Redis移除。
- ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
- select number 切换数据库,默认有0-15个
- flushdb清空当前库
- flushall通杀全部库
- string操作
- SET key value (重点) 添加键值对
- GET key(重点) 获取指定 key 的值
- APPEND KEY VALUE 追加到原值的末尾
- STRLEN KEY 返回字符串长度
- SETNX key value 只有在 key 不存在时设置 key 的值。
- INCR key(重点) 将 key 中储存的数字值增一,如果为空,新增值为1
- incrby 自定义步长
- DECR key 将 key 中储存的数字值减一。如果为空,新增值为-1
- decrby 自定义步长
- MSET KEY VALUE 同时设置一个或多个key-value对,
- MGET KEY 同时获取一个或多个value
- MSETNX KEY VALUE 原子性,有一个失败则都失败
- GETRANGE KEY START END 类似java中的substring,前包,后包
- SETEX key seconds value(重点) 设置键值的同时,设置过期时间,单位秒
- list操作
- lpush或rpush key value 从左边或右边插入一个或多个值 重点
- lpush类似于入栈,左边开始放,rpush右边开始放
- lpop或rpop key 从左边或右边吐出一个值,值在键在,值光键亡
- 没有值之后,键也没了
- LRANGE key start stop 按照索引下标获得元素左0开头,右-1开头
- LINDEX key index 按照索引下标获得元素(从左到右)
- LLEN key 返回指定key所对应的list中元素个数
- length
- linsert key BEFORE或AFTER value newvalue 第一个遇到value,插入新值
- LREM key count value 从左边删除n个value
- remove
- LSET key index value 把指定索引位置的元素替换为另一个值
- lpush或rpush key value 从左边或右边插入一个或多个值 重点
- Set操作,里面的成员称为member,自动去重
- SADD key value 将一个或多个member 元素加入到集合 key 中
- SMEMBERS key 取出该集合的所有值
- SISMEMBER key value 判断是否含有该值
- SCARD key 返回集合中元素的数量
- SREM key value 删除集合某个元素
- SPOP key 随机从该集合中吐出一个值
- SINTER key1 key2 返回两个集合的交集元素
- SUNION key1 key2 返回两个集合的并集元素。
- SDIFF key1 key2 返回两个集合的差集元素
- Hash操作
- HSET key field value 将哈希表 key 中的字段 field 的值设为 value
- HGET key field 获取存储在哈希表中指定字段的值
- HMSET key field value 批量设置hash的值
- HEXISTS key field 判断是否存在某个字段
- HKEYS key 获取所有哈希表中的字段
- HVALS key 获取哈希表中所有值
- zset操作
- ZADD key score1 value1 增加一个或多个元素
- ZRANGE key start stop [WITHSCORES] 获得排名在某个范围的元素列表
- WITHSCORES(可选),可以让分数一起和值返回到结果集
- ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
- 在分数的指定区间内返回数据
- ZREM key value 删除元素,可以删除多个
- ZRANK key value 先对分数进行升序排序,返回集合中的排名。排名从0开始
Jedis
为了使java程序访问jedis,禁用Linux的防火墙
redis.conf中注释掉bind 127.0.0.1(75行) ,然后 protected-mode(94行) 的值设置为no
引入Jedis的依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
使用代码
//指定Redis服务器的IP地址和端口号
Jedis jedis = new Jedis("Jedis服务器的IP地址", 6379);
//jedis的方法是与jedis的命令一一对应的
//存储一个键值对
jedis.set("tom:code","123456");
//根据key获取值
System.out.println(jedis.get("tom:code"));
//关闭连接
jedis.close();
Jedis的连接池
//测试使用Jedis连接池
//1. 创建连接池
JedisPool jedisPool = new JedisPool("192.168.141.136",6379);
//2. 我们可以对连接池进行配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
//最大连接数
poolConfig.setMaxTotal(20);
//最大闲置连接数
poolConfig.setMaxIdle(20);
//最小闲置连接数
poolConfig.setMinIdle(0);
poolConfig.setMaxWaitMillis(3000);
//3. 使用连接池获取连接
Jedis jedis = jedisPool.getResource();
System.out.println(jedis.get("username"));
//归还连接
jedis.close();
Redis事务控制
命令名 | 作用 |
---|---|
MULTI | 表示开始收集命令,后面所有命令都不是马上执行,而是加入到一个队列中。 |
EXEC | 执行MULTI后面命令队列中的所有命令。 |
DISCARD | 放弃执行队列中的命令。 |
WATCH | “观察“、”监控“一个KEY,在当前队列外的其他命令操作这个KEY时,放弃执行自己队列的命令,相当于加入事务 |
UNWATCH | 放弃监控一个KEY |
入队过程中某个命令出现了报告错误,执行时整个的所有队列都会被取消。
如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。
主从复制机制
主机数据更新后根据配置和策略, 自动同步到备机的master/slave机制,
Master以写为主,Slave以读为主
主从复制的目的
- 性能优化:主服务器专注于写操作,可以用更适合写入数据的模式工作;同样,从服务器专注于读操作,可以用更适合读取数据的模式工作。
- 强化数据安全,避免单点故障:由于数据同步机制的存在,各个服务器之间数据保持一致,所以其中某个服务器宕机不会导致数据丢失或无法访问。从这个角度说参与主从复制的Redis服务器构成了一个集群。
搭建思路
集群在运行时使用的是同一个可执行文件(redis-server),只是对应的配置文件(redis.conf)不同。
- 拷贝多个redis.conf文件include(写绝对路径)
- 开启daemonize yes
- Pid文件名字pidfile
- 指定端口port
- Log文件名字
- dump.rdb名字dbfilename
- Appendonly 关掉
- replica-priority 10
- 设置从机的优先级,值越小,优先级越高
运行redis开启服务后进入服务 查看主从关系
info replication
配置主从关系(否则默认每台都是主机)
从机上指定主机的地址和端口号即可
SLAVEOF 127.0.0.1 6000
取消主从关系
从机上执行命令SLAVEOF NO ONE
即可,那么此时从机就自己变成了主机
有以下现象
-
主机关闭之后,会等待主机上线
-
从机关闭之后,需要从新设置主从关系
-
设置之后,之前的命令同步
哨兵模式
主机故障后,从机根据优先级,自动升级为主机,原主机上线后成为从机
新建sentinel.conf文件
sentinel monitor 主机名称 127.0.0.1 主机端口号 1
1是指需要几个哨兵同意
执行redis-sentinel sentinel.conf
缓存穿透
- 服务器压力突然增大
- 大量的请求
- redis命中率降低
- 一直查询不存在的数据
- 缓冲中没有该数据
- 一直查询数据库
- 缓冲查询不到则查询数据库导致崩溃
key对应的数据在数据源并不存在,请求都会压到数据源,可能压垮数据库
解决办法
- 对空值缓存
- 不管是数据是否不存在
- 空结果(null)进行缓存
- 设置空结果的过期时间,不超过五分钟
- 临时应急方案
- 设置可访问的名单(白名单)
- 使用bitmaps类型(位操作)定义一个可以访问的名单
- 如果访问id不在bitmaps里面,进行拦截
- 效率不高
- 采用布隆过滤器
- 布隆过滤器可以用于检索一个元素是否在一个集合中
- 缺点是有一定的误识别率和删除困难
- 进行实时监控
- 排查访问对象和访问的数据
- 设置黑名单限制服务
缓存击穿
- 数据库访问压力瞬间增加
- redis没有发现大量key过期
- redis正常运行
- 原因
- redis某个key(比较热门的key)过期了,大量访问使用这个key
- 这个时候大并发的请求可能会瞬间把后端数据库压垮。
数据存在,但在redis中过期,若有大量并发请求过来,
请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存
这个时候大并发的请求可能会瞬间把后端DB压垮
解决办法
- 预先设置热门数据
- 热门数据提前存入到redis里面,加大这些热门数据key的时长
- 实时调整
- 现场监控哪些数据热门,实时调整key的过期时长
- 使用锁
- 效率低
缓存雪崩
- 数据库压力变大
- 造成服务器崩溃
- 原因
- 极少时间段,查询大量key的集中过期情况
缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key
正常访问
解决办法
- 构建多级缓存架构
- nginx缓存 + redis缓存 +其他缓存(ehcache等)
- 使用锁或队列
- 不适用高并发情况
- 设置过期标志更新缓存
- 记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
- 将缓存失效时间分散开
- 原有的失效时间基础上增加一个随机值
- 1-5分钟随机,缓存的过期时间的重复率就会降低