阿里2021年最新面试题

前言:

最近问我要阿里面试题的人实在是有点多呀 ,私信挨个回复实在是太累了,我在这里统一给大家一个回复了,也是让自己偷个懒。

面试问题如下:

分布式:

一、大型网站系统的特点
高并发,大流量
需要面对高并发用户,大流量访问。 Google 日均 PV 35 亿,日 IP 访问数 3 亿;腾讯 QQ 的最大在线用户数 1.4 亿
2011 年数据)。
高可用
系统 7 x 24 小时不间断服务。
海量数据
需要存储、管理海量数据,需要使用大量服务器。 Facebook 每周上传的照片数量接近 10 亿,百度收录的网页数
目有数百亿, Google 有近百万台服务器为全球用户提供服务。
用户分布广泛,网络情况复杂
许多大型互联网站都是为全球用户提供服务的,用户分布范围广,各地网络情况千差万别。在国内,还有各个运营
商网络互通难的问题。
安全环境恶劣
由于互联网的开放性,使得互联网站更容易受到攻击,大型网站几乎每天都会被黑客攻击。
需求快速变更,发布频繁
和传统软件的版本发布频率不同,互联网产品为快速适应市场,满足用户需求,其产品发布频率极高。一般大型网
站的产品每周都有新版本发布上线,中小型网站的发布更频繁,有时候一天会发布几十次。
渐进式发展
几乎所有的大型互联网网站都是从一个小网站开始,渐进地发展起来的。 Facebook 是扎克伯格同学在哈佛大学的
宿舍里开发的; Google 的第一台服务器部署在斯坦福大学的实验室;阿里巴巴是在马云家的客厅诞生的。好的互
联网产品都是慢慢运营出来的,不是一开始就开发好的,这也正好与网站架构的发展演化过程对应。
二、大型网站架构演化发展历程
的数据和面对数以亿计的用户,问题就会变得很棘手。大型网站架构主要解决这类问题。
初始阶段的网站架构
大型网站都是从小型网站发展而来,网站架构也是一样,是从小型网站架构逐步演化而来。小型网站最开始没有太
多人访问,只需要一台服务器就绰绰有余,这时的网站架构如下图所示:

应用程序、数据库、文件等所有资源都在一台服务器上。
应用服务和数据服务分离
随着网站业务的发展,一台服务器逐渐不能满足需求:越来越多的用户访问导致性能越来越差,越来越多的数据导
致存储空间不足。这时就需要将应用和数据分离。应用和数据分离后整个网站使用 3 台服务器:应用服务器、文件
服务器和数据库服务器。这 3 台服务器对硬件资源的要求各不相同:
应用服务器需要处理大量的业务逻辑,因此需要更快更强大的 CPU
数据库服务器需要快速磁盘检索和数据缓存,因此需要更快的磁盘和更大的内存;
文件服务器需要存储大量用户上传的文件,因此需要更大的硬盘。
此时,网站系统的架构如下图所示:
应用和数据分离后,不同特性的服务器承担不同的服务角色,网站的并发处理能力和数据存储空间得到了很大改
善,支持网站业务进一步发展。但是随着用户逐渐增多,网站又一次面临挑战:数据库压力太大导致访问延迟,进
而影响整个网站的性能,用户体验受到影响。这时需要对网站架构进一步优化。
使用缓存改善网站性能
网站访问的特点和现实世界的财富分配一样遵循二八定律: 80% 的业务访问集中在 20% 的数据上。既然大部分业
务访问集中在一小部分数据上,那么如果把这一小部分数据缓存在内存中,就可以减少数据库的访问压力,提高整
个网站的数据访问速度,改善数据库的写入性能了。 网站使用的缓存可以分为两种:缓存在应用服务器上的本地缓
存和缓存在专门的分布式缓存服务器上的远程缓存。
本地缓存的访问速度更快一些,但是受应用服务器内存限制,其缓存数据量有限,而且会出现和应用程序争
用内存的情况。
远程分布式缓存可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可以在理论上做到不受
内存容量限制的缓存服务。

