当前位置:   article > 正文

Redis

Redis

redis官网:https://redis.io/
redis中文网:https://www.redis.net.cn/


Redis(Remote Dictionary Server ),即远程字典服务。
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。

  • 关系型数据库:列+行,同一个表下数据的结构是一样的。
    非关系型数据库:数据存储没有固定的格式,并且可以进行横向扩展。
  • 大数据时代的主要问题:海量、多样、实时
    大数据时代对程序的要求:高并发、高可扩、高性能
  • Redis是单线程的,是基于内存操作的。
    所以Redis的性能瓶颈是机器内存和网络带宽。
    对于内存系统来说,读写都是在一个CPU上,没有上下文切换效率最高
    (多线程CPU上下文切换会耗时)所以单线程就是最佳的方案
    官方数据,读速度110000次/s,写速81000次/s。

数据库的不同使用场景

  • 商品信息:关系型数据库:Mysql
  • 文字居多:文档型数据库:MongoDB
  • 图片:
    分布式文件系统:FastDFS
    淘宝:TFS
    Google: GFS
    Hadoop: HDFS
    阿里云: oss
  • 用于搜索:搜索引擎:solr,elasticsearch
  • 热门的波段信息:内存数据库:Redis,Memcache
  • 外部接口:第三方应用

redis默认有16个数据库:db0~db15(默认使用db0)
不同数据库之间 数据是不能互通的

操作命令

更多命令教程:redis中文网:https://www.redis.net.cn/tutorial/3501.html

set key value
get key
// 测试100个并发连接100000次请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
// 查看数据库数量
config get databases
// 切换数据库
select 0
// 查看数据库大小
dbsize 
// 查看所有的key
keys *
// 清空当前数据库中的键值对
flushdb
// 清空所有数据库的键值对
flushall
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
// 判断键是否存在
exists key
// 删除键值对
del key
// 将键值对移动到指定数据库1
move key 1
// 设置键值对的过期时间(秒钟倒计时)
expire key second
// 查看key的过期剩余时间,-2 表示过期,-1表示未设置过期时间
ttl key
// 查看value的数据类型
type key
// 修改 key 的名称
rename key newkey
// 仅当 newkey 不存在时,将 key 改名为 newkey
renamenx key newkey
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

数据类型

String 字符串

Redis 字符串数据类型的相关命令用于管理 redis 字符串值
还可以做计数器

List 列表

Redis列表是简单的字符串列表,按照插入顺序排序
你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含(2的32次方 - 1)个元素 (4294967295, 每个列表超过40亿个元素)。
Redis中List是可以双端操作的,所以命令分为了L开头和R开头两类
list实际上是一个链表,在两边插入或者改动值,效率最高!修改中间元素,效率相对较低
应用:消息排队!消息队列(Lpush Rpop),栈(Lpush Lpop)

Set 集合

Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的。
集合对象的编码可以是 intset 或者 hashtable。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为(2的32次方 - 1)(4294967295, 每个集合可存储40多亿个成员)。

Hash 哈希

Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象
Redis 中每个 hash 可以存储(2的32次方 - 1)键值对(40多亿)。
Set就是一种简化的Hash,只变动key,而value使用默认值填充。
可以将一个Hash表作为一个对象进行存储,表中存放对象的信息

Zset 有序集合

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序
有序集合的成员是唯一的,但分数(score)却可以重复
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为(2的32次方 - 1)(4294967295, 每个集合可存储40多亿个成员)。
score相同:则会按照 member 的字典顺序进行排列
应用案例:重要消息、带权重进行判断、排行榜实现

Geospatial 地理位置

城市经纬度查询:http://www.jsons.cn/lngcode/
使用经纬度定位地理坐标并用一个有序集合zset保存
有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度。
单位:m米、km千米、mi英里、ft英尺。

// 添加
geoadd china:city 116.4 39.9 beijing
// 批量添加
geoadd china:city 116.4 39.9 beijing 121.4 31.2 shanghai
// 获取地理位置
geopos china:city beijing
// 获取两地直线距离
geodist china:city beijing xianggang
// 范围查找 (经度 纬度)为圆心 半径 km 内所有的城市
// withcoord 带上经纬度
// withdist 城市距离该点的直线距离
// count 查找个数
georadius china:city 110 30 1000 km withcoord withdist count 2
// 根据给定的元素确定中心点,再进行查找
georadiusbymember china:city shanghai 1000 km
// 将二维的经纬度转换为一维的字符串,经过hash之后的结果,两个字符串越像,代表越接近
geohash china:city beijing
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Hyperloglog 基数统计

