文章目录
- 高并发相关问题
- 1.项目如何拆分的,分为几个子系统
- 2.NGINX的原理,负载均衡的策略
- 3.Tomcat集群
- 4.Redis的原理,支持的数据类型,分片/哨兵/集群的原理和优缺点,持久化,实际项目应用
- 5.缓存穿透,缓存雪崩,缓存击穿
- 6.dubbo的原理,RPC通信原理,zookeeper和eureka的区别,dubbo支持的协议
- 7.消息队列的原理,五种工作模式,实际应用哪种(路由模式比较多,重点了解)
- 8.springcloud的核心组件
- 9 补充
高并发相关问题
1.项目如何拆分的,分为几个子系统
分布式思想
概念: 将系统按照指定的规则进行拆分.形成了多个业务的子系统.
优势:如果其中一个宕机,则不会影响整个项目的正常运行.
作用: 为了降低系统架构的耦合性.
弊端: 之前可能只需要运维一个服务器. 现在需要运维多个服务器. 运维的成本变高了.
1.1 按照功能模块拆分(垂直拆分)
垂直拆分之后,项目实现了松耦合.当一个模块出现问题.不会影响整个项目运行.
1.2 按照层级进行拆分(水平拆分)
在垂直拆分的基础之上进行水平拆分,按照代码的层级进行拆分,将层级拆分为具体项目。一般大项目才会进行水平拆分.因为多人维护同一个项目时容易出错。
2.NGINX的原理,负载均衡的策略
2.1 nginx介绍
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器
,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
特点: 占有内存少 不超过2M ,并发能力强 3-5万次/秒
2.1 Nginx的优缺点?
- 优点:
- 占内存小,可实现高并发连接,处理响应快
- 可实现http服务器、虚拟主机、方向代理、负载均衡
- Nginx配置简单
- 可以不暴露正式的服务器IP地址
- 缺点:
动态处理差:nginx处理静态文件好,耗费内存少,但是处理动态页面则很鸡肋,现在一般前端用nginx作为反向代理抗住压力,
2.3 Nginx应用场景
- http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
- 虚拟主机。可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机。
- 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以用nginx做反向代理。并且多台服务器可以平均分担负载,不会应为某台服务器负载高宕机而某台服务器闲置的情况。
- nginz 中也可以配置安全管理、比如可以使用Nginx搭建API接口网关,对每个接口服务进行拦截。
2.3 为什么要做动静分离?
-
Nginx是当下最热的Web容器,网站优化的重要点在于静态化网站,网站静态化的关键点则是是动静分离,动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们则根据静态资源的特点将其做缓存操作。
-
让静态的资源只走静态资源服务器,动态的走动态的服务器
-
Nginx的静态处理能力很强,但是动态处理能力不足,因此,在企业中常用动静分离技术。
-
对于静态资源比如图片,js,css等文件,我们则在反向代理服务器nginx中进行缓存。这样浏览器在请求一个静态资源时,代理服务器nginx就可以直接处理,无需将请求转发给后端服务器tomcat。
若用户请求的动态文件,比如servlet,jsp则转发给Tomcat服务器处理,从而实现动静分离。这也是反向代理服务器的一个重要的作用。
2.4 Nginx负载均衡的算法怎么实现的?策略有哪些?
为了避免服务器崩溃,大家会通过负载均衡的方式来分担服务器压力。将对台服务器组成一个集群,当用户访问时,先访问到一个转发服务器,再由转发服务器将访问分发到压力更小的服务器。
Nginx负载均衡实现的策略有以下五种:
2.4.1 轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某个服务器宕机,能自动剔除故障系统。
upstream backserver {
server 192.168.0.12;
server 192.168.0.13;
}
2.4.2 权重 weight
weight的值越大分配到的访问概率越高,主要用于后端每台服务器性能不均衡的情况下
。其次是为在主从
的情况下设置不同的权值,达到合理有效的地利用主机资源。
upstream backserver {
server 192.168.0.12 weight=2;
server 192.168.0.13 weight=8;
}
权重越高,在被访问的概率越大,如上例,分别是20%,80%。
2.4.3 ip_hash( IP绑定)
每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题
upstream backserver {
ip_hash;
server 192.168.0.12:88;
server 192.168.0.13:80;
}
弊端:
- 用户与服务器进行绑定,当
服务器宕机时则可能影响用户的使用
. - 由于访问是通过算数计算的结果,可能导致严重的
负载不均
的现象.
2.4.4 fair(第三方插件)
-
必须安装upstream_fair模块。
-
对比 weight、ip_hash更加智能的负载均衡算法,fair算法可以根据页面大小和加载时间长短智能地进行负载均衡,响应时间短的优先分配。
upstream backserver {
server server1;
server server2;
fair;
}
哪个服务器的响应速度快,就将请求分配到那个服务器上
2.4.5 url_hash(第三方插件)
- 必须安装Nginx的hash软件包
- 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
3.Tomcat集群
4.Redis的原理,支持的数据类型,分片/哨兵/集群的原理和优缺点,持久化,实际项目应用
4.1 缓存的基本思想
缓存的基本思想其实很简单,就是我们非常熟悉的空间换时间
。不要把缓存想的太高大上,虽然,它的确对系统的性能提升的性价比非常高。
其实,我们在学习使用缓存的时候,你会发现缓存的思想实际在操作系统或者其他地方都被大量用到。 比如 CPU Cache 缓存的是内存数据用于解决 CPU 处理速度和内存不匹配的问题,内存缓存的是硬盘数据用于解决硬盘访问速度过慢的问题。 再比如操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把块表理解为一种特殊的高速缓冲存储器(Cache)。
回归到业务系统来说:我们为了避免用户在请求数据的时候获取速度过于缓慢,所以我们在数据库之上增加了缓存这一层来弥补。
4.2缓存机制的介绍
说明:使用缓存机制主要的目的就是为了降低用户访问物理设备的频次.从缓存服务器中直接获取数据,快速的响应用户,提高整体的查询速度.用户体验更好.
如何实现:
1.缓存机制应该采用什么样的数据结构 进行构建? K-V结构
K必须唯一
2.应该使用什么语言进行开发? C语言
3.缓存的运行环境是哪? 内存
4.内存断电即擦除, 如何保证数据的安全性?? 实现持久化(写入磁盘)
操作
5.内存中的数据如何进行优化 (不能一直存? ) 内存优化的算法 LRU算法
4.3 Redis介绍
Redis 是一个开源(BSD许可)的,内存
中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability).
速度快:
- tomcat: 150-220/秒
- nginx: 3-5万/秒
- redis: 写:8.6万/秒;读:11.2万/秒 ~ 平均10万次/秒
注意:Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念
4.3.1 各个数据类型应用场景
类型 | 简介 | 特性 | 场景 |
---|---|---|---|
String | 二进制安全 | 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M | – |
Hash(字典) | 键值对集合,即编程语言中的Map类型 | 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) | 存储、读取、修改用户属性 |
List(列表) | 链表(双向链表) | 增删快,提供了操作某一段元素的API | 1、最新消息排行等功能(比如朋友圈的时间线) ;2、消息队列 |
Set(集合) | 哈希表实现,元素不重复 | 1、添加、删除,查找的复杂度都是O(1) ;2、为集合提供了求交集、并集、差集等操作 | 1、共同好友 ;2、利用唯一性,统计访问网站的所有独立ip;’3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐 |
Sorted Set(有序集合) | 将Set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行天然排序 | 1、排行榜;2、带权重的消息队列 |
4.3.2 redis使用场景
4.4 Redis持久化
Redis中的数据都保存在内存中.如果服务关闭或者宕机则内存资源直接丢失.导致缓存失效.
Redis中默认的持久化的方式为RDB模式
.
4.4.1持久化的方式
4.4.1.1 RDB模式
-
特点说明:
1.RDB模式采用定期持久化的方式. 风险:可能丢失数据.
2.RDB模式记录的是当前Redis的内存记录快照. 只记录当前状态. 持久化效率最高的
3.RDB模式是默认的持久化方式. -
持久化命令:
命令1: save 同步操作. 要求记录马上持久化. 可能对现有的操作造成阻塞
名来2: bgsave 异步操作. 开启单独的线程实现持久化任务. -
持久化周期:
save 900 1 在900秒内,如果执行一次更新操作,则持久化一次.
save 300 10 在300秒内,如果执行10次更新操作,则持久化一次.
save 60 10000 在60秒内,如果执行10000次更新操作,则持久化一次.
save 1 1 ???不可以 容易阻塞 性能太低.不建议使用.
用户操作越频繁,则持久化周期越短.
4.4.1.2 AOF模式
-
特点:
1.AOF模式默认是关闭状态 如果需要则手动开启.
2.AOF能够记录程序的执行过程 可以实现数据的实时持久化. AOF文件占用的空间较大.恢复数据的速度较慢.
3.AOF模式开启之后.RDB模式将不生效. -
AOF配置:
持久化周期配置:
appendfsync always 实时持久化.
appendfsync everysec 每秒持久化一次 略低于rdb模式
appendfsync no 自己不主动持久化(被动:由操作系统解决)
4.5 Redis内存优化策略
Redis运行的空间是内存.内存的资源比较紧缺.所以应该维护redis内存数据,将改让redis保留热点数据.
4.5.1 LRU算法
LRU是Least Recently Used的缩写,即最近最少使用
,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
维度: 自上一次使用的时间T
最为理想的内存置换算法.
4.5.2 LFU算法
LFU(least frequently used (LFU) page-replacement algorithm)。即最不经常使用页置换算法
,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。
维度: 引用次数
4.5.3 RANDOM算法
随机算法
4.5.4 配置redis内存策略优化
- volatile-lru 在设定了超时时间的数据, 采用lru算法进行删除.
- allkeys-lru 所有数据采用lru算法
- volatile-lfu 在设定了超时时间的数据, 采用LFU算法进行删除.
- allkeys-lfu 所有数据采用LFU算法
- volatile-random 设定超时时间数据采用随机算法
- allkeys-random 所有数据采用随机算法
- volatile-ttl 设定了超时时间的数据 根据ttl规则删除. 将剩余时间少的提前删除
- noeviction 内存满了 不做任何操作.报错返回.
4.6 分片/哨兵/集群的原理和优缺点
4.6.1 一致性hash算法
一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,目的是解决分布式缓存的问题
。在移除或者添加一个服务器时,能够尽可能小地改变
已存在的服务请求与处理请求服务器之间的映射关系
。一致性哈希解决了
简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩
等问题 [2] 。
4.6.1.1 一致性hash原理
- 首先求出redis服务器(节点)的哈希值,并将其配置到0~232的圆(continuum)上。
- 然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
- 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台redis服务器上。
4.6.1.1.1添加节点带来的影响
如果现在node2和node4节点中间增加一个node5节点,那么在node4和node2之间的这些数据要存储的节点就会有所变化。在图中的黄色区域的数据将会从原来的node4节点挪到node5节点。
4.6.1.1.2 删除节点带来的影响
删除了node2节点后,原本在node2节点上的数据就会被重新定位node4上。这样就产生一个影响:原来node2的数据转移到node4上,这样node4的内存使用率会骤增,如果node2上存在热点数据,node4会扛不住甚至会可能挂掉,挂掉之后数据又转移给node3,如此循环会造成所有节点崩溃,也就是前面所说的雪崩的情况。
4.6.1.1.3节点太少造成的影响
节点太少的话可能造成数据倾斜的情况,如图中中只有俩节点,可能会造成大量数据存放在node A节点上,而node B节点存储很少的数据。
4.6.1.1.4 虚拟节点
为了解决雪崩现象和数据倾斜现象,提出了虚拟节点这个概念
。就是将真实节点计算多个哈希形成多个虚拟节点并放置到哈希环上,定位算法不变,只是多了一步虚拟节点到真实节点映射的过程
以雪崩现象来说明:如下图节点real1节点又俩个虚拟节点v100和v101,real2有俩个虚拟节点v200和v201,real3节点有v300和v301俩个虚拟节点。
当real1节点挂掉后,v100和v101节点也会随即消失,这时k1数据就会被分配到v301上,k4就会被分配到了v200上,这就解决了雪崩的问题,当某个节点宕机后,其数据并没有全部分配给某一个节点,而是被分到了多个节点。
正因为加入了虚拟节点机制,数据倾斜的问题也随之解决
注意:真实节点不放置到哈希环上,只有虚拟节点才会放上去。
4.6.1.2一致性hash 特性
4.6.1.2.1 平衡性(Balance)
平衡性是指hash的结果应该平均分配到各个节点,这样从算法上解决了负载均衡问题
说明:引入虚拟节点,实现数据的平衡
但是平衡是相对的。不是绝对的。
4.6.1.2.2 单调性(Monotonicity)
单调性是指在新增或者删减节点时,不影响系统正常运行。
4.6.1.2.3 分散性(Spread)
分散性是指数据应该分散地存放在分布式集群中的各个节点
(节点自己可以有备份),不必每个节点都存储所有的数据。
鸡蛋不要放到一个篮子里。
4.6.2 分片
redis可以通过修改内存的大小实现数据的保存。但是内存的资源不宜设置的过大
,因为很多的时间都浪费在内存的寻址
中;
如果有海量的数据,需要redis存储
,那么应该如何处理?我们可以采用Redis分片机制
实现内存数据的扩容。
优点:可以实现redis内存的动态扩容.
缺点:没有实现高可用(当其中一台redis服务器发生宕机,则会影响整个分片使用)
4.6.3 哨兵
4.6.3.1 哨兵机制原理
- 首先启动Redis哨兵.由哨兵监控整个Redis主从状态. 主要监控M主机. 同时获取其从机的信息.
- 哨兵利用心跳检测机制(PING-PONG)的方式监控主机是否宕机. 如果连续3次主机没有响应.则哨兵判断主机宕机.
之后开始进行选举. - 根据从主机中获取的从机信息.之后利用选举机制算法.挑选新的主机.
- 之后将剩余的redis修改为当前主机的的从.并且修改配置文件.
4.6.3.2 为什么要用到哨兵
哨兵(Sentinel)主要是为了解决在主从复制架构中出现宕机的情况
4.6.3.3 哨兵机制(sentinel)的高可用
Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。
在Server1 掉线后:
利用选举机制算法,挑选Server2 为新的主服务器:
优点:实现Redis节点的高可用。
缺点:哨兵本身没有高可用效果. 如果哨兵宕机则整个服务宕机;Redis中的数据不能实现内存的扩容。
4.6.4 集群
Redis集群相当于整合redis分片机制(内存扩容),redis哨兵机制(高可用).Redis集群由所有的主节点负责监控和选举.从而在不依赖第三方的基础之后实现了redis集群的高可用.
细节:集群中的所有的节点都能互相通信.(PING-PONG)
4.6.4.1为什么要搭建集群
通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取。
Redis是一个很好的Cache工具。大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿。
由于内存大小的限制,使用一台 Redis 实例显然无法满足需求,这时就需要使用多台 Redis作为缓存数据库。但是如何保证数据存储的一致性呢,这时就需要搭建redis集群.采用合理的机制,保证用户的正常的访问需求.
采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.并且在内部实现高可用的机制.实现了服务故障的自动迁移.
4.6.4.2 Redis集群原理
4.6.4.2.1Redis集群高可用推选原理
原理说明:
Redis的所有节点都会保存当前redis集群中的全部主从状态信息
。并且每个节点都能够相互通信。当一个节点发生宕机现象。则集群中的其他节点通过PING-PONG检测机制检查Redis节点是否宕机。当有半数以上
的节点认为宕机,则认为主节点宕机。同时由Redis剩余的主节点进入选举机制
。投票选举链接宕机的主节点的从机,实现故障迁移。
4.6.4.2.2 Redis集群宕机条件
特点:集群中如果主机宕机,那么从机可以继续提供服务,当主机中没有从机时,则向其它主机借用多余的从机(其他主机有多台从机,自己至少保留一台从机,其他可以外借
)。继续提供服务。如果主机宕机时没有从机可用,则集群崩溃。
答案:9个redis节点,节点宕机5-7次时集群才崩溃。
如图所示:
问题分析:
- 如果有6台Redis搭建集群,问: 最少宕机多少台Redis集群崩溃??? 宕机2台集群崩溃
- 如果搭建9台Redis.3台主机, 问 :最少宕机Redis台 集群奔溃??? 宕机5台集群崩溃
补充说明:如果想让集群尽可能不宕机,则适当增加从节点的数量. 2-3个从即可.
4.6.4.2.3 集群主机
为什么是奇数
集群存活节点数量 > n/2
3 > 1.5 3台可以搭建集群 宕机1台
4 > 2 4台可以搭建集群 宕机1台
通过上述证明,集群搭建的主机台数是奇数时,解是最优的。
一般情况下的集群是奇数的要求. zookeeper Eureka集群
4.6.4.2.4 如果选举平票如何处理?
规定投票进行3次.如果连续平票的概率是1/8。概率偏低。如果适当增加主节点的数量
则可以有效的降低平票导致脑裂的风险.
4.6.4.2.5 Redis hash槽存储数据原理
redis cluster采用数据分片的哈希槽来进行数据存储和数据的读取。redis cluster一共有2^14(16384)个槽,所有的master节点都会有一个槽区比如0~1000,槽数是可以迁移的。master节点的slave节点不分配槽,只拥有读权限。但是注意在代码中redis cluster执行读写操作的都是master节点,并不是你想 的读是从节点,写是主节点。第一次新建redis cluster时,16384个槽是被master节点均匀分布的。
RedisCluster采用此分区,所有的键根据哈希函数(CRC16[key]&16384)映射到0-16383槽内,共16384个槽位,每个节点维护部分槽及槽所映射的键值数据。根据主节点的个数,均衡划分区间。
算法:哈希函数: Hash()=CRC16[key]&16384按位与。
当向redis集群中插入数据时,首先将key进行计算.之后将计算结果匹配到具体的某一个槽的区间内,之后再将数据set到管理该槽的节点中。
Redis分区只负责数据应该存储到哪里的问题。至于是否能存储的下,完全由Redis内存决定。
4.6.4.2.6 Redis hash槽与一致性 hash算法的区别
一致性哈希用于解决
分布式缓存系统
中的数据选择节点存储问题和数据选择节点读取问题以及在增删节点后减少数据缓存的消失范畴,防止雪崩的发生。哈希槽是在
redis cluster集群
方案中采用的,redis cluster集群没有采用一致性哈希方案,而是采用数据分片中的哈希槽来进行数据存储与读取的。
- 运算位置不同:
- redis分片机制在业务服务器中完成的运算.
- redis分区算法在连接Redis之后,由redis进行计算.
- 算法不同:
- 一致性hash算法
- hash槽算法
- redis
分片
可以随意的进行数据的保存; redis分区不能随机存储,分区中只能保存属于我的key;
参考文章:redis一致性hash和hash槽
4.6.4.2.7 分片与集群总结
- 分片的运算发生在tomcat服务器中,数据直接计算完成之后保存到了具体的redis节点中.
- redis集群是将key在redis内部进行计算.之后保存数据,性能浪费在计算上.
4.6.4.2.8 Redis面试题
- Redis集群中的主机最多 多少台?
16384个。 - Redis中存储的数据最多16384个?
不对的。16384只是分区的大小.至于能存储多少数据,完全由内存决定。
5.缓存穿透,缓存雪崩,缓存击穿
5.1 缓存穿透
5.1.1 什么是缓存穿透?
缓存穿透说简单点就是大量请求的 key 根本不存在于缓存中,导致请求直接到了数据库上,根本没有经过缓存这一层
。举个例子:某个黑客故意制造我们缓存中不存在的 key 发起大量请求,导致大量请求落到数据库。
影响:由于用户高并发访问,则数据库可能存在宕机
的风险.
5.1.2 如何避免缓存穿透?
- 方案1:使用API网关
API Gateway很好的解决了微服务下调用、统一接入等问题,如下图所示:
一个API网关的基本功能包含了统一接入、协议适配、流量管理与容错、以及安全防护,这四大基本功能构成了网关的核心功能。网关首要的功能是负责统一接入,然后将请求的协议转换成内部的接口协议,在调用的过程中还要有限流、降级、熔断等容错的方式来保护网关的整体稳定,同时网关还要做到基本的安全防护(防刷控制),以及黑白名单(比如IP白名单)等基本安全措施,如下图所示:
- 方案2:限定IP访问次数
参考文章 - 方案3:缓存无效key
如果缓存和数据库都查不到某个 key 的数据就写一个到 Redis 中去并设置过期时间,具体命令如下:SET key value EX 10086
。这种方式可以解决请求的 key 变化不频繁的情况,如果黑客恶意攻击,每次构建不同的请求 key,会导致 Redis 中缓存大量无效的 key 。很明显,这种方案并不能从根本上解决此问题。如果非要用这种方式来解决穿透问题的话,尽量将无效的 key 的过期时间设置短一点比如 1 分钟。
另外,这里多说一嘴,一般情况下我们是这样设计 key 的:表名:列名:主键名:主键值
。
如果用 Java 代码展示的话,差不多是下面这样的:
public Object getObjectInclNullById(Integer id) {
// 从缓存中获取数据
Object cacheValue = cache.get(id);
// 缓存为空
if (cacheValue == null) {
// 从数据库中获取
Object storageValue = storage.get(key);
// 缓存空对象
cache.set(key, storageValue);
// 如果存储数据为空,需要设置一个过期时间(300秒)
if (storageValue == null) {
// 必须设置过期时间,否则有被攻击的风险
cache.expire(key, 60 * 5);
}
return storageValue;
}
return cacheValue;
}
- 方案4:使用布隆过滤器
布隆过滤器是一个非常神奇的数据结构,通过它我们可以非常方便地判断一个给定数据是否存在于海量数据中。我们需要的就是判断 key 是否合法,有没有感觉布隆过滤器就是我们想要找的那个“人”。
具体是这样做的:把所有可能存在的请求的值都存放在布隆过滤器中,当用户请求过来,先判断用户发来的请求的值是否存在于布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端,存在的话才会走下面的流程。
加入布隆过滤器之后的缓存处理流程图如下。
但是,需要注意的是布隆过滤器可能会存在误判的情况。总结来说就是: 布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。
为什么会出现误判的情况呢? 我们还要从布隆过滤器的原理来说!
我们先来看一下,当一个元素加入布隆过滤器中的时候,会进行哪些操作:
- 使用布隆过滤器中的哈希函数对元素值进行计算,得到哈希值(有几个哈希函数得到几个哈希值)。
- 根据得到的哈希值,在位数组中把对应下标的值置为 1。
我们再来看一下,当我们需要判断一个元素是否存在于布隆过滤器的时候,会进行哪些操作: - 对给定元素再次进行相同的哈希计算;
- 得到值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值在布隆过滤器中,如果存在一个值不为 1,说明该元素不在布隆过滤器中。
然后,一定会出现这样一种情况:不同的字符串可能哈希出来的位置相同。 (可以适当增加位数组大小或者调整我们的哈希函数来降低概率)
更多关于布隆过滤器的内容可以看我的这篇原创:《不了解布隆过滤器?一文给你整的明明白白!》 ,强烈推荐,个人感觉网上应该找不到总结的这么明明白白的文章了。
5.2 缓存雪崩
5.2.1 什么是缓存雪崩?
由于高并发的环境下.大量的用户访问服务器. 缓存中大量的数据在同一时间超时(删除),导致后面的请求都直接落到了数据库上,造成数据库短时间内承受大量请求。
5.2.2 如何避免缓存雪崩
针对 Redis 服务不可用的情况:
- 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
- 限流,避免同时处理大量的请求。
针对热点缓存失效的情况:
3. 设置不同的失效时间比如随机设置缓存的失效时间。
4. 缓存永不失效。
5.3 缓存击穿
5.3.1 什么是缓存击穿
由于用户高并发的访问. 访问的数据刚开始有缓存,但是由于特殊原因 导致缓存失效.(数据是单个
)
缓存击穿是指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。
5.3.2 如何避免缓存击穿
-
设置热点数据永远不过期。
-
加互斥锁,互斥锁参考代码如下:
说明:
1)缓存中有数据,直接走上述代码13行后就返回结果了
2)缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待100ms,再重新去缓存取数据。这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。
3)当然这是简化处理,理论上如果能根据key值加锁就更好了,就是线程A从数据库取key1的数据并不妨碍线程B取key2的数据,上面代码明显做不到这点。
6.dubbo的原理,RPC通信原理,zookeeper和eureka的区别,dubbo支持的协议
6.1 dubbo的原理,RPC通信原理
6.2zookeeper和eureka的区别
都可以作为注册中心的Zookeeper和Eureka,想要理解两种注册中心的区别,首先要理解CAP理论。
CPA理论:C–>Consistency(一致性):数据一致更新,所有数据变动都是同步的。A–>Availability(可用性):好的相应性能。P–>Partition tolerance(分区容忍性):可靠性。
一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性在分布式系统中是必须要保证的,因此我们只能在A和C之间权衡。
故在此Zookeeper保证的是CP,而Eureka则保证的是AP。
-
Zookeeper:
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是Zookeeper会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30s~120s,并且选举期间整个Zookeeper集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题是得Zookeeper集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。 -
Eureka:
Eureka看明白了这点,因此在设计师就有限保证可用性,Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时如果发现连接失败,会自动切换至其他节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
1、Eureka不再从注册列表中溢出因为长时间没有收到心跳而应该过期的服务。
2、Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)。
3、当网络稳定是,当前实例新的注册信息会被同步到其他节点中。
因此,Eureka可以很好的应对网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪
6.3 dubbo支持的协议
Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的。
7.消息队列的原理,五种工作模式,实际应用哪种(路由模式比较多,重点了解)
8.springcloud的核心组件
9 补充
9.1 反向代理/正向代理
9.1.1 反向代理
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率。
特点:
- 反向代理服务器位于用户和目标服务器之间.
- 反向代理服务器就相当于目标服务器.(用户以为代理服务器就是真实服务器)
- 用户通过反向代理服务器获取资源 而不是直接访问真实服务器.
- 用户不清楚真实的服务器到底是谁.
- 反向代理是服务器端代理.保护真实服务器信息.
特征: 用户不清楚真实目标服务器是谁.
反向代理服务器的优点是什么?
反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层。这对于安全方面来说是很好的,特别是当您使用web托管服务时。
9.1.2 正向代理
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。
特点:
1.代理服务器位于用户和服务器之间
2.用户发起请求之前已经清楚的知道谁的目标服务器.
3.用户通过代理服务器到指定的目标服务器获取资源.
4.正向代理保护的是客户端信息**,是客户端代理**
9.1.3关于正向/反向代理总结
正向代理是客户端代理,用户清楚的知道访问的服务器是谁. 保护了客户端信息
反向代理是服务器端代理.用户不清楚访问的真实服务到底是谁. 保护了服务端信息\