1、redis 是 nosql 数据库,不仅仅只有sql
redis是目前使用比较广泛的缓存技术,redis数据都是在内存中存放的所以在获取过程中可以直接获取,从而减少执行时间
2:redis支持的数据类型
五大类型的数据结构
String:
字符串类型,使用最多的类型,value可以是任何数据,只要将数据转换为String即可,常用的方式是通过JSON转换
常用命令:
获取:get key 、添加:set key value
list:
列表,通常可用于模拟栈、队列
常用命令:
插入数据在最左侧:lpush key value
插入数据在最右边:rpush key value
获取数据:lrange key start end
hash:
hash(散列),可用于投票、关注、购物车等
常用命令:
插入数据:hset key field value field2 value
获取数据:hset key field
获取所有:hgetall key
set:
集合,可用于差集、交集、并集等业务场景
常用命令:
插入数据:sadd key value
获取数据:smembers key
随机获取并移除集合中的元素:spop key
获取key1不存在key2的差集:sdiff key1 key2
获取所有给定的并集:sunion key1 key2
获取给定集合的交集:sinter key1 key2
随机返回给定集合的一个元素:srandmember key
zset:
有序集合,可用于排名,排序等业务场景
常用命令:
添加:zadd key score member
获取所有:zcard key
命令详情可参考Redis 有序集合(sorted set) | 菜鸟教程
或者官网
3:redis geo 主要用于位置信息,并对位置信息进行操作
如:获取geodist key1 key2 可获取两个key之间的距离
georadius 经度 纬度 range(m/km)可获取指定坐标range内的数据
还有不常用的HyperLogLog等
4:安装redis
# 直接安装,
yum install redis
# 启动
systemctl start redis
# 查看安装位置
whereis redis
# 下载zip
unzip redis
# 安装环境
yum install gcc-c++
# 编译,进入redis 目录
make
# 安装,最后出现src目录,安装成功
make install
# 进入src启动
redis-server ../redis.conf
redis 默认不是后台运行的:
修改配置文件:redis.conf
daemonize no 为 yes 可后台运行
bind 127.0.0.1 修改ip可远程访问
port 6379 默认端口6379
requirepass foobared 设置密码,默认是没有密码的
5:持久化 rdb 和 aof,数据恢复是自动的,只要重启redis会自动加载这些文件
rdb:默认是开启的,如果服务器意外宕机,重启服务后会默认加载这些记录文件
save 900 1 每隔900秒有一个修改命令,则保存一次
save 300 10
save 60 10000
可根据业务进行修改,触发之后会在redis下创建一个dump.rdb文件
优点:高效,redis会启动两个进程,主进程主要处理业务,子进程进行记录,
缺点:在宕机之前未触发的命令会丢失
如果对数据的完整性不敏感可使用该方式
aof:默认是关闭的
appendonly no 修改为 yes 即开启aof持久化
会在redis文件夹下生成appendonly .aof文件,所有的写操作都会被记录
如果aof被破坏redis是启动不了的,
使用redis-check-aof 工具进行恢复即可命令:redis-check-aof --fix appendonly .aof
优点:数据完整性高,基本不会丢失数据,每次修改都会同步
缺点:aof文件远大于rdb,修复速度比rdb慢,运行效率也比rdb慢,aof记录是无限增加的,数据量会越来越大
6:主从配置,修改配置即可实现集群的搭建,主机可读可写,从机只能度不能写,否则报错。
如果使用命令配置主从关系,宕机重启后从机会恢复为主机,只有修改配置文件才是永久。
从机(slave)重启重新链接后会同步主机(master)中的数据,
并且是全量复制,然后加载到内存中
主从配置方式一:
这种方式如果主机宕机从机不会成为主机,会造成只能读,不能写的状态,
哨兵模式(主机宕机之后从机自动选举主机)
在redis文件夹下创建文件(哨兵配置文件):vim sentinel.conf
输入:
sentinel monitor mymaster 127.0.0.1 6379 1
保存退出
src 下有 redis-sentinel ,运行 :./redis-sentinel ../sentinel.conf 启动哨兵
每一台服务都需要配置哨兵,最后会形成哨兵集群,配置文件就会涉及到
端口、主机密码、故障转移时间等等配置,上边这个配置是主要配置
穿透:
是指用户访问的数据在缓存中不存在(没有命中),然后去查数据库,数据库中也没有,于是当前查询失败,当很多用户都去访问,缓存没有命中、都去请求数据库,给数据库造成压力,就相当于出现了缓存穿透
解决方式:增加条件过滤器、缓存空值等
击穿:
一个热key,所有人都在访问同一个数据,导致压力倍增,当key扛不住压力或者失效瞬间,持续的大并发就穿破缓存,直接请求数据库。
解决方式:
热key过期时间做延长处理、加锁(同一时间内只能有一个线程进行访问)等
雪崩:
是指在某一时间段,缓存集中过期失效,redis宕机;所有请求数据库,导致数据库访问量暴增,造成数据库宕机的情况
springboot集成redis
导入redis
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>springboot 提供了一个RedisTemplate 类,
redisTemplate.opsForValue 是操作String类型的 redisTemplate.opsForList 列表 redisTemplate.opsForHash hash redisTemplate.opsForSet 集合 redisTemplate.opsForZSet 有序集合一些公用的方法直接使用:redisTemplate 调用即可
常用的开发方式是创建一个RedisService 注入RedisTemplate,来简化redisTemplate原生的复杂性,如下。然后使用的时候直接注入redisService 即可
@Service public class RedisService implements IRedisService { @Autowired private RedisTemplate redisTemplate; /** * 创建key-value 添加 * * @param key * @param value * @param time */ public void set(String key, Object value, Long time) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } /** * 获取key 对应的数据 * * @param key * @return */ public Object get(String key) { return redisTemplate.opsForValue().get(key); } public Object del(String key) { return redisTemplate.delete(key); } /** * list 数据结构类型的数据添加数据(添加到最右边) * * @param key * @param value */ public void rightPush(String key, List<Object> value) { redisTemplate.opsForList().rightPush(key, value); } /** * list 数据类型的数据结构添加数据(添加到最左边) * * @param key * @param value */ public void leftPush(String key, List<Object> value) { redisTemplate.opsForList().leftPush(key, value); } /** * list 数据类型的数据结构删除数据(删除最左边) * * @param key */ public void leftPop(String key) { redisTemplate.opsForList().leftPop(key); } /** * list 数据类型的数据结构删除数据(删除最右边) * * @param key */ public void rightPop(String key) { redisTemplate.opsForList().rightPop(key); } public void listSize(String key) { redisTemplate.opsForList().size(key); } public void setAdd(String key, Object value) { redisTemplate.opsForSet().add(key, value); } /** * 获取set中所有元素 * * @param key */ public void setMembers(String key) { redisTemplate.opsForSet().members(key); } /** * 随机删除set中的一个元素 * * @param key */ public void setPop(String key) { redisTemplate.opsForSet().pop(key); } public void setSize(String key) { redisTemplate.opsForSet().size(key); } /** * 交集----返回key1,key2中都存在的数据 * * @param key1 * @param key2 */ public void intersect(String key1, String key2) { redisTemplate.opsForSet().intersect(key1, key2); } /** * 并集----返回key1,key2 合并之后的数据 * * @param key1 * @param key2 */ public void union(String key1, String key2) { redisTemplate.opsForSet().union(key1, key2); } /** * 差集----返回key1中不存在key2中的数据 * * @param key1 * @param key2 */ public void difference(String key1, String key2) { redisTemplate.opsForSet().difference(key1, key2); } /** * 随机获取出set中的一个元素,或获取指定个数的元素 * * @param key */ public void setRandm(String key, Integer num) { if (num != null && num > 0) { redisTemplate.opsForSet().randomMembers(key, num); } redisTemplate.opsForSet().randomMember(key); } /** * hash 结构数据添加 * * @param key * @param value */ public void mapAdd(String key, Map value) { redisTemplate.opsForHash().putAll(key, value); } /** * hash 结构数据添加,指定hashKey添加 * * @param key * @param value */ public void mapAdd(String key, String hashKey, Object value) { redisTemplate.opsForHash().put(key, hashKey, value); } /** * 获取hash中所有的数据 * * @param key */ public void mapGet(String key) { redisTemplate.opsForHash().entries(key); } /** * 获取hash中指定key的数据 * * @param key */ public void mapGet(String key, String hashKey) { redisTemplate.opsForHash().get(key, hashKey); } /** * 删除指定key * * @param key * @param hashKey */ public void mapDel(String key, String hashKey) { redisTemplate.opsForHash().delete(key, hashKey); } public void zsetAdd(String key, Set<Object> value) { redisTemplate.opsForZSet().add(key, value); } public Long zsetCount(String key) { Long aLong = redisTemplate.opsForZSet().zCard(key); return aLong; } public void zsetGet(String key, Integer start, Integer end) { if (start == null || start < 0) { start = 0; } if (end > 0 && end < start) { end = -1; } redisTemplate.opsForZSet().range(key, start, end); }