redis原理及应用web
1、redis来源redis
2、数据类型算法
3、主流的应用场景数据库
4、特性数组
5、补充缓存
1、 redis来源服务器
做者:Salvatore Sanfilippo (antirez),男,意大利人.网络
需求: 一个访客信息追踪网站,网站能够通 过 JavaScript 脚本,将访客的 IP 地 址、所属国家、阅览器信息、被访问页 面的地址等数据传送给 LLOOGG. com 。 而后 LLOOGG.com 会将这些浏览数 据经过 web 页面实时地展现给用户, 并储存起最新的 5 至 10,000 条浏览 记录以便进行查阅。数据结构
redis解决方案app
每当某个被追踪的网站新增一条 浏览记录时, LLOOGG.com 就会将这条新的浏览记录推入 (push)到与该网站相对应的列表里面,当列表的 长度超过用户指定的最大长度时,程序每向 列表推入一条新的记录,就须要从列表中弹出(pop)一条最旧的记录。
如今已经被普遍使用:
Twitter 使用 Redis 来储存用户时间线(user timeline)。
StackOverflow 使用 Redis 来进行缓存和消息分发。
Pinterest 使用 Redis 来构建关注模型(follow model)和兴趣图谱(interest graph)。
Flickr 使用 Redis 来构建队列。
Github 使用 Redis 做为持久化的键值对数据库,并使用 Resque 来实现消息队列。
新浪微博使用 Redis 来实现计数器、反向索引、排行榜、消息 队列,并储存用户关系。
知乎使用 Redis 来进行计数、缓存、消息分发和任务调度。
掌上医讯使用redis来进行缓存,分布式锁等。
阿里云、百度云、Amazon、 RedisLab 等公司都提供了基于 Redis 的应用服务。
2、支持的数据类型
Redis 全部的数据结构都是以惟一的 key 字符串做为名称,而后经过这个惟一 key 值来获取相应的 value 数据。不一样类型的数据结构的差别就在于 value 的结构不同。
a.字符串
经常使用命令 SET key value [NX|XX] 保存值
SETNX key value 命令仅在键 key 不存在的状况下,才进行设置操做
SETXX key value 命令仅在键 key 存在的状况下,才进行设置操做
APPEND key value
STRLEN key
get key
SETRANGE key index value 根据索引设置值
GETRANGE key start end
字符串结构使用很是普遍,一个常见的用途就是缓存用户信息。咱们将用户信息结构体使用 JSON 序列化成字符串,而后将序列化后的 字符串塞进 Redis 来缓存。一样,取用户信息会通过一次反序列化的过程。
struct SDS<T> {
T capacity; // 数组容量
T len; // 数组长度
byte flags; // 特殊标识位,
byte[] content; // 数组内内容
}
Redis 的字符串是动态字符串,是能够修改的字符串,内部结构实现上相似于 Java 的 ArrayList,采用预分配冗余空间的方式来减小内存的频繁分配,如图中所示,内部为当前字符串实际分配的空间 capacity 通常要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,若是超过 1M,扩容时一次只会多扩 1M 的空间。须要注意的是字符串最大长度为 512M。
存储二进制数据相关的命令
SETBIT key index value
GETBIT key index
BITCOUNT key [start] [end]
b 列表
Redis 的列表至关于 Java 语言里面的 LinkedList,注意它是链表而不是数组。这意味着 list 的插入和删除操做很是快
经常使用的命令有 LPUSH key value [value ...]
LPOP key
RPUSH key value [value ...]
RPOP key
LLEN key
LINDEX key index
LRANGE key start stop
LSET key index value
LREM key count value
LTRIM key start stop
阻塞弹出
BLPOP key [key ...] timeout
Redis 的列表结构经常使用来作异步队列使用。将须要延后处理的任务结构体序列化成字符串塞进 Redis 的列表,另外一个线程从这个列表中轮询数据进行处理
hash 字典
Redis 的字典至关于 Java 语言里面的 HashMap,它是无序字典。内部实现结构上同 Java 的 HashMap 也是一致的
经常使用指令:HSET key field value
HGET key field
HEXISTS key field
HDEL key field [field ...]
HLEN key
hash 结构也能够用来存储用户信息,不一样于字符串一次性须要所有序列化整个对象,hash 能够对用户结构中的每一个字段单独存储。这样当咱们须要获取用户信息时能够进行部分获取。而以整个字符串的形式去保存用户信息的话就只能一次性所有读取,这样就会比较浪费网络流量...
集合(set)
Redis 的集合至关于 Java 语言里面的 HashSet,它内部的键值对是无序的惟一的。它的内部实现至关于一个特殊的字典,字典中全部的 value 都是一个值NULL
。
用户能够速地向集合添加元素,或者从集合里面 删除元素,也能够对多个集合进行集合运算操做,比 如计算并集、交集和差集。
SDIFF key [key ...] 计算全部给定集合的差集,并返回结果。
SDIFF key [key ...] 计算全部给定集合的差集,,并将结果储存到 destkey 。
SINTER key [key ...] 计算全部给定集合的交集,并返回结果
SINTERSTORE destkey key [key ...] 计算全部给定集合的交集,并将结果储存到 destkey
SUNION key [key ...] 计算全部给定集合的并集,并返回结果
SUNIONSTORE destkey key [key ...] 计算全部给定集合的并集,并将结果储存到 destkey
使用集合实现共同关注功能
使用集合能够实现商品筛选功能
有序集合
有序集合和集合同样,均可以包含任意数量的、各不相同的元素( element),不一样于集合的是,有序集 合的每一个元素都关联着一个浮点数格式的分 值(score),而且有序集合会按照分 值,以从小到大的顺序 来排列有序集合中的各个元素。 虽然有序集合中的每一个元素都必 须是各不相同的,但元素的分 值并无这一限制,换句话来讲,两个不 同元素的分值能够是相同的。
ZADD key score element [[score element] [score element] ...]
ZREM key element [element ...]
ZSCORE key element 返回分值
ZINCRBY key increment element 添加分值 ZINCRBY fruits-price 1.5 西瓜 3.5
ZCARD key 返回有序集合包含的元素数量
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 获取指定分值范围内的升序元素
ZCOUNT key min max 计算给定分值范围内的元素数量
zset 能够用来存粉丝列表,value 值是粉丝的用户 ID,score 是关注时间。咱们能够对粉丝列表按关注时间进行排序
ZUNIONSTORE destkey numkeys key [key ...] 计算多个集合的并集
eg:水果的销售状况:
HyperLogLog
需求:记录网站天天得到的独立 IP 数量
集合方式:
SADD '2018.9.10::unique::ip' ip 加入IP
SCARD '20148:9:10:unique::ip' 计算独立IP数量
集合实现的问题
使用字符串来储存每一个 IPv4 地址最多须要耗费 15 字节(格式为 'XXX.XXX.XXX.XXX' ,好比 '202.189.128.186')。下表给给出了不一样用户量使用内存的数量
随着集合记录的 IP 愈来愈多,消耗的内存也会愈来愈多。 另外若是要储存 IPv6 地址的话,须要的内存还会更多一些。为了解决此类问题,Redis 提供了 HyperLogLog 数据结构就是用来解决这种统计问题的。
HyperLogLog 提供了两个指令 pfadd 和 pfcount
pfadd key value 增长对象
pfcount key 获取计数
HyperLogLog 是不精确的去重计数方案,虽然不精确可是也不是很是不精确,标准偏差是 0.81%,重点是省空间,总共占用的内存是12k.关于该算法的介绍https://blog.csdn.net/firenet1/article/details/77247649
发明这个算法的牛人,名字叫Philippe Flajolet 。
pfmerge 用于将多个 pf 计数值累加在一块儿造成一个新的 pf 值。
好比获取两个网站的合并起来的独立ip。
主流的应用场景
一、缓存
二、分布式锁
三、 消息列队
四、位图
在咱们平时开发过程当中,会有一些 bool 型数据须要存取,好比用户一年的签到记录,签了是 1,没签是 0,要记录 365 天。若是使用普通的 key/value,每一个用户要记录 365 个,当用户上亿的时候,须要的存储空间是惊人的。 为了解决这个问题,Redis 提供了位图数据结构,这样天天的签到记录只占据一个位,365 天就是 365 个位,46 个字节 (一个稍长一点的字符串) 就能够彻底容纳下,这就大大节约了存储空间。
五、HyperLogLog
六、geoHash 附近的人
七、排行榜
八、关注点赞
4、特性
一、快
二、支持多种数据类型
三、过时键功能
四、支持持久化
五、管道
六、支持主从模式
七、sentinel高可用
八、Cluster集群
快!!!内存存储,不受IO到硬盘IO速度限制 速度极快!
采用了非阻塞 I/O 多路复用机制 极大增长访问速度。
过时键功能
设置生存时间 EXPIRE 命令和 PEXPIRE 命令。 SETEX 命令 PSETEX 命令
设置过时时间 EXPIREAT 命令和 PEXPIREAT 命令。
查看剩余生存时间 TTL 命令和 PTTL 命令。
删除生存时间或过时时间 PERSIST 命令。
应用:一、自动更新的缓存
二、自动刷新的排行榜:在有序集合中,经过给日排行榜设置生存时间,咱们能够 让 Redis 在每一个新的一天开始时,自动删除旧的排行榜。
过时删除机制:
redis 会将每一个设置了过时时间的 key 放入到一个独立的字典中,之后会定时遍历这个字典来删除到期的 key。除了定时遍历以外,它还会使用惰性策略来删除过时的 key,所谓惰性策略就是在客户端访问这个 key 的时候,redis 对 key 的过时时间进行检查,若是过时了就当即删除。定时删除是集中处理,惰性删除是零散处理。
定时扫描:
Redis 默认会每秒进行十次过时扫描,过时扫描不会遍历过时字典中全部的 key,而是采用了一种简单的贪心策略。
一、从过时字典中随机 20 个 key;
二、 删除这 20 个 key 中已通过期的 key;
三、 若是过时的 key 比率超过 1/4,那就重复步骤 1;
注意:若是有大批量的 key 过时,要给过时时间设置一个随机范围,而不能所有在同一时间过时。不然可能会系统资源不足,形成卡顿。
支持持久化
Redis 的数据所有在内存里,若是忽然宕机,数据就会所有丢失,所以必须有一种机制来保证 Redis 的数据不会由于故障而丢失,这种机制就是 Redis 的持久化机制。
若是咱们仅仅是将 Redis 用做缓存的话,那么这种数据丢失带来的问题并非很是大,咱们只须要重 启机器,而后再次将数据放到 缓存里面就能够了;但若是我 们将 Redis 用做数据库的话,那么这种数据 丢失就不能接受了。
Redis 的持久化机制有两种:
第一种是快照 RDB,全量备份 记录数据
那么 Redis 服务器在何时才会建立 RDB 文件呢?
在 Redis 服务器建立 RDB 文件的状况中,如下三种是最常 见的:
1. 服务器执行客户端发送的 SAVE 命令; 手动 阻塞 快
2. 服务器执行客户端发送的 BGSAVE 命令;手动 不阻塞 慢
3. 使用 save 配置选项设置的自动保存条件被知足,服务器自动执行 BGSAVE 。自动 不阻塞
BGSAVE 命令不会㐀成服务器阻塞的缘由在于:
1. 当 Redis 服务器接收到 BGSAVE 命令的时候,它不会本身来建立 RDB 文件,而是经过 fork() 来生 成一个子进程,而后由子进程负责建立 RDB 文件,而本身则继续处理客户端的命令请求;
2. 当子进程建立好 RDB 文件并退出时,它会向父进程(也便是负责处理命令请求的 Redis 服务器)发 送一个信号,告知它 RDB 文件已经建立完毕;
3. 最后 Redis 服务器(父进程)接收子进程建立的 RDB 文件,BGSAVE 执行完毕。
自动BGSAVE的条件
save 900 1
save 300 10
save 60 10000
表示“若是距离上一次建立 RDB 文件已通过去了 900 秒,而且服务器的全部数据库总共已经发生了 很多于 1 次修改,那么执行 BGSAVE 命令”。
RDB持久化策略的不足:
因 为建立 RDB 文件须要将服务器全部数据库的数据都保存起来, 这是一个很是耗费资源和时间的操做,因此服务器须要隔一段时间才建立一个新的 RDB 文件,也即 是说,建立 RDB 文件的操做不能执行得过于频繁,不然就会严重地影响服务器的性能。 好比说,在 save 配置选项的默认设置下,即便有超过 10000 次修改操做发生,服务器也至少会间隔 一分钟才建立下一个 RDB 文件: save 900 1 save 300 10 save 60 10000 若是在等待建立下一个 RDB 文件的过程当中,服务器遭遇了意外停机,那么用 户将丢失最后一次建立 RDB 文件以后,数据库发生的全部修改。
第二种是 AOF 日志 增量备份 记录指令
AOF 持久化有一个巨大的优点,那就是,用户能够根据本身的须要对 AOF 持 久化进行调整,让 Redis 在遭遇意外停机时不丢失任何数据,或者只丢失一秒钟数据,这比 RDB 持 久化遭遇意外停机时,丢失的数据要少得多。
配置 相关配置
appendonly yes no#开启AOF模式
appendfilename "appendonly.aof" #保存数据的AOF文件名称
appendfsync always everysec no
原理
AOF 持久化保存数据库数据的方法是:每当有修改数据 库的命令被执行时,服务器就会将被执行的命 令写入到 AOF 文件的末尾。下次服务启动时还原。
AOF重写-----给文件瘦身
AOF 重写的触发
有两种方法能够触发 AOF 重写:
1. 客户端向服务器发送 BGREWRITEAOF 命令。
2. 经过设置配置选项来让服务器自动执行 BGREWRITEAOF 命令,它们分别是:
• auto-aof-rewrite-min-size ,触发 AOF 重写所需的最小体积:只有在 AOF 文件的体积 大于等于 size 时,服务器才会考虑是否须要进行 AOF 重写。这个选项用于避免对体积太小的 AOF 文件进行重写。
• auto-aof-rewrite-percentage ,指定触发重写所需的 AOF 文件体积百分比:当 AOF 文件的体积大于 auto-aof-rewrite-min-size 指定的体积,而且超过上一次重写以后的 AOF 文件 体积的 percent% 时,就会触发 AOF 重写。(若是服务器刚刚启动不久,尚未进行过 AOF 重 写,那么使用服务器启动时载入的 AOF 文件的体积来做为基准值。)将这个值设置为 0 表示关 闭自动 AOF 重写。
管道
在通常状况下, 用户每执行一个 Redis 命令,客户端与服务器都须要进行一次通讯:客户端会将命令 请求发送给服务器,而服务器则会将执行命令所得的结果返回给客户端。 当程序执行一些复杂的操做时, 客户端可能须要执行多个命令, 并与服务器进行屡次通讯。
Redis 的流水线功能容许客户端一次将多个命令请求发送给服务器, 并将被执行的多个命令请求的结 果在一个命令回复中所有返回 给客户端, 使用这个功能能够有效地减小客 户端在执行多个命令时须要 与服务器进行通讯的次数。
支持主从模式
为了分担读压力,Redis支持主从复制,Redis的主从结构能够采用一主多从或者级联结构,Redis主从复制能够根据是不是全量分为全量同步和增量同步。
Redis 的复制(replication)功能容许用户根据一个 Redis 服务器来建立任意多个该服务器的复制品,其 中被复制的服务器为主服务器(master),而经过复制建立出来的服务器复制品则为从服务器(slave)。 主从服务器二者拥有相同的数据库数据:只要主从服务器之间的网络链接正常,主服务器就会一直将 发生在本身身上的数据更新同步 给从服务器,从而一直保证主从服务器的数据相同。
Redis 提供了两种方法来为某个主服务器建立从服务器:
1. 使用 SLAVEOF 命令,好比向一个服务器发送 SLAVEOF 127.0.0.1 6379 ,可让接收到该命令的服务器变为 127.0.0.1:6379 的从服务器。 在将一个服务器设置成从服务器以后,能够经过向它发送 SLAVEOF no one 来让它变回一个主 服务器(数据库已有的数据会被保留)。
2. 在启动服务器时,经过设置 slaveof 配置选项来让服务器成为指定 服务器的从服务器。
我配置的服务器分布:
6376 | 6377 | 6378 | 6379 |
master | slave | slave | slave |
配置而且启动主节点:
port 6376
daemonize yes
logfile "6376.log"
dbfilename "dump_6376.rdb"
dir "/var/redis/data/"
启动并重启从节点
port 6377
daemonize yes
logfile "6377.log"
dbfilename "dump-6377.rdb"
dir "/var/redis/data/"
slaveof 127.0.0.1 6376 // 从属主节点
查看服务状态,登录客户端,查看主从关系 INFO replication
sentinel高可用
监视主从服务器,并在主服务器下线时自动进行故障转移.
它负责持续监控主从节点的健康,当主节点挂掉时,自动选择一个最优的从节点切换为主节点。客户端来链接集群时,会首先链接 sentinel,经过 sentinel 来查询主节点的地址,而后再去链接主节点进行数据交互。当主节点发生故障时,客户端会从新向 sentinel 要地址,sentinel 会将最新的主节点地址告诉客户端。如此应用程序将无需重启便可自动完成节点切换。好比上图的主节点挂掉后,集群将可能自动调整为下图所示结构。
部署sentinel集群
sentinel26379 | sentinel26380 | sentinel26381 |
修改sentinel.conf文件
// Sentinel节点的端口
port 26379
dir /var/redis/data/
logfile "26379.log"
// 当前Sentinel节点监控 127.0.0.1:6379 这个主节点
// 2表明判断主节点失败至少须要2个Sentinel节点节点赞成
// mymaster是主节点的别名
sentinel monitor mymaster 127.0.0.1 6376 2
//每一个Sentinel节点都要按期PING命令来判断Redis数据节点和其他Sentinel节点是否可达,若是超过30000毫秒且没有回复,则断定不可达
sentinel down-after-milliseconds mymaster 30000
//故障转移超时时间为180000毫秒
sentinel failover-timeout mymaster 180000
启动sentinel节点
redis-sentinel sentinel.conf
确认登录客户端确认:
redis-cli -h 127.0.0.1 -p 26379 INFO Sentinel
测试
相关指令 sentinel masters
sentinel slaves mymaster
Redis Sentinel
的如下几个功能。
Sentinel
节点会按期检测Redis
数据节点和其他Sentinel
节点是否可达。Sentinel
节点会将故障转移通知给应用方。Redis Sentinel
结构中,客户端在初始化的时候链接的是Sentinel
节点集合,从中获取主节点信息。
消息丢失
Redis 主从采用异步复制,意味着当主节点挂掉时,从节点可能没有收到所有的同步消息,这部分未同步的消息就丢失了。若是主从延迟特别大,那么丢失的数据就可能会特别多。Sentinel 没法保证消息彻底不丢失,可是也尽量保证消息少丢失。它有两个选项能够限制主从延迟过大。
min-slaves-to-write 1
min-slaves-max-lag 10
第一个参数表示主节点必须至少有一个从节点在进行正常复制,否 则就中止对外写服务,丧失可用性。 何为正常复制,何为异常复制?这个就是由第二个参数控制的,它的单位是秒,表示若是 10s 没有收到从节点的反馈,就意味着从节点同步不正常,要么网络断开了,要么一直没有给反馈。
Cluster集群
------复制特性能够建立指定服务器的复制品,这些复制品能够用于扩展系统处理读请求的能力。
------Redis Sentinel 能够在复制特性的基础上,经过监视主从服务器并在主服务器故障时执行自动故
障转移来保证系统的可用性。
写能力不足怎么办??????
分片技术
集群使用分片来扩展数据库的容量,并将命令请求的负载交给不一样的节点来分担。
集群将整个数据库分为 16384 个槽(slot),全部键都属于这 16384 个槽的其中一个,计算键 key 属于哪一个槽的公式为 slot_number = crc16(key) % 16384 ,其中 crc16 为 16 位的循环冗余校验和函数。
集群中的每一个主节点均可以处理 0 个至 16384 个槽,当 16384 个槽都有某个节点在负责处理时,集群进入上线状态,并开始处理客户端发送的数据命令请求。
好比说,若是咱们有三个主节点 7000 、 7001 和 7002 ,那么咱们能够:
- 将槽 0 至 5460 指派给节点 7000 负责处理;
- 将槽 5461 至 10922 指派给节点 7001 负责处理;
- 将槽 10923 至 16383 指派给节点 7002 负责处理;
这样就能够将 16384 个槽平均地指派给三个节点负责处理。
请求转向:
对于一个被指派了槽的主 节点来讲,这个主节点只会处理属于指派给本身的槽的命令请求。若是一个节点接收到了和本身处理的槽无关的命令请求,那么节点会向客户端返回一个转向错误(redirection error),告诉客户端,哪一个节点才是负责处理这条命令的,以后客户端须要根据错误中包含的地址和端口号从新向正确的 节点发送命令请求。
集群搭建:
一、建立多个节点
二、为每一个节点指派槽,并将多个节点链接起来,组成一个集群
三、当集群数据库的 16384 个槽都有节点在处理时,集群进入上线状态。
5、补充
一、应用场景不一样,配置不一样。
缓存:关闭aof化,rdb持久化视状况而定 ,开启最大内存设置(不然为物理内存)
数据库:开启 aof ,开启rdb 关闭最大内存设置