文章目录
概述
- Redis(REmote DIctionary Server)是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。
- Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
- Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。
引入
- Web1.0时代:
- **Web2.0时代:**访问量急剧增长,造成CPU压力和IO压力
- NoSQL解决:
- 减少CPU和IO压力,直接从内存读取
- 作为缓存数据库,减少io的读操作
-
NoSQL数据库:
- 简介:
- 泛指非关系型的数据库
- 不依赖业务逻辑方式储存,而以简单的key-value模式储存,大大的增加了数据库的扩展能力
- 不遵循SQL标准
- 不支持ACID(事务特性:原子性、一致性、持久性、隔离性)
- 性能远超于SQL
- 适用场景
- 对数据高并发的读写
- 海量数据的读写
- 对数据高可扩展性的
- (用不着sql以及用了sql也不行的情况)
- 不适用场景
- 需要事务支持
- 基于sql的结构化查询储存,处理复杂的关系,需要即席查询
- 简介:
-
几种NoSQL数据库
1.Memcache
2.Redis
3.MongoDB
Redis安装
1.打开客户端工具
2.安装c语言的编译环境:在客户端输入yum install gcc
(输入gcc --version)检查安装情况
3.输入tar --zxcf命令进行解压
4.cd进入后,使用make命令
5.执行make install命令完成安装
6.redis-server:Redis服务器启动命令
redis-cli:客户端,操作入口
相关知识
- 默认16个数据库,下标从零开始,初始默认使用0号库
- 使用select < dbid >来切换数据库
- 统一密码管理,所有库同样密码
- dbsize查看当前数据库的key的数量
- flushdb清空当前库
- flushall通杀全部库
key键操作
- keys *:查看当前库所有key
- exists key:判断某个key是否存在
- type key:查看你的key是什么类型
- del key:删除指定的key数据
- unlink key:根据value选择非阻塞删除
- expire key 10:为给定的key设置过期时间
- ttl key:查看还有多少秒过期
- -1表示永不过期
- -2表示已过期
- select:命令切换数据库
- dbsize:查看当前数据库的key数量
数据类型
string
- 简介:
- 是Redis最基本的类型,一个key对应一个value
- 是二进制安全的,可以包含任何数据,比如jpg图片或者序列化对象
- 一个字符串value最多可以是512M
- 常用命令:
- set < key > < value >:添加键值对
- get < key >:查询对应键值
- append < key > < value >:将给定的value追加到原值的末尾
- strlen < key >:获得值的长度
- setnx < key > < value >:只有在key不存在的时候,设置key的值
- incr < key >:将key中储存的数字值+1
- decr < key >:将key中储存的数字值-1
- incrby/decrby < key >< 步长 >:将key中储存的数字值增减,步长自定义
- mset < key1 > < value1 > < key2 > < value2 >:同时设置多个键值对
- mget同上
- msetnx同上
- getrange < key > <起始位置> <结束位置>:获得值的范围
- setrange < key > <起始位置> < value >:用value覆写key所储存的字符串值,从起始位置开始
- setex < key > <过期时间> < value >:设置键值的同时,设置过期时间,单位秒
- getset < key > < value >:以新换旧,设置了新值的同时获得旧值
List
- 简介:
- 单键多值
- 是简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表的头部或者尾部
- 底层实际是双向链表,对两端的操作性能很高
- 常用命令:
- lpush/rpush < key > < value1 > < value2 > < value3 >:从左边/右边插入一个或多个值
- lpop/rpop < key >:从左边/右边吐出一个值
- rpoplpush < key1 > < key2 >:从< key1 >列表右边吐出一个值,插到< key2 >列表左边
- lrange < key > < start > < stop >:按照索引下标获得元素(从左到右)
- lindex < key > < index >:按照索引下标获得元素
- llen < key >:获得列表长度
- linsert < key > before < value > < newvalue >在< value >的后面插入< newvalue >插入值
- lerm < key > < n > < value >:从左边删除n个value
- lset < key > < index > < value >将列表key下标为index的值替换成value
Set
- 简介:
- 对外提供的功能与list类似是一个列表的功能,特殊之处在于set可以自动排重,并且提供了判断某个成员是否在一个set集合内的重要接口
- Redis的Set是string类型的无序集合,它底层其实是一个value为null的hash表,添加,删除,查找的复杂度都是O(1)
- 常用命令:
- sadd < key > < value1 > < value2 >:将一个或多个member元素加入集合key中,已经存在的member元素将被忽略
- smembers < key >:取出该集合的所有值
- sismember < key > < value >:判断集合key是否为含有该value值,有1,没有0
- scard < key >:返回该集合的元素个数
- srem < key > < value1 > < value2 >:删除集合中的某个元素
- spop < key >:随机从该集合中吐出一个值
- srandmember < key > < n >:随机从该集合中取出n个值,不会从集合中删除。
- smove < source > < destination > value
- sinter < key1 > < key2 >:返回两个集合的交际元素
- suntion < key1 > < key2 >:返回两个集合的并集元素
- sdiff < key1 > < key2 >:返回两个集合的差集元素
Hash
- 简介:
- 是一个键值对集合
- 是一个string类型的field和value的映射表,hash特别适合用于储存对象
- 主要储存方式
- 常用命令:
- hset < key > < field > < value >:给key集合中的field键赋值value
- hget < key1 > < field >:从key1集合field取出value
- hmset < key1 > < field1 > < value1 > < field2 > < value2 >:批量设计hash的值
- hexists < key1 > < field >:查看哈希表key中,给定域field是否存在
- hkeys < key >:列出该hash集合的所有field
- hvals < key >:列出该hash集合的所有value
- hincrby < key > < field > < increment >:为哈希表key中的域field的值加上增量
- hsetnx < key > < field > < value >:将哈希表key中的域field的值设置为value。当且仅当域field不存在
Zset
- 简介:
- 是一个没有重复元素的字符串集合
- 有序集合的每一个成员都关联了一个评分,这个评分被用来按照从最低分到最高分的方式排序集合中的成员,集合的成员是唯一的,但是评分可以是重复的
- 常用命令:
- zadd < key > < score 1> < value1 > < score2 > < value2 >:将一个或多个member元素及其score值加入到有续集key中
- zrange < key > < start > < stop >:返回有序集key中,下标在start,stop之间的元素
- zrangebyscore key minmax withscores limit offset count:返回有序集key中,所有score值位于min和max之间的成员,有序集成员按score值递增排列
- zincrby < key > < increment > < value >:为元素的score加上增量
- zrem < key > < value >:删除该集合下,指定值的元素
- zcount < key > < min > < max >:统计该集合,分数区间内的元素个数
- zrank < key > < value >:返回该值在集合中的排名,从0开始
新数据类型
Bitmaps
- Bitmaps和set的比较:
- bitmaps较set能节省很多的内存空间,但假如有很多僵尸用户,就不适合用bitmaps了
- 简介:
- 本身不是一种数据类型,实际上就是字符串,但可以对字符串的位进行操作
- 单独提供了一套命令,可以把bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在bitmaps中叫做偏移量
HyperLogLog
- 简介:
- 在输入元素的数量或者体积非常大时,计算基数所需的时间总是固定的,并且是很小的
- 命令:
- pfadd < key > < element > < element >:将所有元素添加到指定的数据结构中,如果执行命令后HLL估计的近似基数发生变化,则返回1,否则返回0
- pfcount < key > < key >…:计算HLL的近似基数,可以计算多个HLL
- pfmerge < destkey > < sourcekey > < sourcekey >… :将一个或多个HLL合并后的结果存储在另一个HLL中
Geospatial
- 简介:
- 元素的二维坐标
- redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等操作
- 命令:
- geoadd < key > < longitude > < latitude > < member > :添加地理位置,可以添加多个
- geopos < key > < member >:获得指定地区的坐标值,可以获取多个
- geodist < key > < member1 > < member2 >:获取两个位置之间的直线距离
- georadius < key > < longitude > < latitude > radius:以给定的经纬度为中心,找出某一半径的元素
Jedis操作
1.在idea中创建maven工程,导入Jedis所需的jar包
2.在配置文件中,找到bind行,注解掉
3.将protected-mode改为no
4.关闭防火墙
SpringBoot与Redis整合
1.在pom文件中引入redis相关依赖
2.application.properties配置redis配置
3.添加redis配置类
事务和锁机制
-
事务:
- 是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行
- 在执行过程中。不会被其他客户端发送来的命令请求所打断
- 主要作用就是串联多个命令防止别的命令插队
-
事务冲突:
- 悲观锁:
- 每次拿数据的时候都认为别人会修改,所以在每次拿数据的时候都会上锁
- 比如行锁,表锁,读锁,写锁,都是在做操作之前上锁,操作完再解锁
- 乐观锁:
- 每次拿数据的时候都认为别人不会修改
- 在更新的时候会判断一下在此期间别人有没有去更新这个数据,使用版本号等机制
- 适用于多读的应用类型,提高吞吐量
- 悲观锁:
-
操作:
- watch key 在执行multi之前,先执行watch key,可以监视一个或多个key,如果在事务执行之前这个key被其他命令所打断,那么事务将被打断
- unwatch 取消watch命令对所有key的监视,如果在执行watch命令之后,exec命令或discard命令先被执行了的话,那么就不需要再执行unwatch了
持久化操作
RDB(Redis DataBase)
- **是什么:**在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复时是将快照文件直接读到内存里
- 备份是如何执行的:
- Redis会单独创建一个子进程(fork)来进行持久化,会先将数据写入一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件
- 主进程不进行任何IO操作
- 若需要进行大规模数据的恢复,且对于数据的完整性不是很敏感,RDB优于AOF
- 缺点:最后一次持久化后的数据可能丢失
- 优势:
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
- 劣势:
- Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
- 虽然Redis在fork时使用了写时拷贝技术,但数据庞大时还是比较消耗性能
AOF(Append Of File)
-
是什么:
- 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来
- 只许追加文件但不可以改写文件
- redis启动之初会读取该文件重新构建数据
-
持久化流程:
- 客户端的请求写命令会被append追加到AOF缓冲区内
- AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中
- AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量
- Redis服务重启后,会重新load加载AOf文件中的写操作达到数据恢复的目的
-
优势:
- 备份机制更稳健,丢失数据概率更低
- 可读的日志文本,通过操作AOF稳健,可以处理误操作
-
劣势:
- 比起RDB占用更多的磁盘空间
- 恢复备份速度要慢
- 每次读写都同步,有一定的性能压力
- 存在个别Bug,造成恢复不能
主从复制
-
**是什么:**主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
-
能干嘛:
- 读写分离
- 容灾快速恢复
-
复制原理:
- Slave启动成功连接到master后会发送一个sync命令
- Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕后,master将传送整个数据文件到slave,以完成,以完成一次完全同步
- 全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中
- 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
- 但是只要是重新连接master,一次完全同步将被自动执行
-
哨兵模式:
- 调整为一主二仆模式
- 自定义的/myredis目录下新建sentinel.conf文件
- 配置哨兵:sentinel monitor mymaster 127.0.0.1 6379 1(其中mymaster为监控对象起的服务器名称,1为至少有多少个哨兵同意迁移的数量
- 启动哨兵:执行redis-sentinel/myredis/sentinel.conf
- 当主机挂掉,从机选举中产生新的主机
集群
-
问题:
- 容量不够,redis如何进行扩容?
- 并发写操作,redis如何分摊?
- 主从模式,主机宕机,导致ip地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息
-
什么是集群:
- 实现了对Redis的水平扩容。即启动N个节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的N分之一
- 通过分区来提供一定程度的可用性,即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求
-
操作:
-
配置基本信息
- 开启daemonize ues
- pid文件名字
- 指定端口
- Log文件名字
- Dump.rdb名字
- Appendonly:关掉或者换名字
-
redis cluster配置修改
- cluster-enabled yes 打开集群模式
- cluster-config-file nodes-6379.conf设定节点配置文件名
- cluster-node-timeout 15000:设定节点失联时间,超过该时间,集群自动进行主从切换
- 修改好redis66379.cof文件,拷贝多个redis.conf文件
- 使用查找替换修改另外5个文件
- 启动6个redis服务
- 将6个节点合成一个集群
应用问题解决
缓存穿透
- 是什么:
- 应用服务器压力变大了
- redis命中率降低,一直查询数据库,数据库崩溃
- 出现很多非正常url访问
- 解决:
- 对空值缓存
- 设置可访问的名单
- 采用布隆过滤器
- 进行实时监控
缓存击穿
- 是什么
- 数据库访问压力瞬时增加
- redis里面没有出现大量的key过期
- redis正常运行,数据库崩溃
- 为什么
- redis某个key过期了,大量访问使用这个key
- 解决
- 预先设置热门数据
- 实时调整
- 使用锁
缓存雪崩
- 是什么
- 数据库压力变大,服务器崩溃
- 为什么
- 在极少时间段,查询大量key的集中过期情况
- 解决
- 构建多级缓存架构
- 使用锁或队列
- 设置过期标志更新缓存
- 将缓存失效时间分散开
分布式锁
- #set sku:1:info"OK" NX PX 10000
- EX second:设置键的过期时间为second秒
- PX millisecond:设置键的过期时间为millisecond毫秒
- NX:只在键不存在时,才对键进行设置操作
- XX:只在键存在时,才对键进行设置操作
其他功能
ACL
- 使用acl list命令展现用户权限列表
- 使用acl cat
- 查看添加权限指令类别
- 加参数类型名可以查看类型下具体命令
- 使用acl whoami命令查看当前用户
- 使用aclsetuser命令创建和编辑用户ACL
IO多线程
- 配置:
- io-threads-do-reads yes
- io threads 4