基数就是数据集中的不重复元素基数估计就是在误差可接受的范围内,快速计算基数。
Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,其底层使用string数据类型
HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

// 添加元素
pfadd key a b c
// 估算基数
pfcount key
// 将多个 HyperLogLog 合并为一个 HyperLogLog
pfmerge newkey key1 key2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

BitMaps 位图

bitmaps是一串连续的二进制串,使用位存储,信息状态只有 0 和 1

// 设置key的第0位为 1(不设置默认是0)
setbit key 0 1
// 获取第 0位的值
getbit key 0
// 统计key中值为1的个数
bitcount key
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

事务

  • Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
    1. 批量操作在发送 EXEC 命令前被放入队列缓存。
    2. 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行
    3. 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中
  • 一个事务从开始到执行会经历以下三个阶段:开始事务 ->命令入队 ->执行事务
// 标记一个事务块的开始。
MULTI
// 取消事务,放弃执行事务块内的所有命令。
DISCARD
// 执行所有事务块内的命令。
EXEC
// 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
WATCH key [key ...]
// 取消 WATCH 命令对所有 key 的监视。
UNWATCH
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
编译时异常
命令入队时就发生了错误,执行事务时所有的命令都不执行
运行时异常
事务执行时才发生了错误,错误的命令不影响队列中其他正常命令的执行

乐观锁

使用watch key监控指定数据,相当于乐观锁加锁。

// 每次监控数据前先取消监控(unwatch)再重新监控,确保监控的是最新的值
// 上锁(类似于获取字段的 version)
watch key
// 开启事务
multi
// 事务执行之前,监视值没有被中途修改,事务正常执行,如果被修改了,会导致事务执行失败
exec
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

每次提交执行exec后都会自动释放锁

Jedis

Jedis是Redis官方推荐的Java连接开发工具

<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
  • 1
  • 2
  • 3

redis.conf

单位(忽略大小写)

1k => 1000 bytes
1kb => 1024 bytes
1m => 1000000 bytes
1mb => 1024*1024 bytes
1g => 1000000000 bytes
1gb => 1024*1024*1024 bytes
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

引入多个配置文件

include .\path\to\local.conf
  • 1

网络

// 绑定主机
bind 127.0.0.1
// 端口设置
port 6379
// 保护模式
protected-mode yes
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

通用

// 守护线程方式运行
daemonize yes
// 如果以后台方式运行,需要指定一个redis.pid文件
pidfile /var/run/redis.pid
// 日志输出级别
// debug (a lot of information, useful for development/testing)
// verbose (many rarely useful info, but not a mess like the debug level)
// notice (moderately verbose, what you want in production probably)
// warning (only very important / critical messages are logged)
loglevel notice
// 日志文件位置
logfile ""
// 数据库数量,默认16
databases 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

快照
redis是内存数据库,断电即失。
快照就是做持久化,在规定时间内做了多少次操作,则会持久化到文件.rdb.aof。

// 900秒内只要有一个key进行了修改,就会进行持久化
save 900 1
// 如果持久化出错,是否继续工作
stop-writes-on-bgsave-error yes
// 是否压缩rdb文件(消耗一部分cpu资源)
rdbcompression yes
// 保存rdb文件时,进行错误检查
rdbchecksum yes
// rdb文件保存目录
dir ./
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

复制
配置主从服务器


  • 1

安全

// 密码
requirepass 123456
// 命令行设置密码
config set requirepass "123456"
config get requirepass
// 密码登录
auth requirepass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

限制

// 连接redis的最大客户端数量
maxclients 10000
// 最大内存容量
maxmemory <bytes>
// 内存达到上限后的处理策略
maxmemory-policy noeviction
// volatile-lru -> (只对设置了过期时间的key进行lru)remove the key with an expire set using an LRU algorithm
// allkeys-lru -> (删除lru算法的key)remove any key according to the LRU algorithm
// volatile-random -> (随机删除即将过期的key)remove a random key with an expire set
// allkeys-random -> (随机删除)remove a random key, any key
// volatile-ttl -> (删除即将过期的)remove the key with the nearest expire time (minor TTL)
// noeviction -> (永不过期,返回错误)don't expire at all, just return an error on write operations
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

APPEND ONLY 模式
AOF配置

