Redis入门
NoSQL概述
NoSQL = Not Only SQl (不仅仅是SQL)
泛指关系型数据库,很多的数据类型用户的个人信息,社交网络,地理位置,这些数据类型的存储不需要一个固定的格式,不需要过多的操作就可以横向扩展
特点
- 方便扩展(数据之间没有关系,很好扩展)
- 大数据量高性能(NoSQL的缓存记录级,是一种细粒度的缓存,性能比较高)
- 数据类型是多样性的(不需要事先设计数据库)
Redis概述
Redis(Remote Dictionary Server)即远程字典服务
一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的内存日志、Key-Value数据库,并提供多种语言的API。
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并在此基础上实习了master-slave(主从)同步
功能
- 内存存储、持久化(rdb、aof)
- 效率高,可以用于高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器、计数器
特点
- 多样的数据类型
- 持久化
- 集群
- 事务
Linux环境下安装
-
下载安装包
[Redis](https://redis.io/)
-
解压Redis的安装包
-
进入解压后的文件,可以看见redis的配置文件
redis.conf
-
安装基本环境
yum install gcc-c++ make make install
-
redis的默认安装路径为
/user/local/bin
-
复制redis的配置文件到当前目录下
-
redis默认不是后台启动的需要修改配置文件
-
启动redis redis-server ccbyconfig/redis.conf
-
连接redis redis-cli -p 6379
基础知识
redis默认有16个数据库,默认使用第0个数据库,可以使用select
进行切换
127.0.0.1:6379> select 3 # 切换到数据库3
OK
127.0.0.1:6379[3]> DBSIZE 查看DB大小
(integer) 0
127.0.0.1:6379[3]> set name zhangsan
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 1
keys * #查看所有的key
flushdb # 清空当前数据库
FLUSHALL # 清空全部数据库
Redis是单线程的
五大基本数据类型
Redis - Key
EXUSTS # 判断当前的key是否存在
move # 移除当前的key
EXPIRE key time # 设置key的过期时间,单位是秒
ttl key # 查看当前key的剩余时间
type key # 查看当前key的类型
String(字符串)
APPEND key # 向key中追加字符串,如果当前key不存在,就相当于set key
STRLEN # 获取字符串长度
incr key # 自增1
decr key # 自减1
INCRBY key num # 设定步长 自增num
DECRBY key num # 自减num
GETRANGE key start end # 查看start到end 从0开始
SETRANGE key start string # 从start替换为string
setex # 设置过期时间
setnx # 不存在则设置,若存在则不修改
mset k1 v1 k2 v2 k3 v3 # 批量添加mget k1 k2 k3 # 批量获取msetnx k1 v1 k4 v4 # 判断不存在则添加,为原子性操作,一个失败全部失败
# 对象 json字符来保存对象set user:1 {name:zhangsan,age:20}mset user:1:name zhangsan user:1:age 20mget user:1:name user:1:age
getset # 先get再set 如果不存在值,则返回nil ,如果存在,获取原来的值,并设置新的值
List(列表)
基本数据类型,列表,所有的list命令都是l开头的
LPUSH list v1 v2 ... # 将一个或者多个值插入到列表头部RPUSH list v1 v2 ... # 将一个或者多个值插入到列表尾部LRANGE list start end # 查看从start到end 若end为-1 则查看全部
LPOP list # 移除第一个元素RPOP list # 移除第二个元素
LRANGE list num # 通过下标num获得值
LLEN list # 返回列表长度
Lrem list num string # 移除List中的num个string
ltrim list num1 num2 # 截取num1到num2的值,会改变list
rpoplpush list1 list2 # 将列表1的最后一个元素移动到列表2中
EXISTS list # 判断list是否存在lset list 0 string # 如果存在则更新,不存在则报错
linsert list before string1 strinig2 # 将string2插入到string1前面linsert list after string1 strinig2 # 将string2插入到string1后面
Set(集合)
Set中的值不能重复
sadd set string # 向set集合中添加元素smembers set # 查看指定set的所有值scard set # 获取set集合中的内容个数srem set string # 移除set集合中的指定元素srandmember set num # 随机抽出指定格式的元素
spop set # 随机删除集合中的一个元素
smove set1 set2 string # 将string从set1移动到set2
sdiff set1 set2 # 查找set1与set2中不同的元素sinter set1 set2 # 查找set1与set2的交集sunion set1 set2 # 并集
Hash
Map集合,key-map
hset hash key value # 向hash中存入key-valuehget hash key # 查询值hmset hash k1 v1 k2 v2 ... # 连续添加值hmget hash k1 k2 # 获取多个值hagetall hash # 获取全部数据
hdel myhash k1 # 删除k1
hlen # 获取有多少个键值对
hexists hash key # 判断指定字段是否存在
hkeys hash # 获取所有的keyhvals hash # 获取所有的value
hincrby hash key num # 指定key中的value增加numhsetnx hash key value # 如果不存在则可以设置,存在不能设置
Zset(有序集合)
在set的基础上,增加了一个值,set k1 v1 — zset k1 score v1
# 添加zadd set 1 onezadd set 2 two 3 three# 查看全部zrange set 0 -1
# 排序zrangebyscore set -inf +inf # 从负无穷(-inf)到正无穷(+inf)排序,安装中间那个数字zrangebyscore set -inf +inf withscores # 附带成绩 zreveramge set 0 -1 # 从大到小排序
# 移除 zrem set value
zcount set num1 num2 # 获取num1和num2之间的成员数量
三种特殊类型数据
geospatial 地理位置
# 添加 # 规则:两级无法直接添加,一般会下载城市数据,直接通过Java程序一次性导入geoadd key 经度 维度 名称
# 获取getpos key 名称 名称 ...
geodist key 名称 名称 (单位) # 两地之间的距离m 米 km 千米 mi 英里 ft 英尺
georadius key 经度 维度 距离 (单位) (withdist 显示距离) (withcoord 显示目标的经纬度) (count 1 (显示数量:1)) # 在key中以给定的经纬度为中心查询距离为半径的目标 georadiusbymember key 名称 num # 查询名称num内的目标
geo底层的实现原理其实就是Zset,我们可以使用Zset命令来操作geo
Hyperloglog
统计不重复的数据
**优点:**占用内存是固定的,2^64不同元素的数据,只需要12KB内存
有0.81%的错误率
# 添加pfadd key v1 v2 v3 v4# 查看pfcount key # 产看不重复的元素有多少个# 合并pfmerge k3 k1 k2 # 将k1和k2合并到k3
Bitmap
操作二进制来进行记录,只有0和1两个状态
setbit key 0 0/1 # 0的状态是0或者1 get key 0 # 获取0的状态bitcount key # 统计是1有多少
事务
Redis事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中,会按顺序执行
一次性、顺序性、排他性 执行一系列的命令
Redis事务没有隔离级别的概念
所有的命令在事务中,并没有直接被执行,只有发起执行命令的时候才会执行
Redis单条命令保证原子性,但是事务不保证原子性
redis事务:
- 开启事务(multi)
- 命令入队(输入命令)
- 执行事务(exec)
取消事务:discard
若出现编译型异常,事务中所有命令都不会执行,若出现运行时异常,其他命令还是可以正常执行的
悲观锁
认为什么时候都会出错。无论做什么都会加锁
乐观锁
认为什么时候都不会出问题,所以不会上锁,更新数据的时候去判断,在此期间时候有人修改过这个数据
- 获取version
- 更新时比较version
watch key # 目标进行监视在事务执行之前另外一个线程修改了值,就会导致事务执行失败
unwatch # 放弃监视
Jedis
使用Java操作Redis
Jedis是Redis官方推荐的Java连接开发工具,使用Java操作Redis中间件
-
导入依赖
<dependencies> <!--jedis--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.2.0</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency></dependencies>
-
检测连接
public class TestPing { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); System.out.println(jedis.ping()); }}
所有的命令与Linux中的命令相同
SpringBoot整合
在SpringBoot2.x之后,原来使用的 jedis 被替换为了 lettuce
- jedis:采用的直列,多个线程操作的话,是不安全的,如果想要避免不安全的,使用jedis pool 连接池
- lettuce:采用netty,实例可以在多个线程中共享,不存在线程安全的清空,可以减少线程数据
# 配置redisspring.redis.host=127.0.0.1spring.redis.port=6379
redisTemplate.opsForValue 操作字符串 类似StringopsForList 操作List opsForSetopsForHashopsForZSet opsForGeoopsForHyperLogLog
//获取redis的连接对象RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();connection.flushDb();connection.flushAll();
Redis持久化
Redis是内存数据库,如果不能将内存中的数据状态保存到磁盘,一旦服务器进程退出,服务器中的数据库状态也会消失
RDB(Redis DataBase)
在指定时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程不进行如何IO操作。如果需要进行大规模数据的恢复,且对数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。RDB的缺点是最后一次持久化后的数据课呢丢失
RDB保存的文件是dump.rdb 可在配置文件中进行配置
触发机制
- save的规则满足的情况下,会自动触发RDB规则
- 执行flushall命令,也会触发RDB规则
- 退出Redis,也会产生RDB文件
恢复RDB文件
只需要将RDB文件放在我们redis启动目录就可以,redis启动就会自动检查dump.rdb恢复其中的数据
优点
- 适合大规模的数据恢复
- 对数据的完整性要求不高
缺点
- 需要一定的时间间隔进程操作,如果redis意外宕机了,最后一次修改数据就没有了
- fork进程的时候,会占用一定的内存空间
AOF(Append Only File)
将我们的所有命令都记录下来
以日志的形式来记录每个写操作,将Redis执行过的所有写的操作记录下来,只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,redis重启的话就根据日志文件内容将写指令从前到后执行一次以完成数据的恢复工作
AOF保存的是appendonly.aof文件
如果aof文件有错,这时候redis是启动不起来的,需要修复aof文件,redis给我们提供了一个根据 redis-check-aof --fix
appendonly no # 默认是不开启aof模式的,默认是使用rdb方式持久化的,大部分情况下,rdb完全够用appendfilename "appendonly.aof" # 持久化的文件的名字# appendfsync always # 每次修改都会 sync 消耗性能appendfsync everysec # 每秒执行一次 sync 可能丢下这1s的数据# appendfsync no # 不执行 sync 这个时候操作系统自己同步数据,速度最快
优点:
- 每一次修改都同步,文件的完整性会更好
- 每秒同步一次,可能会丢失一秒的数据
- 从不同步,效率最高
缺点
- 相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢
- aof运行效率也要比rdb慢
Redis发布订阅
# 订阅端
subscribe key # 订阅一个频道
# 发送端
publish key value # 向key频道中发布一个消息`
Redis主从复制
概述:
将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower),**数据复制是单向的,只能由主节点到从节点。**Master以写为主,Slave以读为主
主从复制的作用主要包括:
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复
- 负载均衡:在主从复制的基础上,配合读写分离,主节点提供写服务,从节点提供读服务
- 高可用基石:是哨兵和集群能够实施的基础
只配置从库,不配置主库
slaveof 127.0.0.1 6379 # 将6379设为当前库的主库
在配置文件中配置为永久配置
主机可以写,但是从机不可以,主机中的所有信息和数据都会被从机保存
**全量复制:**slave服务在接收数据库文件数据后,将其存盘并加载到内存中
**增量复制:**Master继续将新的所有收集到的命令依次传给slave,完成同步
只要重新连接master,就进行一次全量复制
哨兵模式
Redis提供了哨兵命令,哨兵是一个单独的进程,作为进程,它会独立运行,其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控多个Redis实例。
哨兵的两个作用
- 通过发送命令,让Redis服务器返回监控运行状态,包括主服务器和从服务器
- 当哨兵检测到master宕机,自动将slave切换成master,然后通过发布订阅模式通知其他从服务器,修改配置文件,切换主机
# sentinel.conf 哨兵配置文件sentinel monitor myredis 127.0.0.1 6379 # sentinel monitor 被监控的名称 host port 1 (1代表主机挂了,从机投票看让谁接替主机)
# 启动配置文件redis-sentinel kconfig/sentilnel.conf
优点
- 基于主从复制模式,所有主从配置优点全部都要
- 主从可以切换,故障可以转移,系统的可用性更好
- 手动到自动,更加健壮
缺点
- Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦
- 实现哨兵的配置较麻烦
Redis缓存穿透与雪崩
缓存穿透(查不到)
- 布隆过滤器
- 设置空值
缓存击穿(访问量太大,缓存过期)
- 设置热点数据永不过期
- 加互斥锁
缓存雪崩(某一个时间段,缓存集中失效,缓存服务器某个节点宕机或者断网)
- redis高可用
- 限流降级
- 数据预热