什么是Redis
Redis(Remote Dictionary Server) 是一个应用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。
Redis 能够存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值反对五种数据类型:字符串、列表、汇合、散列表、有序汇合。
与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度十分快,因而 redis 被广泛应用于缓存方向,每秒能够解决超过 10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也常常用来做分布式锁。除此之外,Redis 反对事务 、长久化、LUA脚本、LRU驱动事件、多种集群计划。
Redis有哪些优缺点
长处
读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
反对数据长久化,反对AOF和RDB两种长久化形式。
反对事务,Redis的所有操作都是原子性的,同时Redis还反对对几个操作合并后的原子性执行。
数据结构丰盛,除了反对string类型的value外还反对hash、set、zset、list等数据结构。
反对主从复制,主机会主动将数据同步到从机,能够进行读写拆散。
毛病
数据库容量受到物理内存的限度,不能用作海量数据的高性能读写,因而Redis适宜的场景次要局限在较小数据量的高性能操作和运算上。
Redis 不具备主动容错和复原性能,主机从机的宕机都会导致前端局部读写申请失败,须要期待机器重启或者手动切换前端的IP能力复原。
主机宕机,宕机前有局部数据未能及时同步到从机,切换IP后还会引入数据不统一的问题,升高了零碎的可用性。
Redis 较难反对在线扩容,在集群容量达到下限时在线扩容会变得很简单。为防止这一问题,运维人员在零碎上线时必须确保有足够的空间,这对资源造成了很大的节约。
为什么要用缓存,为什么要用 Redis
次要从“高性能”和“高并发”这两点来对待这个问题。
高性能:
如果用户第一次拜访数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户拜访的数据存在数缓存中,这样下一次再拜访这些数据的时候就能够间接从缓存中获取了。操作缓存就是间接操作内存,所以速度相当快。如果数据库中的对应数据扭转的之后,同步扭转缓存中相应的数据即可!
高并发:
间接操作缓存可能接受的申请是远远大于间接拜访数据库的,所以咱们能够思考把数据库中的局部数据转移到缓存中去,这样用户的一部分申请会间接到缓存这里而不必通过数据库。
为什么要用 Redis 而不必 map/guava 做缓存?
缓存分为本地缓存和分布式缓存。以 Java 为例,应用自带的 map 或者 guava 实现的是本地缓存,最次要的特点是轻量以及疾速,生命周期随着 jvm 的销毁而完结,并且在多实例的状况下,每个实例都须要各自保留一份缓存,缓存不具备一致性。
应用 redis 或 memcached 之类的称为分布式缓存,在多实例的状况下,各实例共用一份缓存数据,缓存具备一致性。毛病是须要放弃 redis 或 memcached服务的高可用,整个程序架构上较为简单。
Redis为什么这么快
1、齐全基于内存,绝大部分申请是纯正的内存操作,十分疾速。数据存在内存中,相似于 HashMap,HashMap 的劣势就是查找和操作的工夫复杂度都是O(1);
2、数据结构简略,对数据操作也简略,Redis 中的数据结构是专门进行设计的;
3、采纳单线程,防止了不必要的上下文切换和竞争条件,也不存在多过程或者多线程导致的切换而耗费 CPU,不必去思考各种锁的问题,不存在加锁开释锁操作,没有因为可能呈现死锁而导致的性能耗费;
4、应用多路 I/O 复用模型,非阻塞 IO;
5、应用底层模型不同,它们之间底层实现形式以及与客户端之间通信的利用协定不一样,Redis 间接本人构建了 VM 机制 ,因为个别的零碎调用零碎函数的话,会节约肯定的工夫去挪动和申请;
数据类型
Redis有哪些数据类型
Redis次要有5种数据类型,包含String,List,Set,Zset,Hash,满足大部分的应用要求
Redis的利用场景
总结一
1、计数器
能够对 String 进行自增自减运算,从而实现计数器性能。Redis 这种内存型数据库的读写性能十分高,很适宜存储频繁读写的计数量。
2、缓存
将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保障缓存的命中率。
3、会话缓存
能够应用 Redis 来对立存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就不再具备状态,一个用户能够申请任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。
4、全页缓存(FPC)
除根本的会话token之外,Redis还提供很简便的FPC平台。以Magento为例,Magento提供一个插件来应用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个十分好的插件 wp-redis,这个插件能帮忙你以最快速度加载你曾浏览过的页面。
5、查找表
例如 DNS 记录就很适宜应用 Redis 进行存储。查找表和缓存相似,也是利用了 Redis 疾速的查找个性。然而查找表的内容不能生效,而缓存的内容能够生效,因为缓存不作为牢靠的数据起源。
6、音讯队列(公布/订阅性能)
List 是一个双向链表,能够通过 lpush 和 rpop 写入和读取音讯。不过最好应用 Kafka、RabbitMQ 等消息中间件。
7、分布式锁实现
在分布式场景下,无奈应用单机环境下的锁来对多个节点上的过程进行同步。能够应用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还能够应用官网提供的 RedLock 分布式锁实现。
8、其它
Set 能够实现交加、并集等操作,从而实现独特好友等性能。ZSet 能够实现有序性操作,从而实现排行榜等性能。
总结二
Redis相比其余缓存,有一个十分大的劣势,就是反对多种数据类型。
数据类型阐明string字符串,最简略的k-v存储hashhash格局,value为field和value,适宜ID-Detail这样的场景。list简略的list,程序列表,反对首位或者开端插入数据set无序list,查找速度快,适宜交加、并集、差集解决sorted set有序的set
其实,通过下面的数据类型的个性,根本就能想到适合的利用场景了。
string——适宜最简略的k-v存储,相似于memcached的存储构造,短信验证码,配置信息等,就用这种类型来存储。
hash——个别key为ID或者惟一标示,value对应的就是详情了。如商品详情,个人信息详情,新闻详情等。
list——因为list是有序的,比拟适宜存储一些有序且数据绝对固定的数据。如省市区表、字典表等。因为list是有序的,适宜依据写入的工夫来排序,如:最新的热点新闻,音讯队列等。
set——能够简略的了解为ID-List的模式,如微博中一个人有哪些好友,set最牛的中央在于,能够对两个set提供交加、并集、差集操作。例如:查找两个人独特的好友等。
Sorted Set——是set的加强版本,减少了一个score参数,主动会依据score的值进行排序。比拟适宜相似于top 10等不依据插入的工夫来排序的数据。
如上所述,尽管Redis不像关系数据库那么简单的数据结构,然而,也能适宜很多场景,比个别的缓存数据构造要多。理解每种数据结构适宜的业务场景,不仅有利于晋升开发效率,也能无效利用Redis的性能。
长久化
什么是Redis长久化?
长久化就是把内存的数据写到磁盘中去,避免服务宕机了内存数据失落。
Redis 的长久化机制是什么?各自的优缺点?
Redis 提供两种长久化机制 RDB(默认) 和 AOF 机制;
RDB:是Redis DataBase缩写快照
RDB是Redis默认的长久化形式。依照肯定的工夫将内存的数据以快照的模式保留到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。
长处:
1、只有一个文件 dump.rdb,不便长久化。
2、容灾性好,一个文件能够保留到平安的磁盘。
3、性能最大化,fork 子过程来实现写操作,让主过程持续解决命令,所以是 IO 最大化。应用独自子过程来进行长久化,主过程不会进行任何 IO 操作,保障了 redis 的高性能。
4、绝对于数据集大时,比 AOF 的启动效率更高。
毛病:
1、数据安全性低。RDB 是距离一段时间进行长久化,如果长久化之间 redis 产生故障,会产生数据失落。所以这种形式更适宜数据要求不谨严的时候)
2、AOF(Append-only file)长久化形式:是指所有的命令行记录以 redis 命令请 求协定的格局齐全长久化存储)保留为 aof 文件。
AOF:长久化
AOF长久化(即Append Only File长久化),则是将Redis执行的每次写命令记录到独自的日志文件中,当重启Redis会从新将长久化的日志中文件复原数据。
当两种形式同时开启时,数据恢复Redis会优先选择AOF复原。
长处:
1、数据安全,aof 长久化能够配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。
2、通过 append 模式写文件,即便中途服务器宕机,能够通过 redis-check-aof 工具解决数据一致性问题。
3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),能够删除其中的某些命令(比方误操作的 flushall)
毛病:
1、AOF 文件比 RDB 文件大,且复原速度慢。
2、数据集大的时候,比 rdb 启动效率低。
优缺点是什么?
AOF文件比RDB更新频率高,优先应用AOF还原数据
AOF比RDB更平安也更大
RDB性能比AOF好
如果两个都配了优先加载AOF
如何抉择适合的长久化形式?
一般来说, 如果想达到足以媲美PostgreSQL的数据安全性,你应该同时应用两种长久化性能。在这种状况下,当 Redis 重启的时候会优先载入AOF文件来复原原始的数据,因为在通常状况下AOF文件保留的数据集要比RDB文件保留的数据集要残缺。
如果你十分关怀你的数据, 但依然能够接受数分钟以内的数据失落,那么你能够只应用RDB长久化。
有很多用户都只应用AOF长久化,但并不举荐这种形式,因为定时生成RDB快照(snapshot)十分便于进行数据库备份, 并且 RDB 复原数据集的速度也要比AOF复原的速度要快,除此之外,应用RDB还能够防止AOF程序的bug。
如果你只心愿你的数据在服务器运行的时候存在,你也能够不应用任何长久化形式。
Redis长久化数据和缓存怎么做扩容?
如果Redis被当做缓存应用,应用一致性哈希实现动静扩容缩容。
如果Redis被当做一个长久化存储应用,必须应用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变动。否则的话(即Redis节点须要动态变化的状况),必须应用能够在运行时进行数据再均衡的一套零碎,而以后只有Redis集群能够做到这样。
过期键的删除策略
Redis的过期键的删除策略
咱们都晓得,Redis是key-value数据库,咱们能够设置Redis中缓存的key的过期工夫。Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何解决。
过期策略通常有以下三种:
定时过期:每个设置过期工夫的key都须要创立一个定时器,到过期工夫就会立刻革除。该策略能够立刻革除过期的数据,对内存很敌对;然而会占用大量的CPU资源去解决过期的数据,从而影响缓存的响应工夫和吞吐量。
惰性过期:只有当拜访一个key时,才会判断该key是否已过期,过期则革除。该策略能够最大化地节俭CPU资源,却对内存十分不敌对。极其状况可能呈现大量的过期key没有再次被拜访,从而不会被革除,占用大量内存。
定期过期:每隔肯定的工夫,会扫描肯定数量的数据库的expires字典中肯定数量的key,并革除其中已过期的key。该策略是前两者的一个折中计划。通过调整定时扫描的工夫距离和每次扫描的限定耗时,能够在不同状况下使得CPU和内存资源达到最优的均衡成果。
(expires字典会保留所有设置了过期工夫的key的过期工夫数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX工夫戳示意的过期工夫。键空间是指该Redis集群中保留的所有键。)
Redis中同时应用了惰性过期和定期过期两种过期策略。
Redis key的过期工夫和永恒无效别离怎么设置?
EXPIRE和PERSIST命令。
咱们晓得通过expire来设置key 的过期工夫,那么对过期的数据怎么解决呢?
除了缓存服务器自带的缓存生效策略之外(Redis默认的有6中策略可供选择),咱们还能够依据具体的业务需要进行自定义的缓存淘汰,常见的策略有两种:
1、定时去清理过期的缓存;
2、当有用户申请过去时,再判断这个申请所用到的缓存是否过期,过期的话就去底层零碎失去新数据并更新缓存。
两者各有优劣,第一种的毛病是保护大量缓存的key是比拟麻烦的,第二种的毛病就是每次用户申请过去都要判断缓存生效,逻辑绝对比较复杂!具体用哪种计划,大家能够依据本人的利用场景来衡量。
内存相干
MySQL里有2000w数据,redis中只存20w的数据,如何保障redis中的数据都是热点数据?
redis内存数据集大小回升到肯定大小的时候,就会实施数据淘汰策略。
Redis的内存淘汰策略有哪些
Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么解决须要新写入且须要申请额定空间的数据。
1、全局的键空间选择性移除
noeviction:当内存不足以包容新写入数据时,新写入操作会报错。
allkeys-lru:当内存不足以包容新写入数据时,在键空间中,移除最近起码应用的key。(这个是最罕用的)
allkeys-random:当内存不足以包容新写入数据时,在键空间中,随机移除某个key。
2、设置过期工夫的键空间选择性移除
volatile-lru:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,移除最近起码应用的key。
volatile-random:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,随机移除某个key。
volatile-ttl:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,有更早过期工夫的key优先移除。
总结
Redis的内存淘汰策略的选取并不会影响过期的key的解决。内存淘汰策略用于解决内存不足时的须要申请额定空间的数据;过期策略用于解决过期的缓存数据。
Redis次要耗费什么物理资源?
内存。
Redis的内存用完了会产生什么?
如果达到设置的下限,Redis的写命令会返回错误信息(然而读命令还能够失常返回。)或者你能够配置内存淘汰机制,当Redis达到内存下限时会冲刷掉旧的内容。
Redis如何做内存优化?
能够好好利用Hash,list,sorted set,set等汇合类型数据,因为通常状况下很多小的Key-Value能够用更紧凑的形式寄存到一起。尽可能应用散列表(hashes),散列表(是说散列表外面存储的数少)应用的内存十分小,所以你应该尽可能的将你的数据模型形象到一个散列表外面。比方你的web零碎中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,明码设置独自的key,而是应该把这个用户的所有信息存储到一张散列表外面。
线程模型
Redis线程模型
Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。它的组成构造为4局部:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的生产是单线程的,所以Redis才叫单线程模型。
1、文件事件处理器应用 I/O 多路复用(multiplexing)程序来同时监听多个套接字, 并依据套接字目前执行的工作来为套接字关联不同的事件处理器。
2、当被监听的套接字筹备好执行连贯应答(accept)、读取(read)、写入(write)、敞开(close)等操作时, 与操作绝对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来解决这些事件。
尽管文件事件处理器以单线程形式运行, 但通过应用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又能够很好地与 redis 服务器中其余同样以单线程形式运行的模块进行对接, 这放弃了 Redis 外部单线程设计的简略性。
事务
什么是事务?
事务是一个独自的隔离操作:事务中的所有命令都会序列化、按程序地执行。事务在执行的过程中,不会被其余客户端发送来的命令申请所打断。
事务是一个原子操作:事务中的命令要么全副被执行,要么全副都不执行。
Redis事务的概念
Redis 事务的实质是通过MULTI、EXEC、WATCH等一组命令的汇合。事务反对一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会依照程序串行化执行队列中的命令,其余客户端提交的命令申请不会插入到事务执行命令序列中。
总结说:redis事务就是一次性、程序性、排他性的执行一个队列中的一系列命令。
Redis事务的三个阶段
1、事务开始 MULTI
2、命令入队
3、事务执行 EXEC
事务执行过程中,如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的申请,将会把申请放入队列中排队
Redis事务相干命令
Redis事务性能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的
Redis会将一个事务中的所有命令序列化,而后按程序执行。
1、redis 不反对回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的外部能够放弃简略且疾速。
2、如果在一个事务中的命令呈现谬误,那么所有的命令都不会执行;
3、如果在一个事务中呈现运行谬误,那么正确的命令会被执行。
WATCH 命令是一个乐观锁,能够为 Redis 事务提供 check-and-set (CAS)行为。能够监控一个或多个键,一旦其中有一个键被批改(或删除),之后的事务就不会执行,监控始终继续到EXEC命令。
MULTI命令用于开启一个事务,它总是返回OK。MULTI执行之后,客户端能够持续向服务器发送任意多条命令,这些命令不会立刻被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。
EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil 。
通过调用DISCARD,客户端能够清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。
UNWATCH命令能够勾销watch对所有key的监控。
事务管理(ACID)概述
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都产生,要么都不产生。
一致性(Consistency)
事务前后数据的完整性必须保持一致。
隔离性(Isolation)
多个事务并发执行时,一个事务的执行不应影响其余事务的执行。
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的扭转就是永久性的,接下来即便数据库产生故障也不应该对其有任何影响。
Redis的事务总是具备ACID中的一致性和隔离性,其余个性是不反对的。当服务器运行在AOF长久化模式下,并且appendfsync选项的值为always时,事务也具备耐久性。
Redis事务反对隔离性吗
Redis 是单过程程序,并且它保障在执行事务时,不会对事务进行中断,事务能够运行直到执行完所有事务队列中的命令为止。因而,Redis 的事务是总是带有隔离性的。
Redis事务保障原子性吗,反对回滚吗
Redis中,单条命令是原子性执行的,但事务不保障原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
Redis事务其余实现
基于Lua脚本,Redis能够保障脚本内的命令一次性、按程序地执行,其同时也不提供事务运行谬误的回滚,执行过程中如果局部命令运行谬误,剩下的命令还是会持续运。
基于两头标记变量,通过另外的标记变量来标识事务是否执行实现,读取数据时先读取该标记变量判断是否事务执行实现。但这样会须要额定写代码实现,比拟繁琐。
集群计划
哨兵模式
哨兵的介绍
sentinel,中文名是哨兵。哨兵是 redis 集群机构中十分重要的一个组件,次要有以下性能:
集群监控:负责监控 redis master 和 slave 过程是否失常工作。
音讯告诉:如果某个 redis 实例有故障,那么哨兵负责发送音讯作为报警告诉给管理员。
故障转移:如果 master node 挂掉了,会主动转移到 slave node 上。
配置核心:如果故障转移产生了,告诉 client 客户端新的 master 地址。
哨兵用于实现 redis 集群的高可用,自身也是分布式的,作为一个哨兵集群去运行,相互协同工作。
1、故障转移时,判断一个 master node 是否宕机了,须要大部分的哨兵都批准才行,波及到了分布式选举的问题。
2、即便局部哨兵节点挂掉了,哨兵集群还是能失常工作的,因为如果一个作为高可用机制重要组成部分的故障转移零碎自身是单点的,那就很坑爹了。
哨兵的外围常识
1、哨兵至多须要 3 个实例,来保障本人的健壮性。
2、哨兵 + redis 主从的部署架构,是不保证数据零失落的,只能保障 redis 集群的高可用性。
3、对于哨兵 + redis 主从这种简单的部署架构,尽量在测试环境和生产环境,都进行短缺的测试和演练。
官网Redis Cluster 计划(服务端路由查问)
redis 集群模式的工作原理能说一下么?在集群模式下,redis 的 key 是如何寻址的?分布式寻址都有哪些算法?理解一致性 hash 算法吗?
简介
Redis Cluster是一种服务端Sharding技术,3.0版本开始正式提供。Redis Cluster并没有应用一致性hash,而是采纳slot(槽)的概念,一共分成16384个槽。将申请发送到任意节点,接管到申请的节点会将查问申请发送到正确的节点上执行
计划阐明
1、通过哈希的形式,将数据分片,每个节点均分存储肯定哈希槽(哈希值)区间的数据,默认调配了16384 个槽位
2、每份数据分片会存储在多个互为主从的多节点上
3、数据写入先写主节点,再同步到从节点(反对配置为阻塞同步)
4、同一分片多个节点间的数据不放弃一致性
5、读取数据时,当客户端操作的key没有调配在该节点上时,redis会返回转向指令,指向正确的节点
6、扩容时时须要须要把旧节点的数据迁徙一部分到新节点
在 redis cluster 架构下,每个 redis 要放开两个端口号,比方一个是 6379,另外一个就是 加1w 的端口号,比方 16379。
16379 端口号是用来进行节点间通信的,也就是 cluster bus 的货色,cluster bus 的通信,用来进行故障检测、配置更新、故障转移受权。cluster bus 用了另外一种二进制的协定,gossip 协定,用于节点间进行高效的数据交换,占用更少的网络带宽和解决工夫。
节点间的外部通信机制
根本通信原理
集群元数据的保护有两种形式:集中式、Gossip 协定。redis cluster 节点间采纳 gossip 协定进行通信。
分布式寻址算法
hash 算法(大量缓存重建)
一致性 hash 算法(主动缓存迁徙)+ 虚构节点(主动负载平衡)
redis cluster 的 hash slot 算法
长处
1、无核心架构,反对动静扩容,对业务通明
2、具备Sentinel的监控和主动Failover(故障转移)能力
3、客户端不须要连贯集群所有节点,连贯集群中任何一个可用节点即可
4、高性能,客户端直连redis服务,免去了proxy代理的损耗
毛病
1、运维也很简单,数据迁徙须要人工干预
2、只能应用0号数据库
3、不反对批量操作(pipeline管道操作)
4、分布式逻辑和存储模块耦合等
基于客户端调配
简介
Redis Sharding是Redis Cluster进去之前,业界广泛应用的多Redis实例集群办法。其次要思维是采纳哈希算法将Redis数据的key进行散列,通过hash函数,特定的key会映射到特定的Redis节点上。Java redis客户端驱动jedis,反对Redis Sharding性能,即ShardedJedis以及联合缓存池的ShardedJedisPool
长处
劣势在于非常简单,服务端的Redis实例彼此独立,互相无关联,每个Redis实例像单服务器一样运行,非常容易线性扩大,零碎的灵活性很强
毛病
1、因为sharding解决放到客户端,规模进一步扩充时给运维带来挑战。
2、客户端sharding不反对动静增删节点。服务端Redis实例群拓扑构造有变动时,每个客户端都须要更新调整。连贯不能共享,当利用规模增大时,资源节约制约优化
基于代理服务器分片
简介
客户端发送申请到一个代理组件,代理解析客户端的数据,并将申请转发至正确的节点,最初将后果回复给客户端
特色
1、通明接入,业务程序不必关怀后端Redis实例,切换成本低
2、Proxy 的逻辑和存储的逻辑是隔离的
3、代理层多了一次转发,性能有所损耗
业界开源计划
1、Twtter开源的Twemproxy
2、豌豆荚开源的Codis
Redis 主从架构
单机的 redis,可能承载的 QPS 大略就在上万到几万不等。对于缓存来说,个别都是用来撑持读高并发的。因而架构做成主从(master-slave)架构,一主多从,主负责写,并且将数据复制到其它的 slave 节点,从节点负责读。所有的读申请全副走从节点。这样也能够很轻松实现程度扩容,撑持读高并发。
redis replication -> 主从架构 -> 读写拆散 -> 程度扩容撑持读高并发
redis replication 的外围机制
1、redis 采纳异步形式复制数据到 slave 节点,不过 redis2.8 开始,slave node 会周期性地确认本人每次复制的数据量;
2、一个 master node 是能够配置多个 slave node 的;
3、slave node 也能够连贯其余的 slave node;
4、slave node 做复制的时候,不会 block master node 的失常工作;
5、slave node 在做复制的时候,也不会 block 对本人的查问操作,它会用旧的数据集来提供服务;然而复制实现的时候,须要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了;
6、slave node 次要用来进行横向扩容,做读写拆散,扩容的 slave node 能够进步读的吞吐量。
留神,如果采纳了主从架构,那么倡议必须开启 master node 的长久化,不倡议用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉 master 的长久化,可能在 master 宕机重启的时候数据是空的,而后可能一通过复制, slave node 的数据也丢了。
另外,master 的各种备份计划,也须要做。万一本地的所有文件失落了,从备份中筛选一份 rdb 去复原 master,这样能力确保启动的时候,是有数据的,即便采纳了后续解说的高可用机制,slave node 能够主动接管 master node,但也可能 sentinel 还没检测到 master failure,master node 就主动重启了,还是可能导致下面所有的 slave node 数据被清空。
redis 主从复制的外围原理
当启动一个 slave node 的时候,它会发送一个 PSYNC 命令给 master node。
如果这是 slave node 首次连贯到 master node,那么会触发一次 full resynchronization 全量复制。此时 master 会启动一个后盾线程,开始生成一份 RDB 快照文件,
同时还会将从客户端 client 新收到的所有写命令缓存在内存中。RDB 文件生成结束后, master 会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,而后再从本地磁盘加载到内存中,
接着 master 会将内存中缓存的写命令发送到 slave,slave 也会同步这些数据。
slave node 如果跟 master node 有网络故障,断开了连贯,会主动重连,连贯之后 master node 仅会复制给 slave 局部短少的数据。
过程原理
1、当从库和主库建设MS关系后,会向主数据库发送SYNC命令
2、主库接管到SYNC命令后会开始在后盾保留快照(RDB长久化过程),并将期间接管到的写命令缓存起来
3、当快照实现后,主Redis会将快照文件和所有缓存的写命令发送给从Redis
4、从Redis接管到后,会载入快照文件并且执行收到的缓存的命令
5、之后,主Redis每当接管到写命令时就会将命令发送从Redis,从而保证数据的统一
毛病
所有的slave节点数据的复制和同步都由master节点来解决,会照成master节点压力太大,应用主从从构造来解决
Redis集群的主从复制模型是怎么的?
为了使在局部节点失败或者大部分节点无奈通信的状况下集群依然可用,所以集群应用了主从复制模型,每个节点都会有N-1个复制品
生产环境中的 redis 是怎么部署的?
redis cluster,10 台机器,5 台机器部署了 redis 主实例,另外 5 台机器部署了 redis 的从实例,每个主实例挂了一个从实例,5 个节点对外提供读写服务,每个节点的读写顶峰qps可能能够达到每秒 5 万,5 台机器最多是 25 万读写申请/s。
机器是什么配置?32G 内存+ 8 核 CPU + 1T 磁盘,然而调配给 redis 过程的是10g内存,个别线上生产环境,redis 的内存尽量不要超过 10g,超过 10g 可能会有问题。
5 台机器对外提供读写,一共有 50g 内存。
因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会主动故障迁徙,redis 从实例会主动变成主实例持续提供读写服务。
你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是 10kb。100 条数据是 1mb,10 万条数据是 1g。常驻内存的是 200 万条商品数据,占用内存是 20g,仅仅不到总内存的 50%。目前高峰期每秒就是 3500 左右的申请量。
其实大型的公司,会有基础架构的 team 负责缓存集群的运维。
说说Redis哈希槽的概念?
Redis集群没有应用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定搁置哪个槽,集群的每个节点负责一部分hash槽。
Redis集群会有写操作失落吗?为什么?
Redis并不能保证数据的强一致性,这象征这在理论中集群在特定的条件下可能会失落写操作。
Redis集群之间是如何复制的?
异步复制
Redis集群最大节点个数是多少?
16384个
Redis集群如何抉择数据库?
Redis集群目前无奈做数据库抉择,默认在0数据库。
分区
Redis是单线程的,如何进步多核CPU的利用率?
能够在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来应用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想应用多个CPU,你能够考虑一下分片(shard)。
为什么要做Redis分区?
分区能够让Redis治理更大的内存,Redis将能够应用所有机器的内存。如果没有分区,你最多只能应用一台机器的内存。分区使Redis的计算能力通过简略地减少计算机失去成倍晋升,Redis的网络带宽也会随着计算机和网卡的减少而成倍增长。
你晓得有哪些Redis分区实现计划?
1、客户端分区就是在客户端就曾经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。大多数客户端曾经实现了客户端分区。
2、代理分区 意味着客户端将申请发送给代理,而后代理决定去哪个节点写数据或者读数据。代理依据分区规定决定申请哪些Redis实例,而后依据Redis的响应后果返回给客户端。redis和memcached的一种代理实现就是Twemproxy。
3、查问路由(Query routing) 的意思是客户端随机地申请任意一个redis实例,而后由Redis将申请转发给正确的Redis节点。Redis Cluster实现了一种混合模式的查问路由,但并不是间接将申请从一个redis节点转发到另一个redis节点,而是在客户端的帮忙下间接redirected到正确的redis节点。
Redis分区有什么毛病?
1、波及多个key的操作通常不会被反对。例如你不能对两个汇合求交加,因为他们可能被存储到不同的Redis实例(实际上这种状况也有方法,然而不能间接应用交加指令)。
2、同时操作多个key,则不能应用Redis事务。
3、分区应用的粒度是key,不能应用一个十分长的排序key存储一个数据集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set)
4、当应用分区的时候,数据处理会非常复杂,例如为了备份你必须从不同的Redis实例和主机同时收集RDB / AOF文件。
5、分区时动静扩容或缩容可能非常复杂。Redis集群在运行时减少或者删除Redis节点,能做到最大水平对用户通明地数据再均衡,但其余一些客户端分区或者代理分区办法则不反对这种个性。然而,有一种预分片的技术也能够较好的解决这个问题。
分布式问题
Redis实现分布式锁
Redis为单过程单线程模式,采纳队列模式将并发拜访变成串行拜访,且多客户端对Redis的连贯并不存在竞争关系Redis中能够应用SETNX命令实现分布式锁。
当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 曾经存在,则 SETNX 不做任何动作
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
返回值:设置胜利,返回 1 。设置失败,返回 0 。
应用SETNX实现同步锁的流程及事项如下:
应用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取胜利
为了避免获取锁后程序出现异常,导致其余线程/过程调用SETNX命令总是返回0而进入死锁状态,须要为该key设置一个“正当”的过期工夫
开释锁,应用DEL命令将锁数据删除
如何解决 Redis 的并发竞争 Key 问题
所谓 Redis 的并发竞争 Key 的问题也就是多个零碎同时对一个 key 进行操作,然而最初执行的程序和咱们冀望的程序不同,这样也就导致了后果的不同!
举荐一种计划:分布式锁(zookeeper 和 redis 都能够实现分布式锁)。(如果不存在 Redis 的并发竞争 Key 问题,不要应用分布式锁,这样会影响性能)
基于zookeeper长期有序节点能够实现的分布式锁。大抵思维为:每个客户端对某个办法加锁时,在zookeeper上的与该办法对应的指定节点的目录下,生成一个惟一的刹时有序节点。判断是否获取锁的形式很简略,只须要判断有序节点中序号最小的一个。当开释锁的时候,只需将这个刹时节点删除即可。同时,其能够防止服务宕机导致的锁无奈开释,而产生的死锁问题。实现业务流程后,删除对应的子节点开释锁。
在实践中,当然是从以可靠性为主。所以首推Zookeeper。
分布式Redis是后期做还是前期规模上来了再做好?为什么?
既然Redis是如此的轻量(单实例只应用1M内存),为避免当前的扩容,最好的方法就是一开始就启动较多实例。即使你只有一台服务器,你也能够一开始就让Redis以分布式的形式运行,应用分区,在同一台服务器上启动多个实例。
一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来说这操作起来可能比拟麻烦,然而从短暂来看做这点就义是值得的。
这样的话,当你的数据一直增长,须要更多的Redis服务器时,你须要做的就是仅仅将Redis实例从一台服务迁徙到另外一台服务器而已(而不必思考从新分区的问题)。一旦你增加了另一台服务器,你须要将你一半的Redis实例从第一台机器迁徙到第二台机器。
什么是 RedLock
Redis 官网站提出了一种权威的基于 Redis 实现分布式锁的形式名叫 Redlock,此种形式比原先的单节点的办法更平安。它能够保障以下个性:
1、平安个性:互斥拜访,即永远只有一个 client 能拿到锁
2、防止死锁:最终 client 都可能拿到锁,不会呈现死锁的状况,即便本来锁住某资源的 client crash 了或者呈现了网络分区
3、容错性:只有大部分 Redis 节点存活就能够失常提供服务
缓存异样
缓存雪崩
缓存雪崩是指缓存同一时间大面积的生效,所以,前面的申请都会落到数据库上,造成数据库短时间内接受大量申请而崩掉。
解决方案
1、缓存数据的过期工夫设置随机,避免同一时间大量数据过期景象产生。
2、个别并发量不是特地多的时候,应用最多的解决方案是加锁排队。
3、给每一个缓存数据减少相应的缓存标记,记录缓存的是否生效,如果缓存标记生效,则更新数据缓存。
缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,导致所有的申请都落到数据库上,造成数据库短时间内接受大量申请而崩掉。
解决方案
1、接口层减少校验,如用户鉴权校验,id做根底校验,id<=0的间接拦挡;
2、从缓存取不到的数据,在数据库中也没有取到,这时也能够将key-value对写为key-null,缓存无效工夫能够设置短点,如30秒(设置太长会导致失常状况也没法应用)。这样能够避免攻打用户重复用同一个id暴力攻打;
3、采纳布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个肯定不存在的数据会被这个 bitmap 拦挡掉,从而防止了对底层存储系统的查问压力。
附加
对于空间的利用达到了一种极致,那就是Bitmap和布隆过滤器(Bloom Filter)。
Bitmap:典型的就是哈希表
毛病是,Bitmap对于每个元素只能记录1bit信息,如果还想实现额定的性能,恐怕只能靠就义更多的空间、工夫来实现了。
布隆过滤器(举荐)
就是引入了k(k>1)k(k>1)个互相独立的哈希函数,保障在给定的空间、误判率下,实现元素判重的过程。
它的长处是空间效率和查问工夫都远远超过个别的算法,毛病是有肯定的误识别率和删除艰难。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“抵触”。
Hash存在一个抵触(碰撞)的问题,用同一个Hash失去的两个URL的值有可能雷同。为了缩小抵触,咱们能够多引入几个Hash,如果通过其中的一个Hash值咱们得出某元素不在汇合中,那么该元素必定不在汇合中。只有在所有的Hash函数通知咱们该元素在汇合中时,能力确定该元素存在于汇合中。这便是Bloom-Filter的根本思维。
Bloom-Filter个别用于在大数据量的汇合中断定某元素是否存在。
缓存击穿
缓存击穿是指缓存中没有但数据库中有的数据(个别是缓存工夫到期),这时因为并发用户特地多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力霎时增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案
1、设置热点数据永远不过期
2、加互斥锁,互斥锁
缓存预热
缓存预热就是零碎上线后,将相干的缓存数据间接加载到缓存零碎。这样就能够防止在用户申请的时候,先查询数据库,而后再将数据缓存的问题!用户间接查问当时被预热的缓存数据!
解决方案
1、间接写个缓存刷新页面,上线时手工操作一下;
2、数据量不大,能够在我的项目启动的时候主动进行加载;
3、定时刷新缓存;
缓存降级
当访问量剧增、服务呈现问题(如响应工夫慢或不响应)或非核心服务影响到外围流程的性能时,依然须要保障服务还是可用的,即便是有损服务。零碎能够依据一些要害数据进行主动降级,也能够配置开关实现人工降级。
缓存降级的最终目标是保障外围服务可用,即便是有损的。而且有些服务是无奈降级的(如退出购物车、结算)。
在进行降级之前要对系统进行梳理,看看零碎是不是能够丢卒保帅;从而梳理出哪些必须誓死爱护,哪些可降级;比方能够参考日志级别设置预案:
1、个别:比方有些服务偶然因为网络抖动或者服务正在上线而超时,能够主动降级;
2、正告:有些服务在一段时间内成功率有稳定(如在95~100%之间),能够主动降级或人工降级,并发送告警;
3、谬误:比方可用率低于90%,或者数据库连接池被打爆了,或者访问量忽然猛增到零碎能接受的最大阀值,此时能够依据状况主动降级或者人工降级;
4、严重错误:比方因为非凡起因数据谬误了,此时须要紧急人工降级。
服务降级的目标,是为了避免Redis服务故障,导致数据库跟着一起产生雪崩问题。因而,对于不重要的缓存数据,能够采取服务降级策略,例如一个比拟常见的做法就是,Redis呈现问题,不去数据库查问,而是间接返回默认值给用户。
热点数据和冷数据
热点数据,缓存才有价值
对于冷数据而言,大部分数据可能还没有再次拜访到就曾经被挤出内存,不仅占用内存,而且价值不大。频繁批改的数据,看状况思考应用缓存
对于热点数据,比方咱们的某IM产品,生日祝愿模块,当天的寿星列表,缓存当前可能读取数十万次。再举个例子,某导航产品,咱们将导航信息,缓存当前可能读取数百万次。
数据更新前至多读取两次,缓存才有意义。java培训这个是最根本的策略,如果缓存还没有起作用就生效了,那就没有太大价值了。
那存不存在,批改频率很高,然而又不得不思考缓存的场景呢?有!比方,这个读取接口对数据库的压力很大,然而又是热点数据,这个时候就须要思考通过缓存伎俩,缩小数据库的压力,比方咱们的某助手产品的,点赞数,珍藏数,分享数等是十分典型的热点数据,然而又一直变动,此时就须要将数据同步保留到Redis缓存,缩小数据库压力。
缓存热点key
缓存中的一个Key(比方一个促销商品),在某个工夫点过期的时候,恰好在这个工夫点对这个Key有大量的并发申请过去,这些申请发现缓存过期个别都会从后端DB加载数据并回设到缓存,这个时候大并发的申请可能会霎时把后端DB压垮。
解决方案
对缓存查问加锁,如果KEY不存在,就加锁,而后查DB入缓存,而后解锁;其余过程如果发现有锁就期待,而后等解锁后返回数据或者进入DB查问
常用工具
Redis反对的Java客户端都有哪些?官网举荐用哪个?
Redisson、Jedis、lettuce等等,官网举荐应用Redisson。
Redis和Redisson有什么关系?
Redisson是一个高级的分布式协调Redis客服端,能帮忙用户在分布式环境中轻松实现一些Java的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。
Jedis与Redisson比照有什么优缺点?
Jedis是Redis的Java实现的客户端,其API提供了比拟全面的Redis命令的反对;Redisson实现了分布式和可扩大的Java数据结构,和Jedis相比,性能较为简单,不反对字符串操作,不反对排序、事务、管道、分区等Redis个性。Redisson的主旨是促成使用者对Redis的关注拆散,从而让使用者可能将精力更集中地放在解决业务逻辑上。
其余问题
Redis与Memcached的区别
两者都是非关系型内存键值数据库,当初公司个别都是用 Redis 来实现缓存,而且 Redis 本身也越来越弱小了!Redis 与 Memcached 次要有以下不同:
(1) memcached所有的值均是简略的字符串,redis作为其替代者,反对更为丰盛的数据类型
(2) redis的速度比memcached快很多
(3) redis能够长久化其数据
如何保障缓存与数据库双写时的数据一致性?
你只有用缓存,就可能会波及到缓存与数据库双存储双写,你只有是双写,就肯定会有数据一致性的问题,那么你如何解决一致性问题?
一般来说,就是如果你的零碎不是严格要求缓存+数据库必须一致性的话,缓存能够略微的跟数据库偶然有不统一的状况,最好不要做这个计划,读申请和写申请串行化,串到一个内存队列里去,这样就能够保障肯定不会呈现不统一的状况
串行化之后,就会导致系统的吞吐量会大幅度的升高,用比失常状况下多几倍的机器去撑持线上的一个申请。
还有一种形式就是可能会临时产生不统一的状况,然而产生的几率特地小,就是先更新数据库,而后再删除缓存。
Redis常见性能问题和解决方案?
1、Master最好不要做任何长久化工作,包含内存快照和AOF日志文件,特地是不要启用内存快照做长久化。
2、如果数据比拟要害,某个Slave开启AOF备份数据,策略为每秒同步一次。
3、为了主从复制的速度和连贯的稳定性,Slave和Master最好在同一个局域网内。
4、尽量避免在压力较大的主库上减少从库
5、Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,呈现短暂服务暂停景象。
6、为了Master的稳定性,主从复制不要用图状构造,用单向链表构造更稳固,即主从关系为:Master<–Slave1<–Slave2<–Slave3…,这样的构造也不便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,能够立马启用Slave1做Master,其余不变。
Redis官网为什么不提供Windows版本?
因为目前Linux版本曾经相当稳固,而且用户量很大,无需开发windows版本,反而会带来兼容性等问题。
一个字符串类型的值能存储最大容量是多少?
512M
Redis如何做大量数据插入?
Redis2.6开始redis-cli反对一种新的被称之为pipe mode的新模式用于执行大量数据插入工作。
如果Redis外面有1亿个key,其中有10w个key是以某个固定的已知的前缀结尾的,如果将它们全副找进去?
应用keys指令能够扫出指定模式的key列表。
如果这个redis正在给线上的业务提供服务,那应用keys指令会有什么问题?
这个时候你要答复redis要害的一个个性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会进展,直到指令执行结束,服务能力复原。这个时候能够应用scan指令,scan指令能够无阻塞的提取出指定模式的key列表,然而会有肯定的反复概率,在客户端做一次去重就能够了,然而整体所破费的工夫会比间接用keys指令长。
应用Redis做过异步队列吗,是如何实现的?
应用list类型保留数据信息,rpush生产音讯,lpop生产音讯,当lpop没有音讯时,能够sleep一段时间,而后再查看有没有信息,如果不想sleep的话,能够应用blpop, 在没有信息的时候,会始终阻塞,直到信息的到来。redis能够通过pub/sub主题订阅模式实现一个生产者,多个消费者,当然也存在肯定的毛病,当消费者下线时,生产的音讯会失落。
Redis如何实现延时队列?
应用sortedset,应用工夫戳做score, 音讯内容作为key,调用zadd来生产音讯,消费者应用zrangbyscore获取n秒之前的数据做轮询解决。
Redis回收过程如何工作的?
1、一个客户端运行了新的命令,增加了新的数据。
2、Redis查看内存应用状况,如果大于maxmemory的限度, 则依据设定好的策略进行回收。
3、一个新的命令被执行,等等。
4、所以咱们一直地穿梭内存限度的边界,通过一直达到边界而后一直地回收回到边界以下。
如果一个命令的后果导致大量内存被应用(例如很大的汇合的交加保留到一个新的键),不必多久内存限度就会被这个内存使用量超过。
Redis回收应用的是什么算法?
LRU算法