Redis学习笔记(上)
Redis
remote dictionary server 远程字典服务
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、key-value数据库,并提供多种语言的API。
和 memcached 一样,为了保证效率,数据都是缓存在内存中的。区别的是 redis 会周期性的把更新的数据写入磁盘或者修改操作写入追加的记录文件上,并在此基础上,实现了 master - slave 同步。
NoSql 数据库,Not Only Sql。写入8W,读取11W。
大数据时代的“三V,三高“问题:
三V(主要是描述问题):
- 海量Velume
- 多样Variety
- 实时Velocity
三高(主要是描述对程序的要求):
- 高并发
- 高可扩展
- 高性能
redis能做什么
- 内存存储,持久化,内存中是断电及失的,所以持久化很重要(rdb, aof)
- 效率高,可以用于高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器、计数器
- 。。。
特性
- 多样的数据类型
- 持久化
- 集群
- 事务
redis 是单线程的,基于内存操作,CPU 并不是 Redis 的性能瓶颈,Redis 的性能瓶颈是根据机器的内存和网络带宽
既然可以使用单线程来实现,就使用单线程了。
Redis 是C语言写的,官网的数据未 100000+ 的 QPS。
redis是单线程的,为什么还这么快?
误区:
- 高性能的服务器都是多线程的
- 多线程一定比单线程要快
redis 是将所有的数据全部放到内存中,所以说使用单线程操作效率就是最高的,多线程会带来上下文切换的 CPU 操作,是比较耗时的,大概 2000 纳秒。对内存来说,不存在上下文切换效率就是最高的。多次读写都在一个 CPU 上,在内存情况下,这个就是最佳方案。
Redis 安装
此处不过多赘述安装过程。
![image-20230706161927876](/Users/radish/Library/Application Support/typora-user-images/image-20230706161927876.png)
- Redis-benchmark
- 性能检测工具
- Redis-check-aof
- Aof 文件修复工具
- Redis-check-rdb
- Rdb 文件修复工具
- Redis-sentinel
- 哨兵模式
- Redis-cli
- Redis-server
reids 数据类型
Redis 是一个开源(BSD 许可),内存存储的数据结构服务器,可以用作数据库,高速缓存,消息队列代理。
它支持字符串 String,哈希表 Hash,列表 List,集合 Set,有序结合 SortedSet,位图,hyperloglogs等数据类型。
内置复制、lua 脚本、LRU 回收、事务以及不同级别磁盘持久化功能,同时通过 Redis Sentinel 提供高可用,通过 Redis Cluster 提供自动分区。
更多命令学习:https://www.redis.net.cn/order/
命令
- set
- get
- keys * 查看所有的 key
- exists name 判断当前 key 是否存在
- move name 移动 key 到另一个库
- ttl name 当前 key 的剩余过期时间
- type name 返回 key 所存储的 value 类型
- append name "value" 追加字符串,如果当前 key 不存在,就相当于 set value
- incr key 自增,计数器
- decr key 递减,计数器
- incrby key 10 增加,计数器
- decrby key 10 减少,计数器
- getrange key 0 3 截取字符串[0,3]
- getrange key 0 -1 截取全部字符串
- setrange key 1 xx 替换指定未知字符串
- setex(set with expire) 设置过期时间
- setnx(set if not exist) 如果不存在则设置(在分布式中会经常使用)
- mset(many set)
- mget(many get)
- msetnx k1 v1 k4 v4 msetnx 是一个原子性操作,要么一起成功,要么一起失败
- getset 如果不存在则返回 null , 存在则返回原来的值,之后设置新的值,先 get, 再 set
String 字符串
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象的存储缓存
List
是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边),一个列表最多可以包含 2^32 -1 个元素(4294967295,每个列表超过40亿个元素)。
在 Redis 中,List 是可以进行双端操作的,所以命令也就分成了 Lxxx 和 Rxxx 两类,个别时候 L 也可以标识 List,因此,可以把 List 用来做栈,队列,阻塞队列。
List 允许 value 重复。
命令
- LPUSH list one 将一个值放在 list 的头部
- LRANGE list 0 -1 获取 list 中值
- LRANGE list 0 1 获取区间的 list 值
- RPUSH list righr 将一个值或多个值,插入到列表尾部(右)
- LPOP list 移除列表的第一个元素
- Rpop list 移除列表的最后一个元素
- LINDEX list 1 通过下标获得 list 中的某一个值
- Lrem key count value 移除 list 中指定的value值,存在重复值,可以指定删除几个
- Ltrim key start stop 截取list,可指定区间,这个 list 会被修改,只存在 截取后的 list
- RpopLpush mylist newlist 移除列表的最后一个元素,并添加到新列表中
- exists list 判断列表是否存在
- LSET list 0 value 设置指定下标位置的值,不存在列表会报错
- Linsert
list 实际上是一个链表,before node after ,left, right 都可以插入值
如果 key 不存在,创建新的链表
如果 key 存在,新增内容
如果移除了所有值,空链表,也表示不存在。
在两边插入或改动值,效率最高。
中间元素,相对效率会低一些。
Set(集合)
Set 中的值是不可以重复的。是 String 类型的无序集合。集合成员是唯一的。实现是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数为 2^32 -1 (4294967295, 每个集合可存储40多亿个成员)。
命令
- sadd set 中添加元素
- sismember set中判断某一个元素是不是存在
- scard 获取集合中的内容元素个数
- srem 移除 set 中的指定元素
- smember 查看全部元素
- srandmemeber 随机抽选出一个元素
- spop 随机删除集合中的元素
- smove 将指定值,移动到另一个 set
- sdiff key1 key2 差集
- sinter key1 key2 交集 共同好友就可以这样实现
- sunion key1 key2 并集
Hash 哈希
key-value,本质上和 String 没什么区别。是一个 String 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
Set 就是一种简化的 Hash,只变动 key,而 value 使用默认值填充。可以将一个 Hash 表作为一个对象进行存储,表中存放对象的信息。
命令
- hset set一个具体key-value
- hmset
- hget
- hmget
- hgetall 获取全部的数据
- hlen 获取hash的内容字段数量
- hexists 判断hash中指定字段是否存在
- hkeys
- hvalues
- hincrby 自增
- hsetnx 如果不存在则设置,如果存在则不能设置
hash变更的数据,更适合存储对象的存储
Zset 有序集合
在 set 的基础上,增加了一个值,可以用来排序。每一个元素都会关联一个 double 类型的分数 (score)。redis 正是通过分数来为集合中的元素进行从小到大的排序。Score 相同,按照字典顺序排序。有序集合的成员是唯一的,但是分数却可以相同。
Geospatial实现地理位置
本质上底层是 Zset,我们可以通过 Zset 来操作 Geo。
通过georadius
就可以完成 附近的人功能
withcoord : 带上坐标
withdist : 带上距离,单位与半径单位相同
COUNT n : 只显示前n个(按距离递增排序)
Hyperloglog (基数统计)
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。
因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
其底层使用string数据类型,所谓基数:数据集中不重复的元素的个数。
BitMaps(位图)
使用位存储,信息状态只有 0 和 1,bitmaps是一串从左到右的二进制串
Bitmap是一串连续的2进制数字(0或1),每一位所在的位置为偏移 (offset),在 Bitmap 上可执行AND,OR,XOR,NOT以及其它位操作。
应用场景
签到统计、状态统计
事务
redis 事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
一次性、顺序性、排他性!执行一系列的命令。
redis 事务没有隔离级别的概念
所有的命令在事务中,没有被直接执行,需要发起执行命令的时候才会执行。
redis 的单条命令是原子性的,但是事务不保证原子性!
reids 的事务:
- 开启事务(multi)
- 命令入队(set k1 v1)
- 执行事务(exec)
- 取消事务(discard)
取消事务后,整个事务内容都不会被执行。
事务中的异常:
- 编译型异常,事务中所有的命令都不会正常执行
- 运行时异常,eg:语法错误,事务中其他的命令可以正常执行
监控 Watch
- 悲观锁
- 无论干什么,都加锁,很悲观,认为什么时候都会出现问题
- 乐观锁
- 更新数据的时候判断下,在此期间是否有人改过,很乐观,认为什么时候都不会出问题
- 获取version
- 更新的时候比对 version
watch key : 监视 key 对象
如果获取失败,就会释放锁 unwatch,之后重新获取锁 watch。
每次提交执行 exec 后都会自动释放锁,不管是否成功。
Jedis
Jedis 是 redis 的官方推荐的 java 链接开发工具! 使用 java 操作 redis 中间件。
在 springBoot 2.x 后,原来使用的 Jedis 被 lettuce 替换。注意连接池配置一定要使用 Lettuce 的连接池。
jedis:采用的直连,多个线程操作的话,是不安全的。如果要避免不安全,使用jedis pool连接池!更像BIO模式
lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况!可以减少线程数据了,更像NIO模式
通过阅读源码,可以看到,在 Reids Template 上也有一个条件注解,说明我们可以对其进行客制化。因此当我们创建一个 bean 加入容器,就会触发 Redis Template 上的条件注解使默认的 Redis Template 失效。
如果出现对象在 redis 中乱码的问题,这时候就关系到存储对象的序列化问题了。在网络中传输的对象一定要支持序列化,否则就是一片乱码。
生产中需要将 redis 的很多公共 API 提取成一个工具类。
redis cofig
![image-20230706171508951](/Users/radish/Library/Application Support/typora-user-images/image-20230706171508951.png)
( Redis 单位 )
bind 127.0.0.1 绑定的ip
protected-mode yes 保护模式
daemonize yes 守护进程开启
pidfile /car/redis-6379.pid 如果后台启动,需要指定一个pid文件
loglevel notice 日志级别
logfile 日志文件位置名
database 16 数据库数量,默认16个数据库
always-show-log yes 总是显示log
Redis持久化
RDB redis data base
快照
持久化,在规定的时间呢,执行了多少次操作,则会持久化到文件 .rdb .aof
reids 是内存数据库,如果没有持久化,那么数据断电及失。
save 900 1 在900秒内,如果至少有一个key进行了修改,则保存一次。
stop-writes-on-bgsave-error yes 如果持久化出错了,是否还需要继续工作
rdbcompression yes 是否压缩rdb文件,需要消耗一些cpu资源
rdbchecksum yes 保存rdb文件的时候,进行错误的检查校验
dir ./ rdb文件的保存位置
RE
SECURITY 安全
requirepass 123 redis数据库的密码
限制 CLIENTS
maxclients 10000 最大客户端数量
maxmemory 最大内存
maxmemory-policy noeviction 内存达到上限后的处理策略
maxmemory-policy 六种方式
- volatile-lru:只对设置了过期时间的key进行LRU(默认值)
- allkeys-lru : 删除lru算法的key
- volatile-random:随机删除即将过期key
- allkeys-random:随机删除
- volatile-ttl : 删除即将过期的
- noeviction : 永不过期,返回错误
AOF append only file
append only模式 aof配置
appendonly no 默认不开启aof模式,使用rdb模式进行持久化,大部分时候rdb就够用了
appendfilename "" 持久化的文件名字
appendfsync always 每次修改都会sync.消耗性能
appendfsync everysec 每秒执行一个sync,可能会丢失这1s的数据
appendsync no 不执行 sync,这个时候操作系统自己同步数据,速度最快。