// 默认使用rdb方式持久化,改为yes开启aof模式,重启生效
appendonly no
// 持久化的文件的文件名
appendfilename "appendonly.aof"
// 每次修改都会执行sync,性能消耗大
// appendfsync always
// 每秒执行一次sync,可能会丢失数据
appendfsync everysec
// 不执行sync,操作系统同步数据,速度最快
// appendfsync no
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

持久化

RDB

将 Redis 在内存中的数据写入到硬盘中,生成一个快照文件。
redis 线程 fork 一个子进程,快照持久化完全交给子进程处理,父进程继续处理客户端的读写请求。
/usr/local/bin目录下生成dump.rdb文件,redis启动时自动检查该文件,恢复里面的数据。
触发机制

  • 配置文件save的条件满足save 900 1
  • 执行flushall
  • 退出redis

优点:适合大规模的数据恢复,对数据的完整性要求不高。
缺点:需要一定的时间间隔,如果意外宕机了,最后一次修改的数据就会丢失。fork进程会占用内存空间。

AOF

AOF(Append-only file)日志存储的是redis服务器的顺序指令序列,即对内存中数据进行修改的指令记录,数据恢复的过程就是把记录的指令再顺序执行一次

  • aof文件默认是无限追加,如果文件大于64m,则会fork一个新的进程来将文件进行重写。
  • /usr/local/bin目录下appendonly.aof。
    如果这个文件有错误,执行redis-check-aof --fix修复即可。

优点:每次修改都同步,完整性好。
缺点:数据文件aof比rdb大,恢复的速度比rdb慢,运行效率也比rdb慢。

发布订阅

Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息
当有新消息通过 PUBLISH 命令发送给频道 channel1 时,这个消息就会被发送给订阅它的客户端

主从复制

主机负责写,从机负责读(只能读)

// 查看主从服务器信息
info replication
// role:master 角色:master主服务器,slave从服务器
// connected_slaves:0 从服务器数量
// master_repl_offset:0
// repl_backlog_active:0
// repl_backlog_size:1048576
// repl_backlog_first_byte_offset:0
// repl_backlog_histlen:0
// 将当前服务器转变为指定服务器的从属服务器
slaveof 1270.0.1 6379
// 使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃
slaveof no one
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

复制原理
salve启动成功连接到master后会发送一个sync命令
master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:当slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步。
但是只要重新链接master,一次完全同步(全量复制)将被自动执行。

哨兵模式

配置哨兵配置文件sentinel.conf

// sentinel monitor 被监控者的名称 host port count
// (count表示有几台 Sentinel 发现有问题,就会发生故障转移,使用投票算法选出新的主机)
sentinel monitor redis6379 127.0.0.1 6379 1
  • 1
  • 2
  • 3

当监控主机宕机了,会在从机中自动选举一个作为新的主机,其他从机都变为新主机的从机。
若此时原来宕机的主机重新启动了,哨兵会自动扫描并将它也作为新主机的从机。
优点:基于主从复制,自动监控,发生故障时自动切换主机,系统可用性强。
缺点:配置十分复杂,集群达到上限,在线扩容就非常麻烦。

缓存穿透

请求传进来的key是不存在Redis中的,那么就会去数据库查询,访问量大就会导致数据库压力大。

  • 解决方案1:布隆过滤器
    对所有可能查询的参数以Hash的形式存储,以便快速确定是否存在这个值,在控制层先进行拦截校验,校验不通过直接打回,减轻了存储系统的压力。
  • 解决方案2:缓存空对象
    一次请求若在缓存和数据库中都没找到,就缓存一个空对象用于处理后续这个请求。
    这种方法会耗费大量的空间,必须设置较短过期时间,还有可能出现数据不一致现象。

缓存击穿

当某个key在过期的一瞬间,有大量请求并发访问,就会导致数据库瞬间压力过大。

  • 解决方案1:设置热点数据永不过期
  • 解决方案2:加互斥锁
    使用分布式锁,保证每个key同时只有一个线程去查询后端服务。

缓存雪崩

缓存集体失效
在某一时间段,缓存集中过期失效。(自然形成的,对数据库的压力是周期性的)
某个服务器宕机或断网(不可预知的)

  • 解决方案1:redis高可用
    搭建redis集群,异地多活。
  • 解决方案2:限流降级
    通过加锁或者队列让某个key只允许一个线程查询数据和写缓存。
  • 解决方案3:数据预热
    在正式部署之前,把可能访问的数据预先访问一遍,写入缓存中,并设置不同的过期时间,让缓存失效的时间尽量均匀。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/326260
推荐阅读
相关标签
  

闽ICP备14008679号