使用缓存后,数据访问压力得到有效缓解,但是单一应用服务器能够处理的请求连接有限,在网站访问高峰期,应
用服务器成为整个网站的瓶颈。
使用应用服务器集群改善网站的并发处理能力
使用集群是网站解决高并发、海量数据问题的常用手段。当一台服务器的处理能力、存储空间不足时,不要企图去
更换更强大的服务器,对大型网站而言,不管多么强大的服务器,都满足不了网站持续增长的业务需求。这种情况
下,更恰当的做法是增加一台服务器分担原有服务器的访问及存储压力。 对网站架构而言,只要能通过增加一台服
务器的方式改善负载压力,就可以以同样的方式持续增加服务器不断改善系统性能,从而实现系统的可伸缩性 。应
用服务器实现集群是网站可伸缩架构设计中较为简单成熟的一种,如下图所示:
通过负载均衡调度服务器,可以将来自用户浏览器的访问请求分发到应用服务器集群中的任何一台服务器上,如果
有更多用户,就在集群中加入更多的应用服务器,使应用服务器的压力不再成为整个网站的瓶颈。
数据库读写分离
网站在使用缓存后,使对大部分数据读操作访问都可以不通过数据库就能完成,但是仍有一部分读操作(缓存访问
不命中、缓存过期)和全部的写操作都需要访问数据库,在网站的用户达到一定规模后,数据库因为负载压力过高
而成为网站的瓶颈。 目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数
据库服务器的数据更新同步到另一台服务器上。网站利用数据库的这一功能,实现数据库读写分离,从而改善数据
库负载压力。如下图所示:
应用服务器在写数据的时候,访问主数据库,主数据库通过主从复制机制将数据更新同步到从数据库,这样当应用
服务器读数据的时候,就可以通过从数据库获得数据。为了便于应用程序访问读写分离后的数据库,通常在应用服
务器端使用专门的数据访问模块,使数据库读写分离对应用透明。
使用反向代理和 CDN 加速网站响应
随着网站业务不断发展,用户规模越来越大,由于中国复杂的网络环境,不同地区的用户访问网站时,速度差别也
极大。有研究表明,网站访问延迟和用户流失率正相关,网站访问越慢,用户越容易失去耐心而离开。为了提供更
好的用户体验,留住用户,网站需要加速网站访问速度。主要手段有使用 CDN 和方向代理。如下图所示:
CDN 和反向代理的基本原理都是缓存。
CDN 部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据
反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如
果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户
使用 CDN 和反向代理的目的都是尽早返回数据给用户,一方面加快用户访问速度,另一方面也减轻后端服务器的
负载压力。
使用分布式文件系统和分布式数据库系统
任何强大的单一服务器都满足不了大型网站持续增长的业务需求。数据库经过读写分离后,从一台服务器拆分成两
台服务器,但是随着网站业务的发展依然不能满足需求,这时需要使用分布式数据库。文件系统也一样,需要使用
分布式文件系统。如下图所示:
分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更
常用的数据库拆分手段是业务分库,将不同业务的数据部署在不同的物理服务器上。
使用 NoSQL 和搜索引擎
随着网站业务越来越复杂,对数据存储和检索的需求也越来越复杂,网站需要采用一些非关系数据库技术如
NoSQL 和非数据库查询技术如搜索引擎。如下图所示:
NoSQL 和搜索引擎都是源自互联网的技术手段,对可伸缩的分布式特性具有更好的支持。应用服务器则通过一个
统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。
业务拆分
大型网站为了应对日益复杂的业务场景,通过使用分而治之的手段将整个网站业务分成不同的产品线。如大型购物
交易网站都会将首页、商铺、订单、买家、卖家等拆分成不同的产品线,分归不同的业务团队负责。
具体到技术上,也会根据产品线划分,将一个网站拆分成许多不同的应用,每个应用独立部署。应用之间可以通过
一个超链接建立关系(在首页上的导航链接每个都指向不同的应用地址),也可以通过消息队列进行数据分发,当
然最多的还是通过访问同一个数据存储系统来构成一个关联的完整系统,如下图所示:
分布式微服务
随着业务拆分越来越小,存储系统越来越庞大,应用系统的整体复杂度呈指数级增加,部署维护越来越困难。由于
所有应用要和所有数据库系统连接,在数万台服务器规模的网站中,这些连接的数目是服务器规模的平方,导致数
据库连接资源不足,拒绝服务。
既然每一个应用系统都需要执行许多相同的业务操作,比如用户管理、商品管理等,那么可以将这些共用的业务提
取出来,独立部署。由这些可复用的业务连接数据库,提供共用业务服务,而应用系统只需要管理用户界面,通过
分布式服务调用共用业务服务完成具体业务操作。如下图所示:
三、拆分 VS 集群
1. 拆分:不同的 多台服务器上面部署不同的服务模块 ,模块之间通过 RPC 通信和调用,用于拆分业务功能,独立
部署,多个服务器共同组成一个整体对外提供服务。
2. 集群:不同的 多台服务器上面部署相同的服务模块 ,通过分布式调度软件进行统一的调度,用于分流容灾,
降低单个服务器的访问压力。
四、微服务 VS SOA
单体应用: ALL IN ONE
微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各
个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表
着一个小的业务能力
微服务,从本质意义上看,还是 SOA 架构。但内涵有所不同,微服务并不绑定某种特殊的技术,在一个微服务的
系统中,可以有 Java 编写的服务,也可以有 Python 编写的服务,他们是靠 Restful 架构风格统一成一个系统的。所
以微服务本身与具体技术实现无关,扩展性强。
五、前后端完全分离与 Rest 规范
http 是目前在互联网上使用最多的协议,没有之一。可是 http 的创始人一直都觉得,在过去 10 几年来,所有的人都
在错误的使用 Http
这句话怎么说呢?如果说你要删除一个数据,以往的做法通常是 delete/{id} ,如果你要更新一个数据,可能是 Post
数据放 Body ,然后方法是 update/{id} , 或者是 artichle/{id}?method=update
这种做法让我很暴燥,我觉得这个世界不该这样的,所有的人都在误解而且在严重错误的误解 Http 的设计初衷,好
比是发明了火药却只用它来做烟花爆竹。
那么正确的使用方式是什么呢?如果你要看 Rest 各种特性,你恐怕真的很难理解 Rest ,但是如果你看错误的使用
http 的人倒底儿了哪些错,什么是 Rest 就特别容易理解了。
第一条,混乱。 一万个人心里有一万个 Url 的命名规则, Url 是统一资源定位符,重点是资源。而很多人却把它当成
了万金油,每一个独立的虚拟的网页都可以随意使用,各种操作都能够迭加。这是混乱的来源之一。
第二条,贪婪。 有状态和无状态全部混在一起。特别是在购物车或者是登录的应用中,经常刷新就丢失带来的用户
体验简直棒棒哒。每一个请求并不能单独的响应一些功能,很多的功能混杂在一起里。这是人性贪婪的本质,也是
各种 Hack 的起源,只要能够把问题解决掉,总会有人用他认为最方便的方式去解决问题,比如说汽车门把手坏掉
了直接系根绳子当把手, emmmm 这样确实很棒啊。
第三条,无序。 返回的结果往往是很随意,各种错误信息本来就是用 Http 的状态码构成的,可是很多人还是喜欢把
错误信息返回在返回值中。最常见的就是 Code Message ,当然对于这一点,我个人是保留疑问的,我的观点
是, Http 本身的错误和服务器的内部错误还是需要在不断层面分开的,不能混在一起。可是在大神眼里并非如此,
这个再议。
好了我编不下去了。那么怎么解决这些问题呢?强迫症患者的福音就是先颁规则,第一个规则就是明确 Url 是什
么,该怎么用。就是所有的 Url 本质来讲,都应该是一种资源。一个独立的 Url 地址,就是对应一个独一无二的资
源。怎么样?这种感觉是不是棒棒哒?一个冰淇淋,一个老师,一间房子,在 Url 上对应的都是一个资源,不会有
多余的 Url 跟他对应,也不会表示有多个 Url 地址 ~~ 注意,这里点的是 Url 地址,并不是单独的参数,他就是一
/room/{room_id} 这样的东西,举个栗子 ,/room/3242 这就表示 3242 号房间。
这是一个清爽的世界啊,你想想,之前的 Url 是什么都要,我开房,可能是 /open/room/3242 我要退房可能
/exit/3242/room ,我要打理房间,可能是 room/3242?method=clean.
够了!这些乱七八糟的东西全够了,让世界回归清爽的本质,一间房,就是 /room/3242 没有别的 Url 地址了。 那
我想要对这个资源有操作怎么办?这就是棒棒哒大神想出来的了, http 有几种 Method 来着? get ,put
,post,delete ,还有其他隐藏的 4 种。在过去的混乱世界里,经常用的就是 Get Post 。如果不是因为 Get 不支持大
数据传输,我想连 Post 都会有人使用。(想像一下 Roy Fielding 在愤怒的对着电脑屏幕喊, Http Method 一共
有八个,你们为毛只逮着 Get 一只羊的毛薅薅薅薅薅)。
而对资源最常见的操作是什么? CRUD ,对不对,就是创建,读,更新,删除。再看 Http Method ?是不是非常
完美?其实也怪 Fielding 老爷子一开始命名不准确,如果刚开始就是把 Get 方法叫做 Read Put 方法叫做 Update
Post 叫做 Create 这该多好。。。
你用一个 Get ,大家又发现没什么限制没什么所谓,又很难理解 Put Post 的差别,法无禁止即可为啊,呃,老爷子
不要瞪我,我瞎说的。
总之,这四种方法够不够你浪?你有本身找出来更多的对资源的操作来啊,我还有 4 Method 没用过呢。如果这 4
个真的不够了,有什么问题,大不了我再重新更改 http 协议啊。
其实简单说,对于 Rest 理解到这里就够了。后续的东西,都是在这一条基础上空想出来的,比强迫症更强迫症,当
然,无状态我是百分百支持的。以上的各种表述可能不太准确,也纯属是我的意淫和各种小道资料,并未考据,但
是凭良心讲,我是早就看不惯黑暗年代里的 Url 命名风格了,所以当时最早接触到 Rest 的时候,瞬间就找到了真
爱,我靠,这不就是我一直想要的答案吗?
但是我一直想的仅仅是命名规范,从来没有把自己的思考角度放在一个 url 就是一个资源,所有的操作都是对资源
的更改而言的角度上啊。所以你能理解到的程度,更多的就是在于你要弄清楚你要解决的什么问题,如果你的问题
只是理解 Rest ,恐怕你很理解,如果你的问题是怎么解决 Url 混乱的问题,你反而很快能弄懂了 ~
Rest 操作最佳实践: 现在在很多企业中,虽然都在支持 Rest 规范,但是真正严格遵守的几乎没有,因为按照
Rest 规范,删除需要发送 Delete 请求,插入需要发送 PUT 请求,过于繁琐,并且有些框架,例如 ajax
Springmvc 等,对 Delete PUT 请求的支持不太友好,所以实际应用中很少使用这两种请求,一般还是只是
Get Post 请求,使用接口名字来区分,所以,对于 Rest 规范,只需要记得传递数据只使用 JSON ,而不是
后端去渲染模板,从而实现前后端的完全分离。
六、 CAP 三进二和 Base 定理
关系型数据库遵循 ACID 规则
事务在英文中是 transaction ,和现实世界中的交易很类似,它有如下四个特性:
1 A (Atomicity) 原子性 原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的
条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。比如银行转账,从 A 账户转
100 元至 B 账户,分为两个步骤: 1 )从 A 账户取 100 元; 2 )存入 100 元至 B 账户。这两步要么一起完成,要么一起不
完成,如果只完成第一步,第二步失败,钱会莫名其妙少了 100 元。
2 C (Consistency) 一致性 一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变
数据库原本的一致性约束。
3 I (Isolation) 独立性 所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一
个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。比如现有有个交易是从 A 账户
100 元至 B 账户,在这个交易还未完成的情况下,如果此时 B 查询自己的账户,是看不到新增加的 100 元的
4 D (Durability) 持久性 持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也
不会丢失。
CAP 三进二
在分布式系统中,讲究 C:Consistency (强一致性)、 A:Availability (可用性)、 P:Partition tolerance (分区容错
性)
CAP 的证明基于异步网络,异步网络也是反映了真实网络中情况的模型。真实的网络系统中,节点之间不可能保持
同步,即便是时钟也不可能保持同步,所有的节点依靠获得的消息来进行本地计算和通讯。这个概念其实是相当强
的,意味着任何超时判断也是不可能的,因为没有共同的时间标准。之后我们会扩展 CAP 的证明到弱一点的异步网
络中,这个网络中时钟不完全一致,但是时钟运行的步调是一致的,这种系统是允许节点做超时判断的。
CAP 的证明很简单,假设两个节点集 {G1, G2} ,由于网络分片导致 G1 G2 之间所有的通讯都断开了,如果不满足
P ,则整个网络不可用,如果在 G1 中写,在 G2 中读刚写的数据, G2 中返回的值不可能 G1 中的写值。由于 A 的要
求, G2 一定要返回这次读请求,由于 P 的存在,导致 C 一定是不可满足的。
CAP 理论就是说在分布式存储系统中,最多只能实现上面的两点。 而由于当前的网络硬件肯定会出现延迟丢包等问
题,所以
分区容忍性是我们必须需要实现的。
所以我们只能在一致性和可用性之间进行权衡,没有任何分布式系统能同时保证这三点。
C: 强一致性 A :高可用性 P :分布式容忍性 CA 传统 Oracle 数据库
AP 大多数网站架构的选择
CP Redis Mongodb
注意:分布式架构的时候必须做出取舍。 一致性和可用性之间取一个平衡。多余大多数 web 应用,其实并不需要
强一致性。
因此牺牲 C 换取 P ,这是目前分布式数据库产品的方向
一致性与可用性的决择
对于 web2.0 网站来说,关系数据库的很多主要特性却往往无用武之地
数据库事务一致性需求 很多 web 实时系统并不要求严格的数据库事务,对读一致性的要求很低, 有些场合对写一
致性要求并不高。允许实现最终一致性。
数据库的写实时性和读实时性需求 对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据
的,但是对于很多 web 应用来说,并不要求这么高的实时性,比方说发一条消息之 后,过几秒乃至十几秒之后,我
的订阅者才看到这条动态是完全可以接受的。
对复杂的 SQL 查询,特别是多表关联查询的需求 任何大数据量的 web 系统,都非常忌讳多个大表的关联查询,以
及复杂的数据分析类型的报表查询,特别是 SNS 类型的网站,从需求以及产品设计角 度,就避免了这种情况的产
生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询, SQL 的功能被极大的弱化了。
CAP 理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求, 最多只能同
时较好的满足两个。 因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三
大类:
CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。
AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
BASE 定理
BASE 就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。
BASE 其实是下面三个术语的缩写:
 
基本可用( Basically Available
软状态( Soft state
最终一致( Eventually consistent 它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。为什么这么说呢, 缘由就在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些 指标,我们必须采用另外一种方式来完成,这里 BASE 就是解决这个问题的办法
分布式一致性理论 paxos raft zab 算法
演示 Raft http://thesecretlivesofdata.com/raft /
中间件
一、缓存
为什么要使用缓存
(一)性能 如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的 SQL ,就特别适合将运行结果放入
缓存。这样,后面的请求就去缓存中读取,使得请求能够 迅速响应
题外话: 忽然想聊一下这个 迅速响应 的标准。其实根据交互效果的不同,这个响应时间没有固定标准。不过曾经有
人这么告诉我 :" 在理想状态下,我们的页面跳转需要在 瞬间 解决,对于页内操作则需要在 刹那 间解决。另外,超过
一弹指 的耗时操作要有进度提示,并且可以随时中止或取消,这样才能给用户最好的体验。 "
那么 瞬间、刹那、一弹指 具体是多少时间呢?
根据《摩诃僧祗律》记载
一刹那者为一念,二十念为一瞬,二十瞬为一弹指,二十弹指为一罗预,二十罗预为一须臾,一日一夜有三十须臾。
那么,经过周密的计算,一 瞬间 0.36 , 刹那 0.018 . 弹指 长达 7.2 秒。
(二)并发 如下图所示,在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就 需要使用 redis 做一个缓冲操作,让请求先访问到 redis ,而不是直接访问数据库。

 

优秀的缓存系统 Redis
Redis 是完全开源免费的,用 C 语言编写的,遵守 BSD 协议,是一个高性能的 (key/value) 分布式内存数据库,基于内
存运行并支持持久化的 NoSQL 数据库,是当前最热门的 NoSql 数据库之一 , 也被人们称为数据结构服务器
Redis 相比同类的其他产品,具有如下优点:
Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list set zset hash 等数据结构的存储
Redis 支持数据的备份,即 master-slave 模式的数据备份
redis 为什么这么快
主要是以下三点
纯内存操作
单线程操作,避免了频繁的上下文切换
采用了非阻塞 I/O 多路复用机制
题外话: 我们现在要仔细的说一说 I/O 多路复用机制,因为这个说法实在是太通俗了,通俗到一般人都不懂是什么
意思。博主打一个比方:小曲在 S 城开了一家快递店,负责同城快送服务。小曲因为资金限制,雇佣了 一批 快递
员,然后小曲发现资金不够了,只够买 一辆 车送快递。
经营方式一 客户每送来一份快递,小曲就让一个快递员盯着,然后快递员开车去送快递。慢慢的小曲就发现了这种
经营方式存在下述问题
几十个快递员基本上时间都花在了抢车上了,大部分快递员都处在闲置状态,谁抢到了车,谁就能去送快递
随着快递的增多,快递员也越来越多,小曲发现快递店里越来越挤,没办法雇佣新的快递员了
快递员之间的协调很花时间
综合上述缺点,小曲痛定思痛,提出了下面的经营方式
经营方式二 小曲只雇佣一个快递员。然后呢,客户送来的快递,小曲按 送达地点 标注好,然后 依次 放在一个地方。
最后,那个快递员 依次 的去取快递,一次拿一个,然后开着车去送快递,送好了就回来拿下一个快递。
对比 上述两种经营方式对比,是不是明显觉得第二种,效率更高,更好呢。在上述比喻中 :
每个快递员 ------------------> 每个线程
每个快递 --------------------> 每个 socket(I/O )
快递的送达地点 -------------->socket 的不同状态
客户送快递请求 --------------> 来自客户端的请求
小曲的经营方式 --------------> 服务端运行的代码
一辆车 ---------------------->CPU 的核数
于是我们有如下结论 1 、经营方式一就是传统的并发模型,每个 I/O ( 快递 ) 都有一个新的线程 ( 快递员 ) 管理。 2
经营方式二就是 I/O 多路复用。只有单个线程 ( 一个快递员 ) ,通过跟踪每个 I/O 流的状态 ( 每个快递的送达地点 ) ,来管
理多个 I/O 流。
下面类比到真实的 redis 线程模型,如图所示
参照上图,简单来说,就是。我们的 redis-client 在操作的时候,会产生具有不同事件类型的 socket 。在服务端,有
一段 I/0 多路复用程序,将其置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器
中。 需要说明的是,这个 I/O 多路复用机制, redis 还提供了 select epoll evport kqueue 等多路复用函数库,
大家可以自行去了解。
redis 的数据类型,以及每种数据类型的使用场景
( )String 这个其实没啥好说的,最常规的 set/get 操作, value 可以是 String 也可以是数字。一般做 一些复杂的计数
功能的缓存。
( )hash 这里 value 存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做 单点登录 的时候,就
是用这种数据结构存储用户信息,以 cookieId 作为 key ,设置 30 分钟为缓存过期时间,能很好的模拟出类似 session
的效果。
( )list 使用 List 的数据结构,可以 做简单的消息队列的功能 。另外还有一个就是,可以利用 lrange 命令, 做基于
redis 的分页功能 ,性能极佳,用户体验好。
( )set 因为 set 堆放的是一堆不重复值的集合。所以可以做 全局去重的功能 。为什么不用 JVM 自带的 Set 进行去重?
因为我们的系统一般都是集群部署,使用 JVM 自带的 Set ,比较麻烦,难道为了一个做一个全局去重,再起一个公共
服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以 计算共同喜好,全部的喜好,自己独有的 * *
好等功能 **
( )sorted set
sorted set 多了一个权重参数 score, 集合中的元素能够按 score 进行排列。可以做 排行榜应用,取 TOP N 操作 。另
外,参照另一篇《分布式之延时任务方案解析》,该文指出了 sorted set 可以用来做 延时任务 。最后一个应用就是
可以做 范围查找
redis 的过期策略以及内存淘汰机制
分析 : 这个问题其实相当重要,到底 redis 有没用到家,这个问题就可以看出来。比如你 redis 只能存 5G 数据,可是你
写了 10G ,那会删 5G 的数据。怎么删的,这个问题思考过么?还有,你的数据已经设置了过期时间,但是时间到
了,内存占用率还是比较高,有思考过原因么 ? 回答 : redis 采用的是定期删除 + 惰性删除策略。 为什么不用定时删
除策略 ? 定时删除 , 用一个定时器来负责监视 key, 过期则自动删除。虽然内存及时释放,但是十分消耗 CPU 资源。在
大并发请求下, CPU 要将时间应用在处理请求,而不是删除 key, 因此没有采用这一策略 . 定期删除 + 惰性删除是如何
工作的呢 ? 定期删除, redis 默认每个 100ms 检查,是否有过期的 key, 有过期 key 则删除。需要说明的是, redis 不是
每个 100ms 将所有的 key 检查一次,而是随机抽取进行检查 ( 如果每隔 100ms, 全部 key 进行检查, redis 岂不是卡
) 。因此,如果只采用定期删除策略,会导致很多 key 到时间没有删除。 于是,惰性删除派上用场。也就是说在你
获取某个 key 的时候, redis 会检查一下,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删
除。 采用定期删除 + 惰性删除就没其他问题了么 ? 不是的,如果定期删除没删除 key 。然后你也没即时去请求 key
也就是说惰性删除也没生效。这样, redis 的内存会越来越高。那么就应该采用 内存淘汰机制 。 在 redis.conf 中有一
行配置
该配置就是配内存淘汰策略的 ( 什么,你没配过?好好反省一下自己 ) 1 noeviction :当内存不足以容纳新写入数据
时,新写入操作会报错。 应该没人用吧。 2 allkeys-lru :当内存不足以容纳新写入数据时,在键空间中,移除最
近最少使用的 key 推荐使用,目前项目在用这种。 3 allkeys-random :当内存不足以容纳新写入数据时,在键
空间中,随机移除某个 key 应该也没人用吧,你不删最少使用 Key, 去随机删。 4 volatile-lru :当内存不足以容
纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key 这种情况一般是把 redis 既当缓存,又
做持久化存储的时候才用。不推荐 5 volatile-random :当内存不足以容纳新写入数据时,在设置了过期时间的键
空间中,随机移除某个 key 依然不推荐 6 volatile-ttl :当内存不足以容纳新写入数据时,在设置了过期时间的键
空间中,有更早过期时间的 key 优先移除。 不推荐 ps :如果没有设置 expire key, 不满足先决条件
(prerequisites); 那么 volatile-lru, volatile-random volatile-ttl 策略的行为 , noeviction( 不删除 ) 基本上一致。
渐进式 ReHash
渐进式 rehash 的原因
整个 rehash 过程并不是一步完成的,而是分多次、渐进式的完成。如果哈希表中保存着数量巨大的键值对时,若一
次进行 rehash ,很有可能会导致服务器宕机。
渐进式 rehash 的步骤
ht[1] 分配空间,让字典同时持有 ht[0] ht[1] 两个哈希表
维持索引计数器变量 rehashidx ,并将它的值设置为 0 ,表示 rehash 开始
每次对字典执行增删改查时,将 ht[0] rehashidx 索引上的所有键值对 rehash ht[1] ,将 rehashidx +1
 

最后:

以上的资料是免费提供给大家的,喜欢的点个赞哟~

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值