21、什么时候不要使用索引?

1. 经常增删改的列不要建立索引;

2. 有大量重复的列不建立索引;

3. 表记录太少不要建立索引。

22、说说什么是 MVCC

多版本并发控制(MVCC=Multi-Version Concurrency Control),是一种用来解决读 - 写冲突的无

锁并发控制。也就是为事务分配单向增长的时间戳,为每个修改保存一个版本。版本与事务时间戳

关联,读操作只读该事务开始前的数据库的快照(复制了一份数据)。这样在读操作不用阻塞写操

作,写操作不用阻塞读操作的同时,避免了脏读和不可重复读。

23MVCC 可以为数据库解决什么问题?

在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数

据库并发读写的性能。同时还可以解决脏读、幻读、不可重复读等事务隔离问题,但不能解决更新

丢失问题。

24、说说 MVCC 的实现原理

MVCC 的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主

要是依赖记录中的 3 个隐式字段、undo 日志、Read View 来实现的。

25MySQL 事务隔离级别?

READ UNCOMMITTED(未提交读):事务中的修改,即使没有提交,对其他事务也都是可见

的。会导致脏读。

READ COMMITTED(提交读):事务从开始直到提交之前,所做的任何修改对其他事务都是

不可见的。会导致不可重复读。这个隔离级别,也可以叫做“不可重复读”。

REPEATABLE READ(可重复读):一个事务按相同的查询条件读取以前检索过的数据,其他事

务插入了满足其查询条件的新数据。产生幻行,会导致幻读。(MySQL 默认隔离级别)

SERIALIZABLE(可串行化):强制事务串行执行。

阿里内部资料26、 请说说 MySQL 数据库的锁?

关于 MySQL 的锁机制,可能会问很多问题,不过这也得看面试官在这方面的知识储备。

MySQL 中有共享锁和排它锁,也就是读锁和写锁。

1. 共享锁:不堵塞,多个用户可以同一时刻读取同一个资源,相互之间没有影响。

2. 排它锁:一个写操作阻塞其他的读锁和写锁,这样可以只允许一个用户进行写入,防止其他用

户读取正在写入的资源。

3. 表锁:系统开销最小,会锁定整张表,MyISAM 使用表锁。

4. 行锁:容易出现死锁,发生冲突概率低,并发高,InnoDB 支持行锁(必须有索引才能实现,

否则会自动锁全表,那么就不是行锁了)。

27、说说什么是锁升级?

MySQL 行锁只能加在索引上,如果操作不走索引,就会升级为表锁。因为 InnoDB 的行锁是加

在索引上的,如果不走索引,自然就没法使用行锁了,原因是 InnoDB 是将 primary key index

和相关的行数据共同放在 B+ 树的叶节点。InnoDB 一定会有一个 primary key,secondary

index 查找的时候,也是通过找到对应的 primary,再找对应的数据行。

当非唯一索引上记录数超过一定数量时,行锁也会升级为表锁。测试发现当非唯一索引相同的

内容不少于整个表记录的二分之一时会升级为表锁。因为当非唯一索引相同的内容达到整个记

录的二分之一时,索引需要的性能比全文检索还要大,查询语句优化时会选择不走索引,造成

索引失效,行锁自然就会升级为表锁。

28、说说悲观锁和乐观锁

悲观锁

说的是数据库被外界(包括本系统当前的其他事物以及来自外部系统的事务处理)修改保持着保守

态度,因此在整个数据修改过程中,将数据处于锁状态。悲观的实现往往是依靠数据库提供的锁机

制,也只有数据库层面提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统汇总实

现了加锁机制,也是没有办法保证系统不会修改数据。

在悲观锁的情况下,为了保证事务的隔离性,就需要一致性锁定读。读取数据时给加锁,其它事务

无法修改这些数据。修改删除数据时也要加锁,其它事务无法读取这些数据。

乐观锁

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机

制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事

务而言,这样的开销往往无法承受。

阿里内部资料而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实

现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过

为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对

此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果

提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

29、怎样尽量避免死锁的出现?

1. 设置获取锁的超时时间,至少能保证最差情况下,可以退出程序,不至于一直等待导致死锁;

2. 设置按照同一顺序访问资源,类似于串行执行;

3. 避免事务中的用户交叉;

4. 保持事务简短并在一个批处理中;

5. 使用低隔离级别;

6. 使用绑定链接。

30、使用 MySQL 的索引应该注意些什么?

31CHAR VARCHAR 的区别?

CHAR 和VARCHAR 类型在存储和检索方面有所不同

CHAR 列长度固定为创建表时声明的长度,长度值范围是1 到255当 CHAR 值被存储时,它们

被用空格填充到特定长度,检索CHAR 值时需删除尾随空格。

阿里内部资料32、主键和候选键有什么区别?

表格的每一行都由主键唯一标识,一个表只有一个主键。主键也是候选键。按照惯例,候选键可以被

指定为主键,并且可以用于任何外 键引用。

33、主键与索引有什么区别?

主键一定会创建一个唯一索引,但是有唯一索引的列不一定是主键;

主键不允许为空值,唯一索引列允许空值;

一个表只能有一个主键,但是可以有多个唯一索引;

主键可以被其他表引用为外键,唯一索引列不可以;

主键是一种约束,而唯一索引是一种索引,是表的冗余数据结构,两者有本

34 MySQL 如何做到高可用方案?

MySQL 高可用,意味着不能一台 MySQL 出了问题,就不能访问了。

1. MySQL 高可用:分库分表,通过 MyCat 连接多个 MySQL

2. MyCat 也得高可用:Haproxy,连接多个 MyCat

3. Haproxy 也得高可用:通过 keepalived 辅助 Haproxy

SpringCloud

1、什么是SpringCloud

Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序,提供与外部系统的集

成。Spring cloud Task,一个生命周期短暂的微服务框架,用于快速构建执行有限数据处理的应用

程序。

2、什么是微服务

微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分为一组小的服务,

每个服务运行在其独立的自己的进程中,服务之间相互协调、互相配合,为用户提供最终价值。服

务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)

,每个服务都围绕着具体

的业务进行构建,并且能够被独立的构建在生产环境、类生产环境等。另外,应避免统一的、集中

阿里内部资料式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行

构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也

可以使用不同的数据存储。

3SpringCloud有什么优势

使用 Spring Boot 开发分布式微服务时,我们面临以下问题

(1)与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题。

(2)服务发现-服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服务目

录,在该目录中注册服务,然后能够查找并连接到该目录中的服务。

(3)冗余-分布式系统中的冗余问题。

(4)负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路,

中央处理单元,或磁盘驱动器的分布。

(5)性能-问题 由于各种运营开销导致的性能问题。

(6)部署复杂性-Devops 技能的要求。

4、 什么是服务熔断?什么是服务降级?

熔断机制是应对雪崩效应的一种微服务链路保护机制。当某个微服务不可用或者响应时间太长时,

会进行服务降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微

服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现,Hystrix会监

控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内调用20次,如果失败,就会启动

熔断机制。

服务降级,一般是从整体负荷考虑。就是当某个服务熔断之后,服务器将不再被调用,此时客户端

可以自己准备一个本地的fallback回调,返回一个缺省值。这样做,虽然水平下降,但好歹可用,

比直接挂掉强。

Hystrix相关注解 @EnableHystrix:开启熔断 @HystrixCommand(fallbackMethod=”XXX”):声明

一个失败回滚处理函数XXX,当被注解的方法执行超时(默认是1000毫秒),就会执行fallback函

数,返回错误提示。

5 Eurekazookeeper都可以提供服务注册与发现的功能,请

说说两个的区别?

Zookeeper保证了CP(C:一致性,P:分区容错性),Eureka保证了AP(A:高可用) 1.当向注

册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的信息,但不能容忍直接

down掉不可用。也就是说,服务注册功能对高可用性要求比较高,但zk会出现这样一种情况,当

master节点因为网络故障与其他节点失去联系时,剩余节点会重新选leader。问题在于,选取

阿里内部资料leader时间过长,30 ~ 120s,且选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪。

在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够

恢复,但是漫长的选取时间导致的注册长期不可用是不能容忍的。

2.Eureka保证了可用性,Eureka各个节点是平等的,几个节点挂掉不会影响正常节点的工作,剩余

的节点仍然可以提供注册和查询服务。而Eureka的客户端向某个Eureka注册或发现时发生连接失

败,则会自动切换到其他节点,只要有一台Eureka还在,就能保证注册服务可用,只是查到的信息

可能不是最新的。除此之外,Eureka还有自我保护机制,如果在15分钟内超过85%的节点没有正常

的心跳,那么Eureka就认为客户端与注册中心发生了网络故障,此时会出现以下几种情况:

①、

Eureka不在从注册列表中移除因为长时间没有收到心跳而应该过期的服务。 ②、Eureka仍然能够

接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点仍然可用)

③、当

网络稳定时,当前实例新的注册信息会被同步到其他节点。

因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样

使整个微服务瘫痪

6SpringBootSpringCloud的区别?

SpringBoot专注于快速方便的开发单个个体微服务。

SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整

合并管理起来,

为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策

竞选、分布式会话等等集成服务

SpringBoot可以离开SpringCloud独立使用开发项目,

但是SpringCloud离不开SpringBoot ,属于

依赖的关系.

SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。

7、负载平衡的意义什么?

在计算中,负载平衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多

种计算资源的工作负载分布。负载平衡旨在优化资源使用,最大化吞吐量,最小化响应时间并避免

任何单一资源 的过载。使用多个组件进行负载平衡而不是单个组件可能会通过冗余来提高可靠性和

可用性。负载平衡通常涉及专用软件或硬件,例如多层交换机或域名系统服务器进程。

8、什么是Hystrix?它如何实现容错?

Hystrix是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避

免的故障时,停止级联故障并在复杂的分布式系统中实现弹性。

通常对于使用微服务架构开发的系统,涉及到许多微服务。这些微服务彼此协作。

阿里内部资料思考以下微服务

假设如果上图中的微服务9失败了,那么使用传统方法我们将传播一个异常。但这仍然会导致整个

系统崩溃。

随着微服务数量的增加,这个问题变得更加复杂。微服务的数量可以高达1000.这是hystrix出现的

地方 我们将使用Hystrix在这种情况下的Fallback方法功能。我们有两个服务employee-consumer

使用由employee-consumer公开的服务。

简化图如下所示

现在假设由于某种原因,employee-producer公开的服务会抛出异常。我们在这种情况下使用

Hystrix定义了一个回退方法。这种后备方法应该具有与公开服务相同的返回类型。如果暴露服务中

出现异常,则回退方法将返回一些值。

9、什么是Hystrix断路器?我们需要它吗?

由于某些原因,employee-consumer公开服务会引发异常。在这种情况下使用Hystrix我们定义了

一个回退方法。如果在公开服务中发生异常,则回退方法返回一些默认值。

阿里内部资料如果fifirstPage method() 中的异常继续发生,则Hystrix电路将中断,并且员工使用者将一起跳过

fifirtsPage方法,并直接调用回退方法。 断路器的目的是给第一页方法或第一页方法可能调用的其他

方法留出时间,并导致异常恢复。可能发生的情况是,在负载较小的情况下,导致异常的问题有更

好的恢复机会 。

10、说说 RPC 的实现原理

首先需要有处理网络连接通讯的模块,负责连接建立、管理和消息的传输。其次需要有编 解码的模

块,因为网络通讯都是传输的字节码,需要将我们使用的对象序列化和反序列 化。剩下的就是客户

端和服务器端的部分,服务器端暴露要开放的服务接口,客户调用服 务接口的一个代理实现,这个

代理实现负责收集数据、编码并传输给服务器然后等待结果 返回。

11eureka自我保护机制是什么?

当Eureka Server 节点在短时间内丢失了过多实例的连接时(比如网络故障或频繁启动关闭客户

端)节点会进入自我保护模式,保护注册信息,不再删除注册数据,故障恢复时,自动退出自我保

护模式。

12,什么是Ribbon

ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。feign默认集成了ribbon。

阿里内部资料13,什么是 feigin ?它的优点是什么?

1.feign采用的是基于接口的注解 2.feign整合了ribbon,具有负载均衡的能力 3.整合了Hystrix,具

有熔断的能力

使用: 1.添加pom依赖。 2.启动类添加@EnableFeignClients 3.定义一个接口

@FeignClient(name=“xxx”)指定调用哪个服务

14 RibbonFeign的区别?

1.Ribbon都是调用其他服务的,但方式不同。 2.启动类注解不同,Ribbon是@RibbonClient feign

的是@EnableFeignClients 3.服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign

则是在定义抽象方法的接口中使用@FeignClient声明。 4.调用方式不同,Ribbon需要自己构建http

请求,模拟http请求

Dubbo

其实关于 Dubbo 的面试题,我觉得最好的文档应该还是官网,因为官网有中文版,照顾了很多阅

读英文文档吃力的小伙伴。但是官网内容挺多的,于是这里就结合官网和平时面试被问的相对较多

的题目整理了一下。

1、 说说一次 Dubbo 服务请求流程?

基本工作流程:

阿里内部资料上图中角色说明:

2、说说 Dubbo 工作原理

工作原理分 10 层:

第一层:service 层,接口层,给服务提供者和消费者来实现的(留给开发人员来实现);

第二层:confifig 层,配置层,主要是对 Dubbo 进行各种配置的,Dubbo 相关配置;

第三层:proxy 层,服务代理层,透明生成客户端的 stub 和服务单的 skeleton,调用的是接

口,实现类没有,所以得生成代理,代理之间再进行网络通讯、负责均衡等;

第四层:registry 层,服务注册层,负责服务的注册与发现;

阿里内部资料第五层:cluster 层,集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一

个服务;

第六层:monitor 层,监控层,对 rpc 接口的调用次数和调用时间进行监控;

第七层:protocol 层,远程调用层,封装 rpc 调用;

第八层:exchange 层,信息交换层,封装请求响应模式,同步转异步;

第九层:transport 层,网络传输层,抽象 mina 和 netty 为统一接口;

第十层:serialize 层,数据序列化层。

这是个很坑爹的面试题,但是很多面试官又喜欢问,你真的要背么?你能背那还是不错的,我建议

不要背,你就想想 Dubbo 服务调用过程中应该会涉及到哪些技术,把这些技术串起来就 OK 了。

面试扩散

如果让你设计一个 RPC 框架,你会怎么做?其实你就把上面这个工作原理中涉及的到技术点总结一

下就行了。

3Dubbo 支持哪些协议?

还有三种,混个眼熟就行:Memcached 协议、Redis 协议、Rest 协议。

上图基本上把序列化的方式也罗列出来了。

详细请参考:Dubbo 官网:http://dubbo.apache.org/zh-cn/docs/user/references/protocol/dub

bo.html。

4、注册中心挂了,consumer 还能不能调用 provider

可以。因为刚开始初始化的时候,consumer 会将需要的所有提供者的地址等信息拉取到本地缓

存,所以注册中心挂了可以继续通信。但是 provider 挂了,那就没法调用了。

阿里内部资料关键字:consumer 本地缓存服务列表。

5、怎么实现动态感知服务下线的呢?

阿里内部资料服务订阅通常有 pull 和 push 两种方式:

pull 模式需要客户端定时向注册中心拉取配置;

push 模式采用注册中心主动推送数据给客户端。

阿里内部资料Dubbo ZooKeeper 注册中心采用是事件通知与客户端拉取方式。服务第一次订阅的时候将会拉取

对应目录下全量数据,然后在订阅的节点注册一个 watcher。一旦目录节点下发生任何数据变化,

ZooKeeper 将会通过 watcher 通知客户端。客户端接到通知,将会重新拉取该目录下全量数据,

并重新注册 watcher。利用这个模式,Dubbo 服务就可以做到服务的动态发现。

注意:ZooKeeper 提供了“心跳检测”功能,它会定时向各个服务提供者发送一个请求(实际上建立

的是一个 socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其

剔除。

6Dubbo 负载均衡策略?

随机(默认):随机来

轮训:一个一个来

活跃度:机器活跃度来负载

一致性 hash:落到同一台机器上

7 Dubbo 容错策略

failover cluster 模式

provider 宕机重试以后,请求会分到其他的 provider 上,默认两次,可以手动设置重试次数,建

议把写操作重试次数设置成 0。

failback 模式

失败自动恢复会在调用失败后,返回一个空结果给服务消费者。并通过定时任务对失败的调用进行

重试,适合执行消息通知等操作。

failfast cluster 模式

快速失败只会进行一次调用,失败后立即抛出异常。适用于幂等操作、写操作,类似于 failover

cluster 模式中重试次数设置为 0 的情况。

failsafe cluster 模式

失败安全是指,当调用过程中出现异常时,仅会打印异常,而不会抛出异常。适用于写入审计日志

等操作。

forking cluster 模式

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多

服务资源。可通过 forks="2" 来设置最大并行数。

broadcacst cluster 模式

广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志

等本地资源信息。

阿里内部资料8Dubbo 动态代理策略有哪些?

默认使用 javassist 动态字节码生成,创建代理类,但是可以通过 SPI 扩展机制配置自己的动态代理

策略。

9、说说 Dubbo Spring Cloud 的区别?

这是很多面试官喜欢问的问题,本人认为其实他们没什么关联之处,但是硬是要问区别,那就说说

吧。

回答的时候主要围绕着四个关键点来说:通信方式、注册中心、监控、断路器,其余像 Spring 分布

式配置、服务网关肯定得知道。

通信方式

Dubbo 使用的是 RPC 通信;Spring Cloud 使用的是 HTTP RestFul 方式。

注册中心

Dubbo 使用 ZooKeeper(官方推荐),还有 Redis、Multicast、Simple 注册中心,但不推荐。;

Spring Cloud 使用的是 Spring Cloud Netflflix Eureka。

监控

Dubbo 使用的是 Dubbo-monitor;Spring Cloud 使用的是 Spring Boot admin。

断路器

Dubbo 在断路器这方面还不完善,Spring Cloud 使用的是 Spring Cloud Netflflix Hystrix。

分布式配置、网关服务、服务跟踪、消息总线、批量任务等。

Dubbo 目前可以说还是空白,而 Spring Cloud 都有相应的组件来支撑。

10Zookeeper Dubbo 的关系?

Zookeeper的作用

zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简

单来说就是ip地址和服务名称的对应关系。当然也可以通过硬编码的方式把这种对应关系在调用方

业务代码中实现,但是如果提供服务的机器挂掉调用者无法知晓,如果不更改代码会继续请求挂掉

的机器提供服务。zookeeper通过心跳机制可以检测挂掉的机器并将挂掉机器的ip和服务对应关系

从列表中删除。至于支持高并发,简单来说就是横向扩展,在不更改代码的情况通过添加机器来提

高运算能力。通过添加新的机器向zookeeper注册服务,服务的提供者多了能服务的客户就多了。

阿里内部资料dubbo

是管理中间层的工具,在业务层到数据仓库间有非常多服务的接入和服务提供者需要调度,dubbo

提供一个框架解决这个问题。 注意这里的dubbo只是一个框架,至于你架子上放什么是完全取决于

你的,就像一个汽车骨架,你需要配你的轮子引擎。这个框架中要完成调度必须要有一个分布式的

注册中心,储存所有服务的元数据,你可以用zk,也可以用别的,只是大家都用zk。

zookeeperdubbo的关系

Dubbo 的将注册中心进行抽象,它可以外接不同的存储媒介给注册中心提供服务,有

ZooKeeper,Memcached,Redis 等。

引入了 ZooKeeper 作为存储媒介,也就把 ZooKeeper 的特性引进来。首先是负载均衡,单注册中

心的承载能力是有限的,在流量达到一定程度的时 候就需要分流,负载均衡就是为了分流而存在

的,一个 ZooKeeper 群配合相应的 Web 应用就可以很容易达到负载均衡;资源同步,单单有负载

均衡还不 够,节点之间的数据和资源需要同步,ZooKeeper 集群就天然具备有这样的功能;命名

服务,将树状结构用于维护全局的服务地址列表,服务提供者在启动 的时候,向 ZooKeeper 上的

指定节点 /dubbo/${serviceName}/providers 目录下写入自己的 URL 地址,这个操作就完成了服

务的发布。 其他特性还有 Mast 选举,分布式锁等。

Nginx

1、简述一下什么是Nginx,它有什么优势和功能?

Nginx是一个web服务器和方向代理服务器,用于HTTP、HTTPS、SMTP、POP3和IMAP协议。因

它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。

Nginx---Ngine X,是一款免费的、自由的、开源的、高性能HTTP服务器和反向代理服务器;

也是一个IMAP、POP3、SMTP代理服务器;Nginx以其高性能、稳定性、丰富的功能、简单的

配置和低资源消耗而闻名。

阿里内部资料也就是说Nginx本身就可以托管网站(类似于Tomcat一样),进行Http服务处理,也可以作为

反向代理服务器 、负载均衡器和HTTP缓存。

Nginx 解决了服务器的C10K(就是在一秒之内连接客户端的数目为10k即1万)问题。它的设

计不像传统的服务器那样使用线程处理请求,而是一个更加高级的机制—事件驱动机制,是一

种异步事件驱动结构。

优点:

1)更快 这表现在两个方面:一方面,在正常情况下,单次请求会得到更快的响应;另一方面,

在高峰期(如有数以万计的并发请求),Nginx可以比其他Web服务器更快地响应请求。

2)高扩展性,跨平台 Nginx的设计极具扩展性,它完全是由多个不同功能、不同层次、不同类型

且耦合度极低的模块组成。因此,当对某一个模块修复Bug或进行升级时,可以专注于模块自身,

无须在意其他。而且在HTTP模块中,还设计了HTTP过滤器模块:一个正常的HTTP模块在处理完请

求后,会有一串HTTP过滤器模块对请求的结果进行再处理。这样,当我们开发一个新的HTTP模块

时,不但可以使用诸如HTTP核心模块、events模块、log模块等不同层次或者不同类型的模块,还

可以原封不动地复用大量已有的HTTP过滤器模块。这种低耦合度的优秀设计,造就了Nginx庞大的

第三方模块,当然,公开的第三方模块也如官方发布的模块一样容易使用。 Nginx的模块都是嵌入

到二进制文件中执行的,无论官方发布的模块还是第三方模块都是如此。这使得第三方模块一样具

备极其优秀的性能,充分利用Nginx的高并发特性,因此,许多高流量的网站都倾向于开发符合自

己业务特性的定制模块。

3)高可靠性:用于反向代理,宕机的概率微乎其微 高可靠性是我们选择Nginx的最基本条件,因

为Nginx的可靠性是大家有目共睹的,很多家高流量网站都在核心服务器上大规模使用Nginx。

Nginx的高可靠性来自于其核心框架代码的优秀设计、模块设计的简单性;另外,官方提供的常用

模块都非常稳定,每个worker进程相对独立,master进程在1个worker进程出错时可以快速“拉

起”新的worker子进程提供服务。

4)低内存消耗 一般情况下,10 000个非活跃的HTTP Keep-Alive连接在Nginx中仅消耗2.5MB的

内存,这是Nginx支持高并发连接的基础。

5)单机支持10万以上的并发连接 这是一个非常重要的特性!随着互联网的迅猛发展和互联网用

户数量的成倍增长,各大公司、网站都需要应付海量并发请求,一个能够在峰值期顶住10万以上并

发请求的Server,无疑会得到大家的青睐。理论上,Nginx支持的并发连接上限取决于内存,10万

远未封顶。当然,能够及时地处理更多的并发请求,是与业务特点紧密相关的。

6)热部署 master管理进程与worker工作进程的分离设计,使得Nginx能够提供热部署功能,即

可以在7×24小时不间断服务的前提下,升级Nginx的可执行文件。当然,它也支持不停止服务就更

新配置项、更换日志文件等功能。

阿里内部资料7)最自由的BSD许可协议 这是Nginx可以快速发展的强大动力。BSD许可协议不只是允许用户免

费使用Nginx,它还允许用户在自己的项目中直接使用或修改Nginx源码,然后发布。这吸引了无数

开发者继续为Nginx贡献自己的智慧。 以上7个特点当然不是Nginx的全部,拥有无数个官方功能模

块、第三方功能模块使得Nginx能够满足绝大部分应用场景,这些功能模块间可以叠加以实现更加

强大、复杂的功能,有些模块还支持Nginx与Perl、Lua等脚本语言集成工作,大大提高了开发效

率。这些特点促使用户在寻找一个Web服务器时更多考虑Nginx。 选择Nginx的核心理由还是它能

在支持高并发请求的同时保持高效的服务。

2Nginx是如何处理一个HTTP请求的呢?

Nginx 是一个高性能的 Web 服务器,能够同时处理大量的并发请求。它结合多进程机制和异步机制

,异步机制使用的是异步非阻塞方式 ,接下来就给大家介绍一下 Nginx 的多线程机制和异步非阻塞

机制 。

1、多进程机制

服务器每当收到一个客户端时,就有 服务器主进程 ( master process )生成一个 子进程(

worker process )出来和客户端建立连接进行交互,直到连接断开,该子进程就结束了。

使用进程的好处是各个进程之间相互独立,不需要加锁,减少了使用锁对性能造成影响,同时降低

编程的复杂度,降低开发成本。其次,采用独立的进程,可以让进程互相之间不会影响 ,如果一个

进程发生异常退出时,其它进程正常工作, master 进程则很快启动新的 worker 进程,确保服务

不会中断,从而将风险降到最低。

缺点是操作系统生成一个子进程需要进行 内存复制等操作,在资源和时间上会产生一定的开销。当

有大量请求时,会导致系统性能下降 。

2、异步非阻塞机制

每个工作进程 使用 异步非阻塞方式 ,可以处理 多个客户端请求 。

当某个 工作进程 接收到客户端的请求以后,调用 IO 进行处理,如果不能立即得到结果,就去 处理

其他请求 (即为 非阻塞 );而 客户端 在此期间也 无需等待响应 ,可以去处理其他事情(即为 异

步 )。

当 IO 返回时,就会通知此 工作进程 ;该进程得到通知,暂时 挂起 当前处理的事务去 响应客户端

请求 。

3、列举一些Nginx的特性

1. Nginx服务器的特性包括:

2. 反向代理/L7负载均衡器

3. 嵌入式Perl解释器

4. 动态二进制升级

5. 可用于重新编写URL,具有非常好的PCRE支持

阿里内部资料4、请列举NginxApache 之间的不同点

5、在Nginx中,如何使用未定义的服务器名称来阻止处理请求?

只需将请求删除的服务器就可以定义为:

Server{

listen 80;

server_name "";

return 444;

}

这里,服务器名被保留为一个空字符串,它将在没有“主机”头字段的情况下匹配请求,而一个特殊

的Nginx的非标准代码444被返回,从而终止连接。

一般推荐 worker 进程数与CPU内核数一致,这样一来不存在大量的子进程生成和管理任务,避免

了进程之间竞争CPU 资源和进程切换的开销。而且 Nginx 为了更好的利用 多核特性 ,提供了 CPU

亲缘性的绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来

Cache 的失效。

对于每个请求,有且只有一个工作进程 对其处理。首先,每个 worker 进程都是从 master进程

fork 过来。在 master 进程里面,先建立好需要 listen 的 socket(listenfd)

之后,然后再 fork 出

多个 worker 进程。

阿里内部资料所有 worker 进程的 listenfd 会在新连接到来时变得可读 ,为保证只有一个进程处理该连接,所有

worker 进程在注册 listenfd 读事件前抢占 accept_mutex ,抢到互斥锁的那个进程注册 listenfd 读

事件 ,在读事件里调用 accept 接受该连接。

当一个 worker 进程在 accept 这个连接之后,就开始读取请求、解析请求、处理请求,产生数据

后,再返回给客户端 ,最后才断开连接。这样一个完整的请求就是这样的了。我们可以看到,一个

请求,完全由 worker 进程来处理,而且只在一个 worker 进程中处理。

在 Nginx 服务器的运行过程中,

主进程和工作进程 需要进程交互。交互依赖于 Socket 实现的管道

来实现。

6、请解释Nginx服务器上的MasterWorker进程分别是什么?

主程序 Master process 启动后,通过一个 for 循环来 接收 和 处理外部信号 ;

主进程通过 fork() 函数产生 worker 子进程 ,每个子进程执行一个 for循环来实现Nginx服务器

对事件的接收和处理 。

7、请解释代理中的正向代理和反向代理

首先,代理服务器一般指局域网内部的机器通过代理服务器发送请求到互联网上的服务器,代理服

务器一般作用在客户端。例如:GoAgent翻墙软件。我们的客户端在进行翻墙操作的时候,我们使

用的正是正向代理,通过正向代理的方式,在我们的客户端运行一个软件,将我们的HTTP请求转发

到其他不同的服务器端,实现请求的分发。

反向代理服务器作用在服务器端,它在服务器端接收客户端的请求,然后将请求分发给具体的服务

器进行处理,然后再将服务器的相应结果反馈给客户端。Nginx就是一个反向代理服务器软件。

从上图可以看出:客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,

还有代理程序的端口。 反向代理正好与正向代理相反,对于客户端而言代理服务器就像是原始服务

器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的

内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给

客户端。

8、解释Nginx用途

Nginx服务器的最佳用法是在网络上部署动态HTTP内容,使用SCGI、WSGI应用程序服务器、用于

脚本的FastCGI处理程序。它还可以作为负载均衡器。

MQ

1、为什么要使用MQ

核心:解耦,异步,削峰

阿里内部资料1)解耦:A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那

如果 C 系统现在不需要了呢?A 系统负责人几乎崩溃......A 系统跟其它各种乱七八糟的系统严重耦

合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。如果使用

MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新

系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消

费即可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要

考虑人家是否调用成功、失败超时等情况。

就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻

烦。但是其实这个调用是不需要直接同步调用接口的,如果用 MQ 给它异步化解耦。

2)异步:A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三个系统写库,自己本地

写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 +

450 + 200 = 953ms,接近 1s,用户感觉搞个什么东西,慢死了慢死了。用户通过浏览器发起请

求。如果使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一

个请求到返回响应给用户,总时长是 3 + 5 = 8ms。

3)削峰:减少高峰时期对服务器压力。

欢迎关注微信公众号:Java后端技术全栈

2MQ有什么优缺点

优点上面已经说了,就是在特殊场景下有其对应的好处,解耦、异步、削峰。

缺点有以下几个:

系统可用性降低 系统引入的外部依赖越多,越容易挂掉。万一 MQ 挂了,MQ 一挂,整套系统崩

溃,你不就完了?

系统复杂度提高 硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?

怎么保证消息传递的顺序性?问题一大堆。

一致性问题 A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是

BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致

了。

3KafkaActiveMQRabbitMQRocketMQ 都有什么区

别?

对于吞吐量来说kafka和RocketMQ支撑高吞吐,ActiveMQ和RabbitMQ比他们低一个数量级。对于

延迟量来说RabbitMQ是最低的。

1.从社区活跃度

阿里内部资料按照目前网络上的资料,RabbitMQ 、activeM 、ZeroMQ 三者中,综合来看,RabbitMQ 是首

选。

2.持久化消息比较

ActiveMq 和RabbitMq 都支持。持久化消息主要是指我们机器在不可抗力因素等情况下挂掉了,消

息不会丢失的机制。

3.综合技术实现

可靠性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件

系统等等。

RabbitMq / Kafka 最好,ActiveMq 次之,ZeroMq 最差。当然ZeroMq 也可以做到,不过自己必

须手动写代码实现,代码量不小。尤其是可靠性中的:持久性、投递确认、发布者证实和高可用

性。

4.高并发

毋庸置疑,RabbitMQ 最高,原因是它的实现语言是天生具备高并发高可用的erlang 语言。

5.比较关注的比较, RabbitMQ Kafka

RabbitMq 比Kafka 成熟,在可用性上,稳定性上,可靠性上, RabbitMq 胜于 Kafka (理论

上)。

另外,Kafka 的定位主要在日志等方面,

因为Kafka 设计的初衷就是处理日志的,可以看做是一个

日志(消息)系统一个重要组件,针对性很强,所以 如果业务方面还是建议选择 RabbitMq 。

还有就是,Kafka 的性能(吞吐量、TPS )比RabbitMq 要高出来很多。

4、如何保证高可用的?

RabbitMQ 是比较有代表性的,因为是基于主从(非分布式)做高可用性的,我们就以 RabbitMQ

为例子讲解第一种 MQ 的高可用性怎么实现。RabbitMQ 有三种模式:单机模式、普通集群模式、

镜像集群模式。

单机模式,就是 Demo 级别的,一般就是你本地启动了玩玩儿的?,没人生产用单机模式

普通集群模式,意思就是在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个。你创建的

queue,只会放在一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认

为是 queue 的一些配置信息,通过元数据,可以找到 queue 所在实例)。你消费的时候,实际上

如果连接到了另外一个实例,那么那个实例会从 queue 所在实例上拉取数据过来。这方案主要是提

高吞吐量的,就是说让集群中多个节点来服务某个 queue 的读写操作。

阿里内部资料镜像集群模式:这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不一样的是,在

镜像集群模式下,你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,就

是说,每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然

后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。RabbitMQ 有很

好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以

要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应用这

个策略,就会自动将数据同步到其他的节点上去了。这样的话,好处在于,你任何一个机器宕机

了,没事儿,其它机器(节点)还包含了这个 queue 的完整数据,别的 consumer 都可以到其它

节点上去消费数据。坏处在于,第一,这个性能开销也太大了吧,消息需要同步到所有机器上,导

致网络带宽压力和消耗很重!RabbitMQ 一个 queue 的数据都是放在一个节点里的,镜像集群下,

也是每个节点都放这个 queue 的完整数据。

Kafka 一个最基本的架构认识:由多个 broker 组成,每个 broker 是一个节点;你创建一个

topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个

partition 就放一部分数据。这就是天然的分布式消息队列,就是说一个 topic 的数据,是分散放在

多个机器上的,每个机器就放一部分数据。Kafka 0.8 以后,提供了 HA 机制,就是 replica(复制

品)

副本机制。每个 partition 的数据都会同步到其它机器上,形成自己的多个 replica 副本。所有

replica 会选举一个 leader 出来,那么生产和消费都跟这个 leader 打交道,然后其他 replica 就是

follower。写的时候,leader 会负责把数据同步到所有 follower 上去,读的时候就直接读 leader

上的数据即可。只能读写 leader?很简单,要是你可以随意读写每个 follower,那么就要 care 数

据一致性的问题,系统复杂度太高,很容易出问题。Kafka 会均匀地将一个 partition 的所有

replica 分布在不同的机器上,这样才可以提高容错性。因为如果某个 broker 宕机了,没事儿,那

个 broker上面的 partition 在其他机器上都有副本的,如果这上面有某个 partition 的 leader,那

么此时会从 follower 中重新选举一个新的 leader 出来,大家继续读写那个新的 leader 即可。这就

有所谓的高可用性了。写数据的时候,生产者就写 leader,然后 leader 将数据落地写本地磁盘,

接着其他 follower 自己主动从 leader 来 pull 数据。一旦所有 follower 同步好数据了,就会发送

ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。(当

然,这只是其中一种模式,还可以适当调整这个行为)消费的时候,只会从 leader 去读,但是只有

当一个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。

5、如何保证消息的可靠传输?如果消息丢了怎么办

数据的丢失问题,可能出现在生产者、MQ、消费者中

生产者丢失:生产者将数据发送到 RabbitMQ 的时候,可能数据就在半路给搞丢了,因为网络问题

啥的,都有可能。此时可以选择用 RabbitMQ 提供的事务功能,就是生产者发送数据之前开启

RabbitMQ 事务channel.txSelect,然后发送消息,如果消息没有成功被 RabbitMQ 接收到,那么

生产者会收到异常报错,此时就可以回滚事务channel.txRollback,然后重试发送消息;如果收到

了消息,那么可以提交事务channel.txCommit。吞吐量会下来,因为太耗性能。所以一般来说,如

果你要确保说写 RabbitMQ 的消息别丢,可以开启confifirm模式,在生产者那里设置开启confifirm模

式之后,你每次写的消息都会分配一个唯一的 id,然后如果写入了 RabbitMQ 中,RabbitMQ 会给

阿里内部资料你回传一个ack消息,告诉你说这个消息 ok 了。如果 RabbitMQ 没能处理这个消息,会回调你一个

nack接口,告诉你这个消息接收失败,你可以重试。而且你可以结合这个机制自己在内存里维护每

个消息 id 的状态,如果超过一定时间还没接收到这个消息的回调,那么你可以重发。事务机制和

cnofifirm机制最大的不同在于,事务机制是同步的,你提交一个事务之后会阻塞在那儿,但是

confifirm机制是异步的,你发送个消息之后就可以发送下一个消息,然后那个消息RabbitMQ 接收

了之后会异步回调你一个接口通知你这个消息接收到了。所以一般在生产者这块避免数据丢失,都

是用confifirm机制的。

MQ中丢失:就是 RabbitMQ 自己弄丢了数据,这个你必须开启 RabbitMQ 的持久化,就是消息写

入之后会持久化到磁盘,哪怕是 RabbitMQ 自己挂了,恢复之后会自动读取之前存储的数据,一般

数据不会丢。设置持久化有两个步骤:创建 queue 的时候将其设置为持久化,这样就可以保证

RabbitMQ 持久化 queue 的元数据,但是不会持久化 queue 里的数据。第二个是发送消息的时候

将消息的 deliveryMode 设置为 2,就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久

化到磁盘上去。必须要同时设置这两个持久化才行,RabbitMQ 哪怕是挂了,再次重启,也会从磁

盘上重启恢复 queue,恢复这个 queue 里的数据。持久化可以跟生产者那边的confifirm机制配合起

来,只有消息被持久化到磁盘之后,才会通知生产者ack了,所以哪怕是在持久化到磁盘之前,

RabbitMQ 挂了,数据丢了,生产者收不到ack,你也是可以自己重发的。注意,哪怕是你给

RabbitMQ 开启了持久化机制,也有一种可能,就是这个消息写到了 RabbitMQ 中,但是还没来得

及持久化到磁盘上,结果不巧,此时 RabbitMQ 挂了,就会导致内存里的一点点数据丢失。

消费端丢失:你消费的时候,刚消费到,还没处理,结果进程挂了,比如重启了,那么就尴尬了,

RabbitMQ 认为你都消费了,这数据就丢了。这个时候得用 RabbitMQ 提供的ack机制,简单来

说,就是你关闭 RabbitMQ 的自动ack,可以通过一个 api 来调用就行,然后每次你自己代码里确

保处理完的时候,再在程序里ack一把。这样的话,如果你还没处理完,不就没有ack?那

RabbitMQ 就认为你还没处理完,这个时候 RabbitMQ 会把这个消费分配给别的 consumer 去处

理,消息是不会丢的。

6、如何保证消息的顺序性

先看看顺序会错乱的场景:RabbitMQ:一个 queue,多个 consumer,这不明显乱了;

阿里内部资料解决:

7、 如何解决消息队列的延时以及过期失效问题?消息队列满了以

后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?

消息积压处理办法:临时紧急扩容:

先修复 consumer 的问题,确保其恢复消费速度,然后将现有 cnosumer 都停掉。 新建一个

topic,partition 是原来的 10 倍,临时建立好原先 10 倍的 queue 数量。 然后写一个临时的分发

数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀

轮询写入临时建立好的 10 倍数量的 queue。 接着临时征用 10 倍的机器来部署 consumer,每一

批 consumer 消费一个临时 queue 的数据。这种做法相当于是临时将 queue 资源和 consumer 资

源扩大 10 倍,以正常的 10 倍速度来消费数据。 等快速消费完积压数据之后,得恢复原先部署的

架构,重新用原先的 consumer 机器来消费消息。 MQ中消息失效:假设你用的是 RabbitMQ,

RabbtiMQ 是可以设置过期时间的,也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被

RabbitMQ 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq

里,而是大量的数据会直接搞丢。我们可以采取一个方案,就是批量重导,这个我们之前线上也有

类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比

如大家一起喝咖啡熬夜到晚上12点以后,用户都睡觉了。这个时候我们就开始写程序,将丢失的那

批数据,写个临时程序,一点一点的查出来,然后重新灌入 mq 里面去,把白天丢的数据给他补回

阿里内部资料来。也只能是这样了。假设 1 万个订单积压在 mq 里面,没有处理,其中 1000 个订单都丢了,你

只能手动写程序把那 1000 个订单给查出来,手动发到 mq 里去再补一次。

mq消息队列块满了:如果消息积压在 mq 里,你很长时间都没有处理掉,此时导致 mq 都快写满

了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数

据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晚上

再补数据吧。

8、让你来设计一个消息队列,你会怎么设计

比如说这个消息队列系统,我们从以下几个角度来考虑一下:

首先这个 mq 得支持可伸缩性吧,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么

搞?设计个分布式的系统呗,参照一下 kafka 的设计理念,broker -> topic -> partition,每个

partition 放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给 topic 增加 partition,

然后做数据迁移,增加机器,不就可以存放更多数据,提供更高的吞吐量了?

其次你得考虑一下这个 mq 的数据要不要落地磁盘吧?那肯定要了,落磁盘才能保证别进程挂了数

据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读

写的性能是很高的,这就是 kafka 的思路。

其次你考虑一下你的 mq 的可用性啊?这个事儿,具体参考之前可用性那个环节讲解的 kafka 的高

可用保障机制。多副本 -> leader & follower -> broker 挂了重新选举 leader 即可对外服务。

能不能支持数据 0 丢失啊?可以的,参考我们之前说的那个 kafka 数据零丢失方案。

数据结构与算法篇

在另外两本小册子里。

Linux

1、 绝对路径用什么符号表示?当前目录、上层目录用什么表示?

主目录用什么表示? 切换目录用什么命令?

绝对路径:

如/etc/init.d

当前目录和上层目录: ./ ../

主目录: ~/

切换目录: cd

阿里内部资料2、 怎么查看当前进程?怎么执行退出?怎么查看当前路径?

查看当前进程: ps

ps -l 列出与本次登录有关的进程信息; ps -aux 查询内存中进程信息; ps -aux | grep * 查询

*进程的详细信息; top 查看内存中进程的动态信息; kill -9 pid 杀死进程。

执行退出: exit

查看当前路径: pwd

3、查看文件有哪些命令

vi 文件名 #编辑方式查看,可修改

cat 文件名 #显示全部文件内容

more 文件名 #分页显示文件内容

less 文件名 #与 more 相似,更好的是可以往前翻页

tail 文件名 #仅查看尾部,还可以指定行数

head 文件名 #仅查看头部,还可以指定行数

4、列举几个常用的Linux命令

列出文件列表:ls【参数 -a -l】

创建目录和移除目录:mkdir rmdir

用于显示文件后几行内容:tail,例如: tail -n 1000:显示最后1000行

打包:tar -xvf

打包并压缩:tar -zcvf

查找字符串:grep

显示当前所在目录:pwd创建空文件:touch

编辑器:vim vi

5、你平时是怎么查看日志的?

Linux查看日志的命令有多种: tail、cat、tac、head、echo等,本文只介绍几种常用的方法。

1tail

最常用的一种查看方式

命令格式: tail[必要参数][选择参数][文件]

阿里内部资料-f 循环读取 -q 不显示处理信息 -v 显示详细的处理信息 -c<数目> 显示的字节数 -n<行数> 显示行数 -

q, --quiet, --silent 从不输出给出文件名的首部 -s, --sleep-interval=S 与-f合用,表示在每次反复的间

隔休眠S秒

例如:

tail -n 10 test.log 查询日志尾部最后10行的日志;

tail -n +10 test.log 查询10行之后的所有日志;

tail -fn 10 test.log 循环实时查看最后1000行记录(最常用的)

一般还会配合着grep搜索用,例如 :

tail -fn 1000 test.log | grep '关键字'

如果一次性查询的数据量太大,可以进行翻页查看,例如:

tail -n 4700 aa.log |more -1000 可以进行多屏显示(ctrl + f 或者 空格键可以快捷键)

2head

跟tail是相反的head是看前多少行日志

head -n 10 test.log 查询日志文件中的头10行日志;

head -n -10 test.log 查询日志文件除了最后10行的其他所有日志;

head其他参数参考tail

3cat

cat 是由第一行到最后一行连续显示在屏幕上

一次显示整个文件 :

$ cat filename

从键盘创建一个文件 :

$cat > filename

将几个文件合并为一个文件:

$cat file1 file2 > file 只能创建新文件,不能编辑已有文件

将一个日志文件的内容追加到另外一个 :

阿里内部资料$cat -n textfile1 > textfile2

清空一个日志文件:

$cat : >textfile2

注意:> 意思是创建,>>是追加。千万不要弄混了。

cat其他参数参考tail

4more

more命令是一个基于vi编辑器文本过滤器,它以全屏幕的方式按页显示文本文件的内容,支持vi中

的关键字定位操作。more名单中内置了若干快捷键,常用的有H(获得帮助信息),Enter(向下

翻滚一行),空格(向下滚动一屏),Q(退出命令)。more命令从前向后读取文件,因此在启动

时就加载整个文件。

该命令一次显示一屏文本,满屏后停下来,并且在屏幕的底部出现一个提示信息,给出至今己显示

的该文件的百分比:–More–(XX%)

more的语法:more 文件名

Enter 向下n行,需要定义,默认为1行

Ctrl f 向下滚动一屏

空格键 向下滚动一屏

Ctrl b 返回上一屏

= 输出当前行的行号

:f 输出文件名和当前行的行号

v 调用vi编辑器

!命令 调用Shell,并执行命令

q退出more

5sed

这个命令可以查找日志文件特定的一段 , 根据时间的一个范围查询,可以按照行号和时间范围查询

按照行号

sed -n '5,10p' filename 这样你就可以只查看文件的第5行到第10行。

按照时间段

sed -n '/2014-12-17 16:17:20/,/2014-12-17 16:17:36/p' test.log

6less

阿里内部资料less命令在查询日志时,一般流程是这样的

less log.log

shift + G 命令到文件尾部 然后输入 ?加上你要搜索的关键字例如 ?1213

按 n 向上查找关键字

shift+n 反向查找关键字

less与more类似,使用less可以随意浏览文件,而more仅能向前移动,不能向后移动,而且 less 在查

看之前不会加载整个文件。

less log2013.log 查看文件

ps -ef | less ps查看进程信息并通过less分页显示

history | less 查看命令历史使用记录并通过less分页显示

less log2013.log log2014.log 浏览多个文件

常用命令参数:

less与more类似,使用less可以随意浏览文件,而more仅能向前移动,不能向后移动,而且 less 在查

看之前不会加载整个文件。

less log2013.log 查看文件

ps -ef | less ps查看进程信息并通过less分页显示

history | less 查看命令历史使用记录并通过less分页显示

less log2013.log log2014.log 浏览多个文件

常用命令参数:

-b <缓冲区大小> 设置缓冲区的大小

-g 只标志最后搜索的关键词

-i 忽略搜索时的大小写

-m 显示类似more命令的百分比

-N 显示每行的行号

-o <文件名> 将less 输出的内容在指定文件中保存起来

-Q 不使用警告音

-s 显示连续空行为一行

/字符串:向下搜索"字符串"的功能

?字符串:向上搜索"字符串"的功能

n:重复前一个搜索(与 / 或 ? 有关)

N:反向重复前一个搜索(与 / 或 ? 有关)

b 向后翻一页

h 显示帮助界面

q 退出less 命令

一般本人查日志配合应用的其他命令

阿里内部资料history // 所有的历史记录

history | grep XXX // 历史记录中包含某些指令的记录

history | more // 分页查看记录

history -c // 清空所有的历史记录

!! 重复执行上一个命令

查询出来记录后选中 : !323

Zookeeper

1,说说 Zookeeper 是什么?

直译:从名字上直译就是动物管理员,动物指的是 Hadoop 一类的分布式软件,管理员三个字体现

了 ZooKeeper 的特点:维护、协调、管理、监控。

简述:有些软件你想做成集群或者分布式,你可以用 ZooKeeper 帮你来辅助实现。

特点:

最终一致性:客户端看到的数据最终是一致的。

可靠性:服务器保存了消息,那么它就一直都存在。

实时性:ZooKeeper 不能保证两个客户端同时得到刚更新的数据。

独立性(等待无关):不同客户端直接互不影响。

原子性:更新要不成功要不失败,没有第三个状态。

注意:回答面试题,切忌只是简单一句话回答,可以将你对概念的理解,特点等多个方面描述一

下,哪怕你自己认为不完全切中题意的也可以说说,面试官不喜欢会打断你的,你的目的是让面试

官认为你是好沟通的。当然了,如果不会可别装作会,说太多不专业的想法。

2 ZooKeeper 有哪些应用场景?

数据发布与订阅

发布与订阅即所谓的配置管理,顾名思义就是将数据发布到ZooKeeper节点上,供订阅者动态获取

数据,实现配置信息的集中式管理和动态更新。例如全局的配置信息,地址列表等就非常适合使

用。

阿里内部资料数据发布/订阅的一个常见的场景是配置中心,发布者把数据发布到 ZooKeeper 的一个或一系列的

节点上,供订阅者进行数据订阅,达到动态获取数据的目的。

配置信息一般有几个特点:

1. 数据量小的KV

2. 数据内容在运行时会发生动态变化

3. 集群机器共享,配置一致

ZooKeeper 采用的是推拉结合的方式。

1. 推: 服务端会推给注册了监控节点的客户端 Wathcer 事件通知

2. 拉: 客户端获得通知后,然后主动到服务端拉取最新的数据

命名服务

作为分布式命名服务,命名服务是指通过指定的名字来获取资源或者服务的地址,利用ZooKeeper

创建一个全局的路径,这个路径就可以作为一个名字,指向集群中的集群,提供的服务的地址,或

者一个远程的对象等等。

统一命名服务的命名结构图如下所示:

阿里内部资料1、在分布式环境下,经常需要对应用/服务进行统一命名,便于识别不同服务。

类似于域名与IP之间对应关系,IP不容易记住,而域名容易记住。

通过名称来获取资源或服务的地址,提供者等信息。

2、按照层次结构组织服务/应用名称。

可将服务名称以及地址信息写到ZooKeeper上,客户端通过ZooKeeper获取可用服务列表类。

配置管理

程序分布式的部署在不同的机器上,将程序的配置信息放在ZooKeeper的znode下,当有配置发生

改变时,也就是znode发生变化时,可以通过改变zk中某个目录节点的内容,利用watch通知给各

个客户端 从而更改配置。

ZooKeeper配置管理结构图如下所示:

1、分布式环境下,配置文件管理和同步是一个常见问题。

阿里内部资料一个集群中,所有节点的配置信息是一致的,比如 Hadoop 集群。

对配置文件修改后,希望能够快速同步到各个节点上。

2、配置管理可交由ZooKeeper实现。

可将配置信息写入ZooKeeper上的一个Znode。

各个节点监听这个Znode。

一旦Znode中的数据被修改,ZooKeeper将通知各个节点。

集群管理

所谓集群管理就是:是否有机器退出和加入、选举master。

集群管理主要指集群监控和集群控制两个方面。前者侧重于集群运行时的状态的收集,后者则是对

集群进行操作与控制。开发和运维中,面对集群,经常有如下需求:

1. 希望知道集群中究竟有多少机器在工作

2. 对集群中的每台机器的运行时状态进行数据收集

3. 对集群中机器进行上下线的操作

集群管理结构图如下所示:

1、分布式环境中,实时掌握每个节点的状态是必要的,可根据节点实时状态做出一些调整。

2、可交由ZooKeeper实现。

可将节点信息写入ZooKeeper上的一个Znode。

监听这个Znode可获取它的实时状态变化。

3、典型应用

阿里内部资料Hbase中Master状态监控与选举。

利用ZooKeeper的强一致性,能够保证在分布式高并发情况下节点创建的全局唯一性,即:同时有

多个客户端请求创建 /currentMaster 节点,最终一定只有一个客户端请求能够创建成功

分布式通知与协调

1、分布式环境中,经常存在一个服务需要知道它所管理的子服务的状态。

a)NameNode需知道各个Datanode的状态。

b)JobTracker需知道各个TaskTracker的状态。

2、心跳检测机制可通过ZooKeeper来实现。

3、信息推送可由ZooKeeper来实现,ZooKeeper相当于一个发布/订阅系统。

分布式锁

处于不同节点上不同的服务,它们可能需要顺序的访问一些资源,这里需要一把分布式的锁。

分布式锁具有以下特性:写锁、读锁、时序锁。

写锁:在zk上创建的一个临时的无编号的节点。由于是无序编号,在创建时不会自动编号,导致只

能客户端有一个客户端得到锁,然后进行写入。

读锁:在zk上创建一个临时的有编号的节点,这样即使下次有客户端加入是同时创建相同的节点

时,他也会自动编号,也可以获得锁对象,然后对其进行读取。

时序锁:在zk上创建的一个临时的有编号的节点根据编号的大小控制锁。

分布式队列

分布式队列分为两种:

1、当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队

列。

a)一个job由多个task组成,只有所有任务完成后,job才运行完成。

b)可为job创建一个/job目录,然后在该目录下,为每个完成的task创建一个临时的Znode,一旦

临时节点数目达到task总数,则表明job运行完成。

2、队列按照FIFO方式进行入队和出队操作,例如实现生产者和消费者模型。

3、说说Zookeeper的工作原理?

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做

Zab协议。

阿里内部资料Zab协议有两种模式,它们 分别是恢复模式(选主)和广播模式(同步)。

Zab协议 的全称是 Zookeeper Atomic Broadcast** (Zookeeper原子广播)。Zookeeper 是通过

Zab 协议来保证分布式事务的最终一致性。Zab协议要求每个 Leader 都要经历三个阶段:发现,同

步,广播。

当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server

完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的

系统状态。

为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议

(proposal)都在被提出的时候加 上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用

来标识leader关系是否改变,每次一个leader被选出来,它都会有一 个新的epoch,标识当前属于

那个leader的统治时期。低32位用于递增计数。

epoch:可以理解为皇帝的年号,当新的皇帝leader产生后,将有一个新的epoch年号。

每个Server在工作过程中有三种状态:

LOOKING:当前Server不知道leader是谁,正在搜寻。

LEADING:当前Server即为选举出来的leader。

FOLLOWING:leader已经选举出来,当前Server与之同步。

4,请描述一下 Zookeeper 的通知机制是什么?

Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听,当服务端的一些指定事件

触发了这个 Watcher ,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客

户端根据 Watcher 通知状态和事件类型做出业务上的改变。

大致分为三个步骤:

客户端注册 Watcher

1、调用 getData、getChildren、exist 三个 API ,传入Watcher 对象。 2、标记请求

request ,封装 Watcher 到 WatchRegistration 。 3、封装成 Packet 对象,发服务端发送

request 。 4、收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理。 5、

请求返回,完成注册。

服务端处理 Watcher

1、服务端接收 Watcher 并存储。 2、Watcher 触发 3、调用 process 方法来触发 Watcher 。

客户端回调 Watcher

1,客户端 SendThread 线程接收事件通知,交由 EventThread 线程回调Watcher 。 2,客户端

的 Watcher 机制同样是一次性的,一旦被触发后,该 Watcher 就失效了。

阿里内部资料client 端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些 client 会收

到 zk 的通知,然后 client 可以根据 znode 变化来做出业务上的改变等。

5 Zookeeper 对节点的 watch 监听通知是永久的吗?

不是,一次性的。无论是服务端还是客户端,一旦一个 Watcher 被触发, Zookeeper 都会将其从

相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务

端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。

6 Zookeeper 集群中有哪些角色?

在一个集群中,最少需要 3 台。或者保证 2N + 1 台,即奇数。为什么保证奇数?主要是为了选举

算法。

7 Zookeeper 集群中Server有哪些工作状态?

LOOKING

寻找 Leader 状态;当服务器处于该状态时,它会认为当前集群中没有 Leader ,因此需要进入

Leader 选举状态

FOLLOWING

跟随者状态;表明当前服务器角色是 Follower

LEADING

领导者状态;表明当前服务器角色是 Leader

OBSERVING

观察者状态;表明当前服务器角色是 Observer

阿里内部资料8 Zookeeper 集群中是怎样选举leader的?

当Leader崩溃了,或者失去了大多数的Follower,这时候 Zookeeper 就进入恢复模式,恢复模式需

要重新选举出一个新的Leader,让所有的Server都恢复到一个状态LOOKING

Zookeeper 有两种选举算法:基于 basic paxos 实现和基于 fast paxos 实现。默认为 fast paxos

由于篇幅问题,这里推荐:选举流程

9 Zookeeper 是如何保证事务的顺序一致性的呢?

Zookeeper 采用了递增的事务 id 来识别,所有的 proposal (提议)都在被提出的时候加上了

zxid 。 zxid 实际上是一个 64 位数字。

高 32 位是 epoch 用来标识 Leader 是否发生了改变,如果有新的 Leader 产生出来, epoch 会自

增。 低 32 位用来递增计数。 当新产生的 proposal 的时候,会依据数据库的两阶段过程,首先会

向其他的 Server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始

执行。

10 ZooKeeper 集群中个服务器之间是怎样通信的?

Leader 服务器会和每一个 Follower/Observer 服务器都建立 TCP 连接,同时为每个

Follower/Observer 都创建一个叫做 LearnerHandler 的实体。

LearnerHandler 主要负责 Leader 和 Follower/Observer 之间的网络通讯,包括数据同步,

请求转发和 proposal 提议的投票等。

Leader 服务器保存了所有 Follower/Observer 的 LearnerHandler 。

11 ZooKeeper 分布式锁怎么实现的?

如果有客户端1、客户端2等N个客户端争抢一个 Zookeeper 分布式锁。大致如下:

1. 大家都是上来直接创建一个锁节点下的一个接一个的临时有序节点

2. 如果自己不是第一个节点,就对自己上一个节点加监听器

3. 只要上一个节点释放锁,自己就排到前面去了,相当于是一个排队机制。

阿里内部资料而且用临时顺序节点的另外一个用意就是,如果某个客户端创建临时顺序节点之后,不小心自己宕

机了也没关系, Zookeeper 感知到那个客户端宕机,会自动删除对应的临时顺序节点,相当于自动

释放锁,或者是自动取消自己的排队。

本地锁,可以用 JDK 实现,但是分布式锁就必须要用到分布式的组件。比如 ZooKeeper、Redis。

网上代码一大段,面试一般也不要写,我这说一些关键点。

几个需要注意的地方如下。

死锁问题:锁不能因为意外就变成死锁,所以要用 ZK 的临时节点,客户端连接失效了,锁就

自动释放了。

锁等待问题:锁有排队的需求,所以要 ZK 的顺序节点。

锁管理问题:一个使用使用释放了锁,需要通知其他使用者,所以需要用到监听。

监听的羊群效应:比如有 1000 个锁竞争者,锁释放了,1000 个竞争者就得到了通知,然后判

断,最终序号最小的那个拿到了锁。其它 999 个竞争者重新注册监听。这就是羊群效应,出点

事,就会惊动整个羊群。应该每个竞争者只监听自己前面的那个节点。比如 2 号释放了锁,那

么只有 3 号得到了通知。

12、了解Zookeeper的系统架构吗?

ZooKeeper 的架构图中我们需要了解和掌握的主要有:

(1)ZooKeeper分为服务器端(Server)

和客户端(Client),客户端可以连接到整个

ZooKeeper服务的任意服务器上(除非 leaderServes 参数被显式设置, leader 不允许接受客户端

连接)。

(2)客户端使用并维护一个 TCP 连接,通过这个连接发送请求、接受响应、获取观察的事件以及

发送心跳。如果这个 TCP 连接中断,客户端将自动尝试连接到另外的 ZooKeeper服务器。客户端

第一次连接到 ZooKeeper服务时,接受这个连接的 ZooKeeper服务器会为这个客户端建立一个会

话。当这个客户端连接到另外的服务器时,这个会话会被新的服务器重新建立。

(3)上图中每一个Server代表一个安装Zookeeper服务的机器,即是整个提供Zookeeper服务的集

群(或者是由伪集群组成);

(4)组成ZooKeeper服务的服务器必须彼此了解。它们维护一个内存中的状态图像,以及持久存

储中的事务日志和快照,

只要大多数服务器可用,ZooKeeper服务就可用;

阿里内部资料(5)ZooKeeper 启动时,将从实例中选举一个 leader,Leader 负责处理数据更新等操作,一个

更新操作成功的标志是当且仅当大多数Server在内存中成功修改数据。每个Server 在内存中存储了

一份数据。

(6)Zookeeper是可以集群复制的,集群间通过Zab协议(Zookeeper Atomic Broadcast)来保

持数据的一致性;

(7)Zab协议包含两个阶段:leader election阶段和Atomic Brodcast阶段。

a) 集群中将选举出一个leader,其他的机器则称为follower,所有的写操作都被传送给

leader,并通过brodcast将所有的更新告诉给follower。

b) 当leader崩溃或者leader失去大多数的follower时,需要重新选举出一个新的leader,让所

有的服务器都恢复到一个正确的状态。

c) 当leader被选举出来,且大多数服务器完成了 和leader的状态同步后,leadder election 的

过程就结束了,就将会进入到Atomic brodcast的过程。

d) Atomic Brodcast同步leader和follower之间的信息,保证leader和follower具有形同的系统

状态。

13Zookeeper为什么要这么设计?

ZooKeeper设计的目的是提供高性能、高可用、顺序一致性的分布式协调服务、保证数据最终一致

性。

高性能(简单的数据模型)

1. 采用树形结构组织数据节点;

2. 全量数据节点,都存储在内存中;

3. Follower 和 Observer 直接处理非事务请求;

高可用(构建集群)

1. 半数以上机器存活,服务就能正常运行

2. 自动进行 Leader 选举

顺序一致性(事务操作的顺序)

1. 每个事务请求,都会转发给 Leader 处理

2. 每个事务,会分配全局唯一的递增id(zxid,64位:epoch + 自增 id)

最终一致性

1. 通过提议投票方式,保证事务提交的可靠性

2. 提议投票方式,只能保证 Client 收到事务提交成功后,半数以上节点能够看到最新数据

14、你知道Zookeeper中有哪些角色?

阿里内部资料系统模型:

领导者(leader)

Leader服务器为客户端提供读服务和写服务。负责进行投票的发起和决议,更新系统状态。

学习者(learner)

跟随者( follower ) Follower服务器为客户端提供读服务,参与Leader选举过程,参与写操

作“过半写成功”策略。

观察者( observer ) Observer服务器为客户端提供读服务,不参与Leader选举过程,不参与

写操作“过半写成功”策略。用于在不影响写性能的前提下提升集群的读性能。

客户端(client) :服务请求发起方。

15、你熟悉Zookeeper节点ZNode和相关属性吗?

节点有哪些类型?

Znode两种类型 :

持久的(persistent):客户端和服务器端断开连接后,创建的节点不删除(默认)。

短暂的(ephemeral):客户端和服务器端断开连接后,创建的节点自己删除。

Znode有四种形式 :

持久化目录节点(PERSISTENT):客户端与Zookeeper断开连接后,该节点依旧存在持久化顺

序编号目录节点(PERSISTENT_SEQUENTIAL)

客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编

号:临时目录节点(EPHEMERAL)

客户端与Zookeeper断开连接后,该节点被删除:临时顺序编号目录节点

(EPHEMERAL_SEQUENTIAL)

客户端与Zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

「注意」:创建ZNode时设置顺序标识,ZNode名称后会附加一个值,顺序号是一个单调递增的计

数器,由父节点维护。

阿里内部资料节点属性有哪些

一个znode节点不仅可以存储数据,还有一些其他特别的属性。接下来我们创建一个/test节点分析

一下它各个属性的含义。

[zk: localhost:2181(CONNECTED) 6] get /test

456

cZxid = 0x59ac //

ctime = Mon Mar 30 15:20:08 CST 2020

mZxid = 0x59ad

mtime = Mon Mar 30 15:22:25 CST 2020

pZxid = 0x59ac

cversion = 0

dataVersion = 2

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 3

numChildren = 0

属性说明

16、请简述Zookeeper的选主流程

阿里内部资料Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做

Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或

者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和

leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状

态。leader选举是保证分布式数据一致性的关键。

出现选举主要是两种场景:初始化、leader不可用。

当zk集群中的一台服务器出现以下两种情况之一时,就会开始leader选举。

(1)服务器初始化启动。

(2)服务器运行期间无法和leader保持连接。

而当一台机器进入leader选举流程时,当前集群也可能处于以下两种状态。

(1)集群中本来就已经存在一个leader。

(2)集群中确实不存在leader。

首先第一种情况,通常是集群中某一台机器启动比较晚,在它启动之前,集群已经正常工作,即已

经存在一台leader服务器。当该机器试图去选举leader时,会被告知当前服务器的leader信息,它

仅仅需要和leader机器建立连接,并进行状态同步即可。

重点是leader不可用了,此时的选主制度。

投票信息中包含两个最基本的信息。

sid :即server id,用来标识该机器在集群中的机器序号。

zxid :即zookeeper事务id号。

ZooKeeper状态的每一次改变, 都对应着一个递增的Transaction id,,该id称为zxid.,由于zxid的递

增性质, 如果zxid1小于zxid2,,那么zxid1肯定先于zxid2发生。创建任意节点,或者更新任意节点的

数据,

或者删除任意节点,都会导致Zookeeper状态发生改变,从而导致zxid的值增加。

以(sid,zxid)的形式来标识一次投票信息。

例如:如果当前服务器要推举sid为1,zxid为8的服务器成为leader,那么投票信息可以表示为

(1,8)

集群中的每台机器发出自己的投票后,也会接受来自集群中其他机器的投票。每台机器都会根据一

定的规则,来处理收到的其他机器的投票,以此来决定是否需要变更自己的投票。

规则如下 :

(1)初始阶段,都会给自己投票。

(2)当接收到来自其他服务器的投票时,都需要将别人的投票和自己的投票进行pk,规则如下:

阿里内部资料节点

sid

server1

1

server2

2

server3

3

优先检查zxid。zxid比较大的服务器优先作为leader。如果zxid相同的话,就比较sid,sid比较大的

服务器作为leader。

所有服务启动时候的选举流程

三台服务器 server1、server2、server3:

1. server1 启动,一台机器不会选举。

2. server2 启动,server1 和 server2 的状态改为 looking,广播投票

3. server3 启动,状态改为 looking,加入广播投票。

4. 初识状态,互不认识,大家都认为自己是王者,投票也投自己为 Leader。

5. 投票信息说明,票信息本来为五元组,这里为了逻辑清晰,简化下表达。

初识 zxid = 0,sid 是每个节点的名字,这个 sid 在 zoo.cfg 中配置,不会重复。

1. 初始 zxid=0,server1 投票(1,0),server2 投票(2,0),server3 投票(3,0)

2. server1 收到 投票(2,0)时,会先验证投票的合法性,然后自己的票进行 pk,pk 的逻辑是

先比较 zxid,server1(zxid)=server2(zxid)=0,zxid 相等再比较 sid,server1(sid)<

server2(sid),pk 结果为 server2 的投票获胜。server1 更新自己的投票为 (2,0),server1

重新投票。

3. TODO 这里最终是 2 还是 3,需要做实验确定。

4. server2 收到 server1 投票,会先验证投票的合法性,然后 pk,自己的票获胜,server 不用更

新自己的票,pk 后,重新在发送一次投票。

5. 统计投票,pk 后会统计投票,如果半数以上的节点投出相同的票,确定选出了 Leader。

6. 选举结束,被选中节点的状态由 LOOKING 变成 LEADING,其他参加选举的节点由 LOOKING

变成 FOLLOWING。如果有 Observer 节点,如果 Observer 不参与选举,所以选举前后它的

状态一直是 OBSERVING,没有变化。

简单地说

开始投票 -> 节点状态变成 LOOKING -> 每个节点选自己-> 收到票进行 PK -> sid 大的获胜 -> 更新

选票 -> 再次投票 -> 统计选票,选票过半数选举结果 -> 节点状态更新为自己的角色状态。

17、为什么Zookeeper集群的数目,一般为奇数个?

阿里内部资料首先需要明确zookeeper选举的规则:leader选举,要求 可用节点数量 > 总节点数量/2 。

比如:标记一个写是否成功是要在超过一半节点发送写请求成功时才认为有效。同样,Zookeeper

选择领导者节点也是在超过一半节点同意时才有效。最后,Zookeeper是否正常是要根据是否超过

一半的节点正常才算正常。这是基于CAP的一致性原理。

zookeeper有这样一个特性:集群中只要有过半的机器是正常工作的,那么整个集群对外就是可用

的。

也就是说如果有2个zookeeper,那么只要有1个死了zookeeper就不能用了,因为1没有过半,所以

2个zookeeper的死亡容忍度为0;

同理,要是有3个zookeeper,一个死了,还剩下2个正常的,过半了,所以3个zookeeper的容忍度

为1;

同理:

2->0;两个zookeeper,最多0个zookeeper可以不可用。

3->1;三个zookeeper,最多1个zookeeper可以不可用。

4->1;四个zookeeper,最多1个zookeeper可以不可用。

5->2;五个zookeeper,最多2个zookeeper可以不可用。

6->2;两个zookeeper,最多0个zookeeper可以不可用。

....

会发现一个规律,2n和2n-1的容忍度是一样的,都是n-1,所以为了更加高效,何必增加那一个不

必要的zookeeper呢。

zookeeper的选举策略也是需要半数以上的节点同意才能当选leader,如果是偶数节点可能导致票

数相同的情况。

18、知道Zookeeper监听器的原理吗?

1. 创建一个Main()线程。

2. 在Main()线程中创建两个线程,一个负责网络连接通信(connect),一个负责监听

(listener)。

阿里内部资料3. 通过connect线程将注册的监听事件发送给Zookeeper。

4. 将注册的监听事件添加到Zookeeper的注册监听器列表中。

5. Zookeeper监听到有数据或路径发生变化时,把这条消息发送给Listener线程。

6. Listener线程内部调用process()方法

19、说说Zookeeper中的ACL 权限控制机制

UGO(User/Group/Others)

目前在 Linux/Unix 文件系统中使用,也是使用最广泛的权限控制方式。是一种粗粒度的文件系统权

限控制模式。

ACL(Access Control List)访问控制列表

包括三个方面:

权限模式(Scheme)

(1)IP:从 IP 地址粒度进行权限控制

(2)Digest:最常用,用类似于 username:password 的权限标识来进行权限配置,便于区分不同

应用来进行权限控制

(3)World:最开放的权限控制方式,是一种特殊的 digest 模式,只有一个权限标

识“world:anyone”

(4)Super:超级用户

授权对象

授权对象指的是权限赋予的用户或一个指定实体,例如 IP 地址或是机器灯。

权限 Permission

(1)CREATE:数据节点创建权限,允许授权对象在该 Znode 下创建子节点

(2)DELETE:子节点删除权限,允许授权对象删除该数据节点的子节点

(3)READ:数据节点的读取权限,允许授权对象访问该数据节点并读取其数据内容或子节点列表

(4)WRITE:数据节点更新权限,允许授权对象对该数据节点进行更新操作

(5)ADMIN:数据节点管理权限,允许授权对象对该数据节点进行 ACL 相关设置操作

20Zookeeper 有哪几种几种部署模式?

Zookeeper 有三种部署模式:

阿里内部资料1. 单机部署:一台集群上运行;

2. 集群部署:多台集群运行;

3. 伪集群部署:一台集群启动多个 Zookeeper 实例运行。

21Zookeeper集群支持动态添加机器吗?

其实就是水平扩容了,Zookeeper 在这方面不太好。两种方式:

全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。

逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常

用的方式。

3.5 版本开始支持动态扩容。

22、描述一下 ZAB 协议

ZAB 协议是 ZooKeeper 自己定义的协议,全名 ZooKeeper 原子广播协议。

ZAB 协议有两种模式:Leader 节点崩溃了如何恢复和消息如何广播到所有节点。

整个 ZooKeeper 集群没有 Leader 节点的时候,属于崩溃的情况。比如集群启动刚刚启动,这时节

点们互相不认识。比如运作 Leader 节点宕机了,又或者网络问题,其他节点 Ping 不通 Leader 节

点了。这时就需要 ZAB 中的节点崩溃协议,所有节点进入选举模式,选举出新的 Leader。整个选

举过程就是通过广播来实现的。选举成功后,一切都需要以 Leader 的数据为准,那么就需要进行

数据同步了。

23ZAB Paxos 算法的联系与区别?

相同点:

(1)两者都存在一个类似于 Leader 进程的角色,由其负责协调多个 Follower 进程的运行

(2)Leader 进程都会等待超过半数的 Follower 做出正确的反馈后,才会将一个提案进行提交

(3)ZAB 协议中,每个 Proposal 中都包含一个 epoch 值来代表当前的 Leader周期,Paxos 中名

字为 Ballot

不同点:

ZAB 用来构建高可用的分布式数据主备系统(Zookeeper),Paxos 是用来构建分布式一致性状态

机系统。

24ZooKeeper 宕机如何处理?

ZooKeeper 本身也是集群,推荐配置奇数个服务器。因为宕机就需要选举,选举需要半数 +1 票才

能通过,为了避免打成平手。进来不用偶数个服务器。

阿里内部资料如果是 Follower 宕机了,没关系不影响任何使用。用户无感知。如果 Leader 宕机,集群就得停止

对外服务,开始选举,选举出一个 Leader 节点后,进行数据同步,保证所有节点数据和 Leader 统

一,然后开始对外提供服务。

为啥投票需要半数 +1,如果半数就可以的话,网络的问题可能导致集群选举出来两个 Leader,各

有一半的小弟支持,这样数据也就乱套了。

25、 描述一下 ZooKeeper session 管理的思想?

分桶策略:

简单地说,就是不同的会话过期可能都有时间间隔,比如 15 秒过期、15.1 秒过期、15.8 秒过期,

ZooKeeper 统一让这些 session 16 秒过期。这样非常方便管理,看下面的公式,过期时间总是

ExpirationInterval 的整数倍。

计算公式:

ExpirationTime = currentTime + sessionTimeout

ExpirationTime = (ExpirationTime / ExpirationInrerval + 1) * ExpirationInterval ,

见图片:

默认配置的 session 超时时间是在 2tickTime~20tickTime。

26ZooKeeper 负载均衡和 Nginx 负载均衡有什么区别?

ZooKeeper

不存在单点问题,zab 机制保证单点故障可重新选举一个 Leader

只负责服务的注册与发现,不负责转发,减少一次数据交换(消费方与服务方直接通信)

需要自己实现相应的负载均衡算法

阿里内部资料Nginx

存在单点问题,单点负载高数据量大,需要通过 KeepAlived 辅助实现高可用

每次负载,都充当一次中间人转发角色,本身是个反向代理服务器

自带负载均衡算法

27、说说ZooKeeper 的序列化

序列化:

内存数据,保存到硬盘需要序列化。

内存数据,通过网络传输到其他节点,需要序列化。

ZK 使用的序列化协议是 Jute,Jute 提供了 Record 接口。接口提供了两个方法:

serialize 序列化方法

deserialize 反序列化方法

要系列化的方法,在这两个方法中存入到流对象中即可。

28,在ZookeeperZxid 是什么,有什么作用?

Zxid,也就是事务 id,为了保证事务的顺序一致性,ZooKeeper 采用了递增的事务 Zxid 来标识事

务。proposal 都会加上了 Zxid。Zxid 是一个 64 位的数字,它高 32 位是 Epoch 用来标识朝代变

化,比如每次选举 Epoch 都会加改变。低 32 位用于递增计数。

Epoch:可以理解为当前集群所处的年代或者周期,每个 Leader 就像皇帝,都有自己的年号,所

以每次改朝换代,Leader 变更之后,都会在前一个年代的基础上加 1。这样就算旧的 Leader 崩溃

恢复之后,也没有人听它的了,因为 Follower 只听从当前年代的 Leader 的命令。欢迎关注微信公

众号:Java后端技术全栈

29、讲解一下 ZooKeeper 的持久化机制

什么是持久化?

数据,存到磁盘或者文件当中。

机器重启后,数据不会丢失。内存 -> 磁盘的映射,和序列化有些像。

ZooKeeper 的持久化:

SnapShot 快照,记录内存中的全量数据

TxnLog 增量事务日志,记录每一条增删改记录(查不是事务日志,不会引起数据变化)

为什么持久化这么麻烦,一个不可用吗?

快照的缺点,文件太大,而且快照文件不会是最新的数据。 增量事务日志的缺点,运行时间长了,

日志太多了,加载太慢。二者结合最好。

阿里内部资料快照模式:

将 ZooKeeper 内存中以 DataTree 数据结构存储的数据定期存储到磁盘中。

由于快照文件是定期对数据的全量备份,所以快照文件中数据通常不是最新的。

见图片:

30Zookeeper选举中投票信息的五元组是什么?

Leader:被选举的 Leader 的 SID

Zxid:被选举的 Leader 的事务 ID

Sid:当前服务器的 SID

electionEpoch:当前投票的轮次

peerEpoch:当前服务器的 Epoch

Epoch > Zxid > Sid

Epoch,Zxid 都可能一致,但是 Sid 一定不一样,这样两张选票一定会 PK 出结果。

31、说说Zookeeper中的脑裂?

简单点来说,脑裂(Split-Brain) 就是比如当你的 cluster 里面有两个节点,它们都知道在这个

cluster 里需要选举出一个 master。那么当它们两个之间的通信完全没有问题的时候,就会达成共

识,选出其中一个作为 master。但是如果它们之间的通信出了问题,那么两个结点都会觉得现在没

有 master,所以每个都把自己选举成 master,于是 cluster 里面就会有两个 master。

阿里内部资料对于Zookeeper来说有一个很重要的问题,就是到底是根据一个什么样的情况来判断一个节点死亡

down掉了?在分布式系统中这些都是有监控者来判断的,但是监控者也很难判定其他的节点的状

态,唯一一个可靠的途径就是心跳,Zookeeper也是使用心跳来判断客户端是否仍然活着。

使用ZooKeeper来做Leader HA基本都是同样的方式:每个节点都尝试注册一个象征leader的临时

节点,其他没有注册成功的则成为follower,并且通过watch机制监控着leader所创建的临时节点,

Zookeeper通过内部心跳机制来确定leader的状态,一旦leader出现意外Zookeeper能很快获悉并

且通知其他的follower,其他flflower在之后作出相关反应,这样就完成了一个切换,这种模式也是

比较通用的模式,基本大部分都是这样实现的。但是这里面有个很严重的问题,如果注意不到会导

致短暂的时间内系统出现脑裂,因为心跳出现超时可能是leader挂了,但是也可能是zookeeper节

点之间网络出现了问题,导致leader假死的情况,leader其实并未死掉,但是与ZooKeeper之间的

网络出现问题导致Zookeeper认为其挂掉了然后通知其他节点进行切换,这样follower中就有一个

成为了leader,但是原本的leader并未死掉,这时候client也获得leader切换的消息,但是仍然会有

一些延时,zookeeper需要通讯需要一个一个通知,这时候整个系统就很混乱可能有一部分client已

经通知到了连接到新的leader上去了,有的client仍然连接在老的leader上,如果同时有两个client

需要对leader的同一个数据更新,并且刚好这两个client此刻分别连接在新老的leader上,就会出现

很严重问题。

这里做下小总结:

假死:由于心跳超时(网络原因导致的)认为leader死了,但其实leader还存活

着。 脑裂:由于假死会发起新的leader选举,选举出一个新的leader,但旧的leader网络又通了,

导致出现了两个leader ,有的客户端连接到老的leader,而有的客户端则连接到新的leader。

32Zookeeper脑裂是什么原因导致的?

主要原因是Zookeeper集群和Zookeeper client判断超时并不能做到完全同步,也就是说可能一前

一后,如果是集群先于client发现,那就会出现上面的情况。同时,在发现并切换后通知各个客户端

也有先后快慢。一般出现这种情况的几率很小,需要leader节点与Zookeeper集群网络断开,但是

与其他集群角色之间的网络没有问题,还要满足上面那些情况,但是一旦出现就会引起很严重的后

果,数据不一致。

33Zookeeper 是如何解决脑裂问题的?

要解决Split-Brain脑裂的问题,一般有下面几种种方法: Quorums (法定人数) 方式: 比如3个节点

的集群,Quorums = 2, 也就是说集群可以容忍1个节点失效,这时候还能选举出1个lead,集群还

可用。比如4个节点的集群,它的Quorums = 3,Quorums要超过3,相当于集群的容忍度还是1,

如果2个节点失效,那么整个集群还是无效的。这是zookeeper防止"脑裂"默认采用的方法。

采用Redundant communications (冗余通信)方式:集群中采用多种通信方式,防止一种通信方式

失效导致集群中的节点无法通信。

Fencing (共享资源) 方式:比如能看到共享资源就表示在集群中,能够获得共享资源的锁的就是

Leader,看不到共享资源的,就不在集群中。

阿里内部资料要想避免zookeeper"脑裂"情况其实也很简单,在follower节点切换的时候不在检查到老的leader节

点出现问题后马上切换,而是在休眠一段足够的时间,确保老的leader已经获知变更并且做了相关

的shutdown清理工作了然后再注册成为master就能避免这类问题了,这个休眠时间一般定义为与

zookeeper定义的超时时间就够了,但是这段时间内系统可能是不可用的,但是相对于数据不一致

的后果来说还是值得的。

1、zooKeeper默认采用了Quorums这种方式来防止"脑裂"现象。即只有集群中超过半数节点投票

才能选举出Leader。这样的方式可以确保leader的唯一性,要么选出唯一的一个leader,要么选举失

败。在zookeeper中Quorums作用如下:

集群中最少的节点数用来选举leader保证集群可用。

通知客户端数据已经安全保存前集群中最少数量的节点数已经保存了该数据。一旦这些节点保

存了该数据,客户端将被通知已经安全保存了,可以继续其他任务。而集群中剩余的节点将会

最终也保存了该数据。

假设某个leader假死,其余的followers选举出了一个新的leader。这时,旧的leader复活并且仍然

认为自己是leader,这个时候它向其他followers发出写请求也是会被拒绝的。因为每当新leader产

生时,会生成一个epoch标号(标识当前属于那个leader的统治时期),这个epoch是递增的,

followers如果确认了新的leader存在,知道其epoch,就会拒绝epoch小于现任leader epoch的所

有请求。那有没有follower不知道新的leader存在呢,有可能,但肯定不是大多数,否则新leader

无法产生。Zookeeper的写也遵循quorum机制,因此,得不到大多数支持的写是无效的,旧

leader即使各种认为自己是leader,依然没有什么作用。

zookeeper除了可以采用上面默认的Quorums方式来避免出现"脑裂",还可以可采用下面的预防措

施: 2、添加冗余的心跳线,例如双线条线,尽量减少“裂脑”发生机会。 3、启用磁盘锁。正在服务

一方锁住共享磁盘,"裂脑"发生时,让对方完全"抢不走"共享磁盘资源。但使用锁磁盘也会有一个

不小的问题,如果占用共享盘的一方不主动"解锁",另一方就永远得不到共享磁盘。现实中假如服

务节点突然死机或崩溃,就不可能执行解锁命令。后备节点也就接管不了共享资源和应用服务。于

是有人在HA中设计了"智能"锁。即正在服务的一方只在发现心跳线全部断开(察觉不到对端)时才

启用磁盘锁。平时就不上锁了。 4、设置仲裁机制。例如设置参考IP(如网关IP),当心跳线完全

断开时,2个节点都各自ping一下 参考IP,不通则表明断点就出在本端,不仅"心跳"、还兼对外"服

务"的本端网络链路断了,即使启动(或继续)应用服务也没有用了,那就主动放弃竞争,让能够

ping通参考IP的一端去起服务。更保险一些,ping不通参考IP的一方干脆就自我重启,以彻底释放

有可能还占用着的那些共享资源。

34、说说 Zookeeper CAP 问题上做的取舍?

一致性 CZookeeper 是强一致性系统,为了保证较强的可用性,

“一半以上成功即成功”的数据同

步方式可能会导致部分节点的数据不一致。所以 Zookeeper 还提供了 sync() 操作来做所有节点的

数据同步,这就关于 C 和 A 的选择问题交给了用户,因为使用 sync()势必会延长同步时间,可用性

会有一些损失。

阿里内部资料可用性 AZookeeper 数据存储在内存中,且各个节点都可以相应读请求,具有好的响应性能。

Zookeeper 保证了数据总是可用的,没有锁。并且有一大半的节点所拥有的数据是最新的。

分区容忍性 PFollower 节点过多会导致增大数据同步的延时(需要半数以上 follower 写完提

交)。同时选举过程的收敛速度会变慢,可用性降低。Zookeeper 通过引入 observer 节点缓解了

这个问题,增加 observer 节点后集群可接受 client 请求的节点多了,而且 observer 不参与投票,

可以提高可用性和扩展性,但是节点多数据同步总归是个问题,所以一致性会有所降低。

35watch 监听为什么是一次性的?

如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,给网络和

服务器造成很大压力。

一般是客户端执行 getData(节点 A,true) ,如果节点 A 发生了变更或删除,客户端会得到它的

watch 事件,但是在之后节点 A 又发生了变更,而客户端又没有设置 watch 事件,就不再给客户端

发送。

在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即

可。

Redis

1,为什么要用缓存

使用缓存的目的就是提升读写性能。而实际业务场景下,更多的是为了提升读性能,带来更好的性

能,带来更高的并发量。 Redis 的读写性能比 Mysql 好的多,我们就可以把 Mysql 中的热点数据缓

存到 Redis 中,提升读取性能,同时也减轻了 Mysql 的读取压力。

欢迎关注微信公众号:Java后端技术全栈

2,使用 Redis 有哪些好处?

具有以下好处:

读取速度快,因为数据存在内存中,所以数据获取快;

支持多种数据结构,包括字符串、列表、集合、有序集合、哈希等;

支持事务,且操作遵守原子性,即对数据的操作要么都执行,要么都不支持;

还拥有其他丰富的功能,队列、主从复制、集群、数据持久化等功能。

3

什么是 Redis

阿里内部资料Redis 是一个开源(BSD 许可)、基于内存、支持多种数据结构的存储系统,可以作为数据库、缓

存和消息中间件。它支持的数据结构有字符串(strings)、哈希(hashes)、列表(lists)、集合

(sets)、有序集合(sorted sets)等,除此之外还支持 bitmaps、hyperloglogs 和地理空间(

geospatial )索引半径查询等功能。

它内置了复制(Replication)、LUA 脚本(Lua scripting)、LRU 驱动事件(LRU eviction)、事

务(Transactions)和不同级别的磁盘持久化(persistence)功能,并通过 Redis 哨兵(哨兵)和

集群(Cluster)保证缓存的高可用性(High availability)。

4,为什么 使用 Redis 而不是用 Memcache 呢?

这时候肯定想到的就是做一个 Memcache 与 Redis 区别。

Redis 和 Memcache 都是将数据存放在内存中,都是内存数据库。不过 Memcache 还可用于缓存

其他东西,例如图片、视频等等。

Memcache 仅支持key-value结构的数据类型,Redis不仅仅支持简单的key-value类型的数据,

同时还提供list,set,hash等数据结构的存储。

虚拟内存– Redis 当物理内存用完时,可以将一些很久没用到的value 交换到磁盘

分布式–设定 Memcache 集群,利用 magent 做一主多从; Redis 可以做一主多从。都可以一主一

存储数据安全– Memcache 挂掉后,数据没了; Redis 可以定期保存到磁盘(持久化)

Memcache 的单个value最大 1m , Redis 的单个value最大 512m 。

灾难恢复– Memcache 挂掉后,数据不可恢复; Redis 数据丢失后可以通过 aof 恢复

Redis 原生就支持集群模式, Redis3.0 版本中,官方便能支持Cluster模式了, Memcached 没

有原生的集群模式,需要依赖客户端来实现,然后往集群中分片写入数据。

Memcached 网络IO模型是多线程,非阻塞IO复用的网络模型,原型上接近于 nignx 。而 Redis

使用单线程的IO复用模型,自己封装了一个简单的 AeEvent 事件处理框架,主要实现类

epoll,kqueue 和 select ,更接近于Apache早期的模式。

5,为什么 Redis 单线程模型效率也能那么高?

1. C语言实现,效率高

2. 纯内存操作

3. 基于非阻塞的IO复用模型机制

4. 单线程的话就能避免多线程的频繁上下文切换问题

5. 丰富的数据结构(全称采用hash结构,读取速度非常快,对数据存储进行了一些优化,比如亚

索表,跳表等)

6,说说 Redis 的线程模型

阿里内部资料这问题是因为前面回答问题的时候提到了 Redis 是基于非阻塞的IO复用模型。如果这个问题回

答不上来,就相当于前面的回答是给自己挖坑,因为你答不上来,面试官对你的印象可能就要

打点折扣了。

Redis 内部使用文件事件处理器 file event handler ,这个文件事件处理器是单线程的,所以

Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 socket ,根据 socket 上的事

件来选择对应的事件处理器进行处理。

文件事件处理器的结构包含 4 个部分:

1. 多个 socket 。

2. IO 多路复用程序。

3. 文件事件分派器。

4. 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)。

多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会

监听多个 socket,会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事

件,把该事件交给对应的事件处理器进行处理。

来看客户端与 Redis 的一次通信过程:

下面来大致说一下这个图:

1. 客户端 Socket01 向 Redis 的 Server Socket 请求建立连接,此时 Server Socket 会产生一个

AE_READABLE 事件,IO 多路复用程序监听到 server socket 产生的事件后,将该事件压入队列

中。文件事件分派器从队列中获取该事件,交给连接应答处理器。连接应答处理器会创建一个

能与客户端通信的 Socket01,并将该 Socket01 的 AE_READABLE 事件与命令请求处理器关

联。

2. 假设此时客户端发送了一个 set key value 请求,此时 Redis 中的 Socket01 会产生

AE_READABLE 事件,IO 多路复用程序将事件压入队列,此时事件分派器从队列中获取到该事

件,由于前面 Socket01 的 AE_READABLE 事件已经与命令请求处理器关联,因此事件分派器

将事件交给命令请求处理器来处理。命令请求处理器读取 Socket01 的 set key value 并在自己

内存中完成 set key value 的设置。操作完成后,它会将 Socket01 的 AE_WRITABLE 事件与令

回复处理器关联。

3. 如果此时客户端准备好接收返回结果了,那么 Redis 中的 Socket01 会产生一个

AE_WRITABLE 事件,同样压入队列中,事件分派器找到相关联的命令回复处理器,由命令回复

阿里内部资料处理器对 Socket01 输入本次操作的一个结果,比如 ok ,之后解除 Socket01 的

AE_WRITABLE 事件与命令回复处理器的关联。

这样便完成了一次通信。 不要怕这段文字,结合图看,一遍不行两遍,实在不行可以网上查点资料

结合着看,一定要搞清楚,否则前面吹的牛逼就白费了。

7,为什么 Redis 需要把所有数据放到内存中?

Redis 将数据放在内存中有一个好处,那就是可以实现最快的对数据读取,如果数据存储在硬盘

中,磁盘 I/O 会严重影响 Redis 的性能。而且 Redis 还提供了数据持久化功能,不用担心服务器重

启对内存中数据的影响。其次现在硬件越来越便宜的情况下,Redis 的使用也被应用得越来越多,

使得它拥有很大的优势。

8Redis 的同步机制了解是什么?

Redis 支持主从同步、从从同步。如果是第一次进行主从同步,主节点需要使用 bgsave 命令,再将

后续修改操作记录到内存的缓冲区,等 RDB 文件全部同步到复制节点,复制节点接受完成后将

RDB 镜像记载到内存中。等加载完成后,复制节点通知主节点将复制期间修改的操作记录同步到复

制节点,即可完成同步过程。

9 pipeline 有什么好处,为什么要用 pipeline

使用 pipeline(管道)的好处在于可以将多次 I/O 往返的时间缩短为一次,但是要求管道中执行的

指令间没有因果关系。

用 pipeline 的原因在于可以实现请求/响应服务器的功能,当客户端尚未读取旧响应时,它也可以

处理新的请求。如果客户端存在多个命令发送到服务器时,那么客户端无需等待服务端的每次响应

才能执行下个命令,只需最后一步从服务端读取回复即可。

10,说一下 Redis 有什么优点和缺点

优点

速度快:因为数据存在内存中,类似于 HashMap , HashMap 的优势就是查找和操作的时间复杂

度都是O (1) 。

支持丰富的数据结构:支持 String ,List,Set,Sorted Set,Hash 五种基础的数据结构。

持久化存储:Redis 提供 RDB 和 AOF 两种数据的持久化存储方案,解决内存数据库最担心的

万一 Redis 挂掉,数据会消失掉

高可用:内置 Redis Sentinel ,提供高可用方案,实现主从故障自动转移。 内置 Redis

Cluster ,提供集群方案,实现基于槽的分片方案,从而支持更大的 Redis 规模。

丰富的特性:Key过期、计数、分布式锁、消息队列等。

缺点

阿里内部资料由于 Redis 是内存数据库,所以,单台机器,存储的数据量,跟机器本身的内存大小。虽然

Redis 本身有 Key 过期策略,但是还是需要提前预估和节约内存。如果内存增长过快,需要定

期删除数据。

如果进行完整重同步,由于需要生成 RDB 文件,并进行传输,会占用主机的 CPU ,并会消耗

现网的带宽。不过 Redis 2.8 版本,已经有部分重同步的功能,但是还是有可能有完整重同步

的。比如,新上线的备机。

修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程中, Redis

不能提供服务。

11 Redis 缓存刷新策略有哪些?

12 Redis 持久化方式有哪些?以及有什么区别?

Redis 提供两种持久化机制 RDB 和 AOF 机制:

RDB 持久化方式

是指用数据集快照的方式半持久化模式)记录 redis 数据库的所有键值对,在某个时间点将数据写入

一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。

优点:

只有一个文件 dump.rdb ,方便持久化。

容灾性好,一个文件可以保存到安全的磁盘。

性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单

独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis 的高性能)

相对于数据集大时,比 AOF 的启动效率更高。

缺点:

数据安全性低。 RDB 是间隔一段时间进行持久化,如果持久化之间 Redis 发生故障,会发生数据

丢失。所以这种方式更适合数据要求不严谨的时候

AOF=Append-only file 持久化方式

阿里内部资料是指所有的命令行记录以 Redis 命令请求协议的格式完全持久化存储,保存为 AOF 文件。

优点:

(1)数据安全, AOF 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录

到 AOF 文件中一次。

(2)通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据

一致性问题。

(3) AOF 机制的 rewrite 模式。 AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重

写),可以删除其中的某些命令(比如误操作的 flushall )

缺点:

(1) AOF 文件比 RDB 文件大,且恢复速度慢。

(2)数据集大的时候,比 RDB 启动效率低。

13,持久化有两种,那应该怎么选择呢?

1. 不要仅仅使用 RDB ,因为那样会导致你丢失很多数据。

2. 也不要仅仅使用 AOF ,因为那样有两个问题,第一,你通过 AOF 做冷备没有 RDB 做冷备的恢

复速度更快; 第二, RDB 每次简单粗暴生成数据快照,更加健壮,可以避免 AOF 这种复杂的备

份和恢复机制的 bug 。

3. Redis 支持同时开启开启两种持久化方式,我们可以综合使用 AOF 和 RDB 两种持久化机制,

用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不同程度的冷备,在 AOF

文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。

4. 如果同时使用 RDB 和 AOF 两种持久化机制,那么在 Redis 重启的时候,会使用 AOF 来重新

构建数据,因为 AOF 中的数据更加完整。

14,怎么使用 Redis 实现消息队列?

一般使用 list 结构作为队列, rpush 生产消息, lpop 消费消息。当 lpop 没有消息的时候,要适当

sleep 一会再重试。

面试官可能会问可不可以不用 sleep 呢?list 还有个指令叫 blpop ,在没有消息的时候,它会

阻塞住直到消息到来。

面试官可能还问能不能生产一次消费多次呢?使用 pub / sub 主题订阅者模式,可以实现 1:N

的消息队列。

面试官可能还问 pub / sub 有什么缺点?在消费者下线的情况下,生产的消息会丢失,得使用

专业的消息队列如 rabbitmq 等。

阿里内部资料面试官可能还问 Redis 如何实现延时队列?我估计现在你很想把面试官一棒打死如果你手上有

一根棒球棍的话,怎么问的这么详细。但是你很克制,然后神态自若的回答道:使用

sortedset ,拿时间戳作为 score ,消息内容作为 key 调用 zadd 来生产消息,消费者用

zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。

面试扩散:很多面试官上来就直接这么问:

Redis 如何实现延时队列

15,说说你对Redis事务的理解

什么是 Redis 事务?原理是什么?

Redis 中的事务是一组命令的集合,是 Redis 的最小执行单位。它可以保证一次执行多个命令,每

个事务是一个单独的隔离操作,事务中的所有命令都会序列化、按顺序地执行。服务端在执行事务

的过程中,不会被其他客户端发送来的命令请求打断。

它的原理是先将属于一个事务的命令发送给 Redis,然后依次执行这些命令。

Redis 事务的注意点有哪些?

需要注意的点有:

Redis 事务是不支持回滚的,不像 MySQL 的事务一样,要么都执行要么都不执行;

Redis 服务端在执行事务的过程中,不会被其他客户端发送来的命令请求打断。直到事务命令

全部执行完毕才会执行其他客户端的命令。

Redis 事务为什么不支持回滚?

Redis 的事务不支持回滚,但是执行的命令有语法错误,Redis 会执行失败,这些问题可以从程序层

面捕获并解决。但是如果出现其他问题,则依然会继续执行余下的命令。这样做的原因是因为回滚

需要增加很多工作,而不支持回滚则可以保持简单、快速的特性。

16Redis 为什么设计成单线程的?

多线程处理会涉及到锁,并且多线程处理会涉及到线程切···换而消耗 CPU。采用单线程,避免了不

必要的上下文切换和竞争条件。其次 CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存或

者网络带宽。

17,什么是 bigkey?会存在什么影响?

bigkey 是指键值占用内存空间非常大的 key。例如一个字符串 a 存储了 200M 的数据。

bigkey 的主要影响有:

网络阻塞;获取 bigkey 时,传输的数据量比较大,会增加带宽的压力。

超时阻塞;因为 bigkey 占用的空间比较大,所以操作起来效率会比较低,导致出现阻塞的可能

性增加。

阿里内部资料导致内存空间不平衡;一个 bigkey 存储数据量比较大,同一个 key 在同一个节点或服务器中存

储,会造成一定影响。

18,熟悉哪些 Redis 集群模式?

1. Redis Sentinel

体量较小时,选择 Redis Sentinel ,单主 Redis 足以支撑业务。

2. Redis Cluster

Redis 官方提供的集群化方案,体量较大时,选择 Redis Cluster ,通过分片,使用更多内

存。

3. Twemprox

Twemprox 是 Twtter 开源的一个 Redis 和 Memcached 代理服务器,主要用于管理 Redis 和

Memcached 集群,减少与Cache 服务器直接连接的数量。

4. Codis

Codis 是一个代理中间件,当客户端向 Codis 发送指令时, Codis 负责将指令转发到后面的

Redis 来执行,并将结果返回给客户端。一个 Codis 实例可以连接多个 Redis 实例,也可以启

动多个 Codis 实例来支撑,每个 Codis 节点都是对等的,这样可以增加整体的 QPS 需求,还能

起到容灾功能。

5. 客户端分片

在 Redis Cluster 还没出现之前使用较多,现在基本很少热你使用了,在业务代码层实现,起

几个毫无关联的 Redis 实例,在代码层,对 Key 进行 hash 计算,然后去对应的 Redis 实例操

作数据。这种方式对 hash 层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,

数据震荡后的自动脚本恢复,实例的监控,等等。

19,是否使用过 Redis Cluster 集群,集群的原理是什么?

使用过 Redis 集群,它的原理是:

所有的节点相互连接

集群消息通信通过集群总线通信,集群总线端口大小为客户端服务端口 + 10000(固定值)

节点与节点之间通过二进制协议进行通信

客户端和集群节点之间通信和通常一样,通过文本协议进行

集群节点不会代理查询

数据按照 Slot 存储分布在多个 Redis 实例上

集群节点挂掉会自动故障转移

可以相对平滑扩/缩容节点

阿里内部资料Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对

key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号

在 0~16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。

20 Redis Cluster 集群方案什么情况下会导致整个集群不可

用?

Redis 没有使用哈希一致性算法,而是使用哈希槽。Redis 中的哈希槽一共有 16384 个,计算给定

密钥的哈希槽,我们只需要对密钥的 CRC16 取摸 16384。假设集群中有 A、B、C 三个集群节点,

不存在复制模式下,每个集群的节点包含的哈希槽如下:

节点 A 包含从 0 到 5500 的哈希槽;

节点 B 包含从 5501 到 11000 的哈希槽;

节点 C 包含从 11001 到 16383 的哈希槽;

这时,如果节点 B 出现故障,整个集群就会出现缺少 5501 到 11000 的哈希槽范围而不可用。

21Redis 集群架构模式有哪几种?

Redis 集群架构是支持单节点单机模式的,也支持一主多从的主从结构,还支持带有哨兵的集群部

署模式。

22,说说 Redis 哈希槽的概念?

Redis 集群并没有使用一致性 hash,而是引入了哈希槽的概念。Redis 集群有 16384(2^14)个哈

希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分

hash 槽。

23Redis 常见性能问题和解决方案有哪些?

Redis 常见性能问题和解决方案如下:

Master 最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件;

如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次;

为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网内;

尽量避免在压力很大的主库上增加从库;

主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <-

Slave3….;这样的结构方便解决单点故障问题,实现 Slave 对 Master 的替换。如果 Master 挂

了,可以立刻启用 Slave1 做 Master,其他不变。

24,假如 Redis 里面有 1 亿个 key,其中有 10w key 是以某

个固定的已知的前缀开头的,如果将它们全部找出来?

阿里内部资料我们可以使用 keys 命令和 scan 命令,但是会发现使用 scan 更好。

1. 使用 keys 命令

直接使用 keys 命令查询,但是如果是在生产环境下使用会出现一个问题,keys 命令是遍历查询

的,查询的时间复杂度为 O(n),数据量越大查询时间越长。而且 Redis 是单线程,keys 指令会导

致线程阻塞一段时间,会导致线上 Redis 停顿一段时间,直到 keys 执行完毕才能恢复。这在生产

环境是不允许的。除此之外,需要注意的是,这个命令没有分页功能,会一次性查询出所有符合条

件的 key 值,会发现查询结果非常大,输出的信息非常多。所以不推荐使用这个命令。

2. 使用 scan 命令

scan 命令可以实现和 keys 一样的匹配功能,但是 scan 命令在执行的过程不会阻塞线程,并且查

找的数据可能存在重复,需要客户端操作去重。因为 scan 是通过游标方式查询的,所以不会导致

Redis 出现假死的问题。Redis 查询过程中会把游标返回给客户端,单次返回空值且游标不为 0,则

说明遍历还没结束,客户端继续遍历查询。scan 在检索的过程中,被删除的元素是不会被查询出来

的,但是如果在迭代过程中有元素被修改,scan 不能保证查询出对应元素。相对来说,scan 指令

查找花费的时间会比 keys 指令长。

25,如果有大量的 key 需要设置同一时间过期,一般需要注意什

么?

如果有大量的 key 在同一时间过期,那么可能同一秒都从数据库获取数据,给数据库造成很大的压

力,导致数据库崩溃,系统出现 502 问题。也有可能同时失效,那一刻不用都访问数据库,压力不

够大的话,那么 Redis 会出现短暂的卡顿问题。所以为了预防这种问题的发生,最好给数据的过期

时间加一个随机值,让过期时间更加分散。

26,什么情况下可能会导致 Redis 阻塞?

Redis 产生阻塞的原因主要有内部和外部两个原因导致:

内部原因

如果 Redis 主机的 CPU 负载过高,也会导致系统崩溃;

数据持久化占用资源过多;

对 Redis 的 API 或指令使用不合理,导致 Redis 出现问题。

外部原因

外部原因主要是服务器的原因,例如服务器的 CPU 线程在切换过程中竞争过大,内存出现问题、网

络问题等。

27,缓存和数据库谁先更新呢?

解决方案

阿里内部资料1. 写请求过来,将写请求缓存到缓存队列中,并且开始执行写请求的具体操作(删除缓存中的数

据,更新数据库,更新缓存)。

2. 如果在更新数据库过程中,又来了个读请求,将读请求再次存入到缓存队列(可以搞n个队

列,采用key的hash值进行队列个数取模hash%n,落到对应的队列中,队列需要保证顺序性)

中,顺序性保证等待队列前的写请求执行完成,才会执行读请求之前的写请求删除缓存失败,

直接返回,此时数据库中的数据是旧值,并且与缓存中的数据是一致的,不会出现缓存一致性

的问题。

3. 写请求删除缓存成功,则更新数据库,如果更新数据库失败,则直接返回,写请求结束,此时

数据库中的值依旧是旧值,读请求过来后,发现缓存中没有数据,

则会直接向数据库中请求,

同时将数据写入到缓存中,此时也不会出现数据一致性的问题。

4. 更新数据成功之后,再更新缓存,如果此时更新缓存失败,则缓存中没有数据,数据库中是新

值 ,写请求结束,此时读请求还是一样,发现缓存中没有数据,同样会从数据库中读取数据,

并且存入到缓存中,其实这里不管更新缓存成功还是失败,

都不会出现数据一致性的问题。

上面这方案解决了数据不一致的问题,主要是使用了串行化,每次操作进来必须按照顺序进行。如

果某个队列元素积压太多,可以针对读请求进行过滤,提示用户刷新页面,重新请求。

潜在的问题,留给大家自己去想吧,因为这个问题属于发散性。

1,请求时间过长,大量的写请求堆压在队列中,一个读请求来得等都写完了才可以获取到数据。

2,读请求并发高

3,热点数据路由问题,导致请求倾斜。

28,怎么提高缓存命中率?

主要常用的手段有:

提前加载数据到缓存中;

增加缓存的存储空间,提高缓存的数据;

调整缓存的存储数据类型;

提升缓存的更新频率。

29Redis 如何解决 key 冲突?

Redis 如果 key 相同,后一个 key 会覆盖前一个 key。如果要解决 key 冲突,最好给 key 取好名区

分开,可以按业务名和参数区分开取名,避免重复 key 导致的冲突。

30Redis 报内存不足怎么处理?

Redis 内存不足可以这样处理:

修改配置文件 redis.conf 的 maxmemory 参数,增加 Redis 可用内存;

设置缓存淘汰策略,提高内存的使用效率;

阿里内部资料使用 Redis 集群模式,提高存储量。

31、说说Redis持久化机制

Redis是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到硬盘文件来保证数据

持久化。当Redis重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目的。 实现:单独

创建fork()一个子进程,将当前父进程的数据库数据复制到子进程的内存中,然后由子进程写入到临

时文件中,持久化的过程结束了,再用这个临时文件替换上次的快照文件,然后子进程退出,内存

释放。

RDB是Redis默认的持久化方式。按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的

二进制文件。即Snapshot快照存储,对应产生的数据文件为dump.rdb,通过配置文件中的save参

数来定义快照的周期。(

快照可以是其所表示的数据的一个副本,也可以是数据的一个复制品。)

AOF:Redis会将每一个收到的写命令都通过Write函数追加到文件最后,类似于MySQL的binlog。

当Redis重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。 当两种方

式同时开启时,数据恢复Redis会优先选择AOF恢复。

32、缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问

一、缓存雪崩

我们可以简单的理解为:由于原有缓存失效,新缓存未到期间 (例如:我们设置缓存时采用了相同的

过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,

而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成

整个系统崩溃。 解决办法:

大多数系统设计者考虑用加锁(

最多的解决方案)或者队列的方式保

证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存

储系统上。还有一个简单方案就时讲缓存失效时间分散开。

二、缓存穿透 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用

户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次

无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。 解决办法;

最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不

存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。 另外也有一个更为

简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然

把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值

存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。

5TB的硬盘上放满了数据,请写一个算法将这些数据进行排重。如果这些数据是一些32bit大小的数

据该如何解决?如果是64bit的呢?

阿里内部资料对于空间的利用到达了一种极致,那就是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、数据量不大,可以在项目启动的时候

自动进行加载; 3、定时刷新缓存;

四、缓存更新 除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们

还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:

(1)定时去清理过期的

缓存;

(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系

统得到新数据并更新缓存。 两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第

二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家

可以根据自己的应用场景来权衡。

五、缓存降级 当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流

程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自

动降级,也可以配置开关实现人工降级。 降级的最终目的是保证核心服务可用,即使是有损的。而

且有些服务是无法降级的(如加入购物车、结算)。 以参考日志级别设置预案:

(1)一般:比如

有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;

(2)警告:有些服务在一

段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;

(3)错

误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大

阀值,此时可以根据情况自动降级或者人工降级;

(4)严重错误:比如因为特殊原因数据错误

了,此时需要紧急人工降级。

服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重

要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据

库查询,而是直接返回默认值给用户。

33、热点数据和冷数据是什么

阿里内部资料热点数据,缓存才有价值 对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,

不仅占用内存,而且价值不大。频繁修改的数据,看情况考虑使用缓存 对于上面两个例子,寿星列

表、导航信息都存在一个特点,就是信息修改频率不高,读取通常非常高的场景。 对于热点数据,

比如我们的某IM产品,生日祝福模块,当天的寿星列表,缓存以后可能读取数十万次。再举个例

子,某导航产品,我们将导航信息,缓存以后可能读取数百万次。 数据更新前至少读取两次,缓存

才有意义。这个是最基本的策略,如果缓存还没有起作用就失效了,那就没有太大价值了。 那存不

存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个读取接口对数据库的压力

很大,但是又是热点数据,这个时候就需要考虑通过缓存手段,减少数据库的压力,比如我们的某

助手产品的,点赞数,收藏数,分享数等是非常典型的热点数据,但是又不断变化,此时就需要将

数据同步保存到Redis缓存,减少数据库压力。

34MemcacheRedis的区别都有哪些?

1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。

Redis有部份存在硬盘上,redis可以持久化其数据 2)、数据支持类型 memcached所有的值均是简

单的字符串,redis作为其替代者,支持更为丰富的数据类型 ,提供list,set,zset,hash等数据结

构的存储 3)、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一

样。 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移

动和请求。 4). value 值大小不同:Redis 最大可以达到 1gb;memcache 只有 1mb。 5)redis的

速度比memcached快很多 6)Redis支持数据的备份,即master-slave模式的数据备份。

35、单线程的redis为什么这么快

(一)纯内存操作 (二)单线程操作,避免了频繁的上下文切换 (三)采用了非阻塞I/O多路复用机制

36redis的数据类型,以及每种数据类型的使用场景

回答:一共五种 (一)String 这个其实没啥好说的,最常规的set/get操作,value可以是String也可以

是数字。一般做一些复杂的计数功能的缓存。 (二)hash 这里value存放的是结构化的对象,比较方

便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以

cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。 (三)list 使用

List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于

redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适—取行情信息。就也是个生

产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。 (四)set 因为set堆放的是一堆

不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系

统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公

共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,

自己独有的喜好等功能。 (五)sorted set sorted set多了一个权重参数score,集合中的元素能够按

score进行排列。可以做排行榜应用,取TOP N操作。

37redis的过期策略以及内存淘汰机制

阿里内部资料redis采用的是定期删除+惰性删除策略。 为什么不用定时删除策略? 定时删除,用一个定时器来负责

监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要

将时间应用在处理请求,而不是删除key,因此没有采用这一策略. 定期删除+惰性删除是如何工作的

? 定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,

redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行

检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于

是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了

过期时间那么是否过期了?如果过期了此时就会删除。 采用定期删除+惰性删除就没其他问题了么?

不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这

样,redis的内存会越来越高。那么就应该采用内存淘汰机制。 在redis.conf中有一行配置

maxmemory-policy volatile-lru

该配置就是配内存淘汰策略的(什么,你没配过?好好反省一下自己) volatile-lru:从已设置过期时

间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 volatile-ttl:从已设置过期时

间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 volatile-random:从已设置过期

时间的数据集(server.db[i].expires)中任意选择数据淘汰 allkeys-lru:从数据集

(server.db[i].dict)中挑选最近最少使用的数据淘汰 allkeys-random:从数据集

(server.db[i].dict)中任意选择数据淘汰 no-enviction(驱逐):禁止驱逐数据,新写入操作会

报错 ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile

random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

38Redis 为什么是单线程的

官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器

内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单

线程的方案了(毕竟采用多线程会有很多麻烦!)Redis利用队列技术将并发访问变为串行访问 1)

绝大部分请求是纯粹的内存操作(非常快速)2)采用单线程,避免了不必要的上下文切换和竞争条

件 3)非阻塞IO优点:

速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复

杂度都是O(1)

支持丰富数据类型,支持string,list,set,sorted set,hash

支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除如何解决redis的

并发竞争key问题

阿里内部资料同时有多个子系统去set一个key。这个时候要注意什么呢?

不推荐使用redis的事务机制。因为我们

的生产环境,基本都是redis集群环境,做了数据分片操作。你一个事务中有涉及到多个key操作的

时候,这多个key不一定都存储在同一个redis-server上。因此,redis的事务机制,十分鸡肋。 (1)

如果对这个key操作,不要求顺序:

准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可 (2)

如果对这个key操作,要求顺序:

分布式锁+时间戳。 假设这会系统B先抢到锁,将key1设置为

{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做

set操作了。以此类推。 (3) 利用队列,将set方法变成串行访问也可以redis遇到高并发,如果保证

读写key的一致性 对redis的操作都是具有原子性的,是线程安全的操作,你不用考虑并发问题,redis内

部已经帮你处理好并发的问题了。

39Redis 常见性能问题和解决方案?

(1) Master 最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件 (2) 如果数据比较重

要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次 (3) 为了主从复制的速度和连接的稳

定性, Master 和 Slave 最好在同一个局域网内 (4) 尽量避免在压力很大的主库上增加从库 (5) 主从

复制不要用图状结构,用单向链表结构更为稳定,即: Master <- Slave1 <- Slave2 <-Slave3…

40、为什么Redis的操作是原子性的,怎么保证原子性的?

对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。

Redis的操作之所以是原子性的,是因为Redis是单线程的。 Redis本身提供的所有API都是原子操

作,Redis中的事务其实是要保证批量操作的原子性。 多个命令在并发中也是原子性的吗?

不一

定,

将get和set改成单命令操作,incr 。使用Redis的事务,或者使用Redis+Lua==的方式实现.

41、了解Redis的事务吗?

Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的 Redis会将一个事务中的

所有命令序列化,然后按顺序执行。 1.redis 不支持回滚“Redis 在事务失败时不进行回滚,而是继

续执行余下的命令”,

所以 Redis 的内部可以保持简单且快速。 2.如果在一个事务中的命令出现错

误,那么所有的命令都不会执行; 3.如果在一个事务中出现运行错误,那么正确的命令会被执行。

1)MULTI命令用于开启一个事务,它总是返回OK。 MULTI执行之后,客户端可以继续向服务器发

送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有

队列中的命令才会被执行。 2)EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回

值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。 3)通过调用DISCARD,客户

端可以清空事务队列,并放弃执行事务,

并且客户端会从事务状态中退出。 4)WATCH 命令可以

为 Redis 事务提供 check-and-set (CAS)行为。 可以监控一个或多个键,一旦其中有一个键被修

改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。

42Redis 的数据类型及使用场景

String

阿里内部资料最常规的 set/get 操作,Value 可以是 String 也可以是数字。一般做一些复杂的计数功能的缓存。

Hash

这里 Value 存放的是结构化的对象,比较方便的就是操作其中的某个字段。我在做单点登录的时

候,就是用这种数据结构存储用户信息,以 CookieId 作为 Key,设置 30 分钟为缓存过期时间,能

很好的模拟出类似 Session 的效果。

List

使用 List 的数据结构,可以做简单的消息队列的功能。另外,可以利用 lrange 命令,做基于 Redis

的分页功能,性能极佳,用户体验好。

Set

因为 Set 堆放的是一堆不重复值的集合。所以可以做全局去重的功能。我们的系统一般都是集群部

署,使用 JVM 自带的 Set 比较麻烦。另外,就是利用交集、并集、差集等操作,可以计算共同喜

好,全部的喜好,自己独有的喜好等功能。

Sorted Set

Sorted Set 多了一个权重参数 Score,集合中的元素能够按 Score 进行排列。可以做排行榜应用,

取 TOP(N) 操作。Sorted Set 可以用来做延时任务。

分布式篇

1、分布式幂等性如何设计?

在高并发场景的架构里,幂等性是必须得保证的。比如说支付功能,用户发起支付,如果后台没有

做幂等校验,刚好用户手抖多点了几下,于是后台就可能多次受到同一个订单请求,不做幂等很容

易就让用户重复支付了,这样用户是肯定不能忍的。

解决方案

1,查询和删除不在幂等讨论范围,查询肯定没有幂等的说,删除:第一次删除成功后,后面来删

除直接返回0,也是返回成功。

2,建唯一索引:唯一索引或唯一组合索引来防止新增数据存在脏数据 (当表存在唯一索引,并发

时新增异常时,再查询一次就可以了,数据应该已经存在了,返回结果即可)。

3,token机制:由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交。前端

在数据提交前要向后端服务的申请token,token放到 Redis 或 JVM 内存,token有效时间。提交后

后台校验token,同时删除token,生成新的token返回。redis要用删除操作来判断token,删除成

功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用。

4,悲观锁

阿里内部资料悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用(另外还要考

虑id是否为主键,如果id不是主键或者不是 InnoDB 存储引擎,那么就会出现锁全表)。

5,乐观锁,给数据库表增加一个version字段,可以通过这个字段来判断是否已经被修改了

6,分布式锁,比如 Redis 、 Zookeeper 的分布式锁。单号为key,然后给Key设置有效期(防止支

付失败后,锁一直不释放),来一个请求使用订单号生成一把锁,业务代码执行完成后再释放锁。

7,保底方案,先查询是否存在此单,不存在进行支付,存在就直接返回支付结果。

2,简单一次完整的 HTTP 请求所经历的步骤?

1、 DNS 解析(通过访问的域名找出其 IP 地址,递归搜索)。

2、HTTP 请求,当输入一个请求时,建立一个 Socket 连接发起 TCP的 3 次握手。

如果是 HTTPS 请求,会略微有不同。等到 HTTPS 小节,我们在来讲。

3.1、客户端向服务器发送请求命令(一般是 GET 或 POST 请求)。

这个是补充内容,面试一般不用回答。

客户端的网络层不用关心应用层或者传输层的东西,主要做的是通过查找路由表确定如何

到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的

描述,无非就是通过查找路由表决定通过那个路径到达服务器。

客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定 IP 地址的 MAC 地

址,然后发送 ARP 请求查找目的地址,如果得到回应后就可以使用 ARP 的请求应答交换

的 IP 数据包现在就可以传输了,然后发送 IP 数据包到达服务器的地址。

3.2、客户端发送请求头信息和数据。

4.1、服务器发送应答头信息。

4.2、服务器向客户端发送数据。

5、服务器关闭 TCP 连接(4次挥手)。

这里是否关闭 TCP 连接,也根据 HTTP Keep-Alive 机制有关。

同时,客户端也可以主动发起关闭 TCP 连接。

6、客户端根据返回的 HTML 、 CSS 、 JS 进行渲染。

select id ,name from table_# where id='##' for update;

update table_xxx set name=#name#,version=version+1 where version=#version#

阿里内部资料3、说说你对分布式事务的了解

分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,

特别是在微服务架构中,几乎可以说是无法避免。

首先要搞清楚:ACID、CAP、BASE理论。

ACID

指数据库事务正确执行的四个基本要素:

1. 原子性(Atomicity)

2. 一致性(Consistency)

3. 隔离性(Isolation)

4. 持久性(Durability)

CAP

CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性

(Availability)、分区容忍性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同

时实现两点,不可能三者兼顾。

阿里内部资料一致性:在分布式系统中的所有数据备份,在同一时刻是否同样的值。

可用性:在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。

分区容忍性:以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数

据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

BASE理论

BASE理论是对CAP中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到

强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。

Basically Available(基本可用)

Soft state(软状态)

Eventually consistent(最终一致性)

4、你知道哪些分布式事务解决方案?

我目前知道的有五种:

1. 两阶段提交(2PC)

2. 三阶段提交(3PC)

3. 补偿事务(TCC=Try-Confifirm-Cancel)

4. 本地消息队列表(MQ)

5. Sagas事务模型(最终一致性)

说完上面五种,面试官一般都会继续问下面这几个问题(可能就问一两个,也可能全部问)。

5,什么是二阶段提交?

两阶段提交2PC是分布式事务中最强大的事务类型之一,两段提交就是分两个阶段提交:

第一阶段询问各个事务数据源是否准备好。

第二阶段才真正将数据提交给事务数据源。

为了保证该事务可以满足ACID,就要引入一个协调者(Cooradinator)。其他的节点被称为参与者

(Participant)。协调者负责调度参与者的行为,并最终决定这些参与者是否要把事务进行提交。

处理流程如下:

阿里内部资料阶段一

a) 协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待答复。

b) 各参与者执行事务操作,将 undo 和 redo 信息记入事务日志中(但不提交事务)。

c) 如参与者执行成功,给协调者反馈 yes,否则反馈 no。

阶段二

如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(rollback)消息;否则,

发送提交(commit)消息。两种情况处理如下:

情况1当所有参与者均反馈 yes,提交事务

a) 协调者向所有参与者发出正式提交事务的请求(即 commit 请求)。

b) 参与者执行 commit 请求,并释放整个事务期间占用的资源。

c) 各参与者向协调者反馈 ack(应答)完成的消息。

d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务提交。

情况2当有一个参与者反馈 no,回滚事务

a) 协调者向所有参与者发出回滚请求(即 rollback 请求)。

b) 参与者使用阶段 1 中的 undo 信息执行回滚操作,并释放整个事务期间占用的资源。

c) 各参与者向协调者反馈 ack 完成的消息。

d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务。

问题

阿里内部资料1) 性能问题:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈。

2) 可靠性问题:如果协调者存在单点故障问题,或出现故障,提供者将一直处于锁定状态。

3) 数据一致性问题:在阶段 2 中,如果出现协调者和参与者都挂了的情况,有可能导致数据不一

致。

优点:尽量保证了数据的强一致,适合对数据强一致要求很高的关键领域。(其实也不能100%保证

强一致)。

缺点:实现复杂,牺牲了可用性,对性能影响较大,不适合高并发高性能场景。

6、什么是三阶段提交?

三阶段提交是在二阶段提交上的改进版本,3PC最关键要解决的就是协调者和参与者同时挂掉的问

题,所以3PC把2PC的准备阶段再次一分为二,这样三阶段提交。

处理流程如下 :

阶段一

a) 协调者向所有参与者发出包含事务内容的 canCommit 请求,询问是否可以提交事务,并等待所

有参与者答复。

b) 参与者收到 canCommit 请求后,如果认为可以执行事务操作,则反馈 yes 并进入预备状态,否

则反馈 no。

阶段二

协调者根据参与者响应情况,有以下两种可能。

情况1所有参与者均反馈 yes,协调者预执行事务

a) 协调者向所有参与者发出 preCommit 请求,进入准备阶段。

b) 参与者收到 preCommit 请求后,执行事务操作,将 undo 和 redo 信息记入事务日志中(但不

提交事务)。

c) 各参与者向协调者反馈 ack 响应或 no 响应,并等待最终指令。

阿里内部资料情况2只要有一个参与者反馈 no,或者等待超时后协调者尚无法收到所有提供者的反馈,即中断

事务

a) 协调者向所有参与者发出 abort 请求。

b) 无论收到协调者发出的 abort 请求,或者在等待协调者请求过程中出现超时,参与者均会中断事

务。

阶段三

该阶段进行真正的事务提交,也可以分为以下两种情况。

情况 1所有参与者均反馈 ack 响应,执行真正的事务提交

a) 如果协调者处于工作状态,则向所有参与者发出 do Commit 请求。

b) 参与者收到 do Commit 请求后,会正式执行事务提交,并释放整个事务期间占用的资源。

c) 各参与者向协调者反馈 ack 完成的消息。

d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务提交。

情况2只要有一个参与者反馈 no,或者等待超时后协调组尚无法收到所有提供者的反馈,即回滚

事务。

a) 如果协调者处于工作状态,向所有参与者发出 rollback 请求。

b) 参与者使用阶段 1 中的 undo 信息执行回滚操作,并释放整个事务期间占用的资源。

c) 各参与者向协调组反馈 ack 完成的消息。

d) 协调组收到所有参与者反馈的 ack 消息后,即完成事务回滚。

优点:相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。

避免了协调者单点问题。阶段 3 中协调者出现问题时,参与者会继续提交事务。

缺点:数据不一致问题依然存在,当在参与者收到 preCommit 请求后等待 do commite 指令时,

此时如果协调者请求中断事务,而协调者无法与参与者正常通信,会导致参与者继续提交事务,造

成数据不一致。

7、什么是补偿事务?

TCC (Try Confifirm Cancel)是服务化的二阶段编程模型,采用的补偿机制:

阿里内部资料TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补

偿(撤销)操作。

它分为三个步骤:

Try 阶段主要是对业务系统做检测及资源预留。

Confifirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confifirm阶段时,默

认 Confifirm阶段是不会出错的。即:只要Try成功,Confifirm一定成功。

Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

举个例子,假入你要向 老田 转账,思路大概是:

我们有一个本地方法,里面依次调用步骤: 1、

首先在 Try 阶段,要先调用远程接口把 你 和 老田 的钱给冻结起来。 2、在 Confifirm 阶段,执行远

程调用的转账的操作,转账成功进行解冻。 3、如果第2步执行成功,那么转账成功,如果第二步执

行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。

优点:

性能提升:具体业务来实现控制资源锁的粒度变小,不会锁定整个资源。

数据最终一致性:基于 Confifirm 和 Cancel 的幂等性,保证事务最终完成确认或者取消,保证数据

的一致性。

可靠性:解决了 XA 协议的协调者单点故障问题,由主业务方发起并控制整个业务活动,业务活动

管理器也变成多点,引入集群。

缺点:TCC 的 Try、Confifirm 和 Cancel 操作功能要按具体业务来实现,业务耦合度较高,提高了开

发成本。

阿里内部资料8、消息队列是怎么实现的?

本地消息表(异步确保)

本地消息表这种实现方式应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行

处理,这种思路是来源于ebay。我们可以从下面的流程图中看出其中的一些细节:

基本思路就是:

消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提

交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。如果消息发送

失败,会进行重试发送。

消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经

处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个

业务补偿消息,通知生产方进行回滚等操作。

生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。如果有

靠谱的自动对账补账逻辑,这种方案还是非常实用的。

这种方案遵循BASE理论,采用的是最终一致性,笔者认为是这几种方案里面比较适合实际业务场景

的,即不会出现像2PC那样复杂的实现(当调用链很长的时候,2PC的可用性是非常低的),也不会像

TCC那样可能出现确认或者回滚不了的情况。

优点:

一种非常经典的实现,避免了分布式事务,实现了最终一致性。在 .NET中 有现成的解决方

案。

缺点:

消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。

MQ 事务消息

阿里内部资料有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用

的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不

支持。

以阿里的 RocketMQ 中间件为例,其思路大致为:

第一阶段Prepared消息,会拿到消息的地址。 第二阶段执行本地事务,第三阶段通过第一阶段拿到

的地址去访问消息,并修改状态。

也就是说在业务方法内要想消息队列提交两次请求,一次发送消息和一次确认消息。如果确认消息

发送失败了RocketMQ会定期扫描消息集群中的事务消息,这时候发现了Prepared消息,它会向消

息发送者确认,所以生产方需要实现一个check接口,RocketMQ会根据发送端设置的策略来决定是

回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。

遗憾的是,RocketMQ并没有 .NET 客户端。有关 RocketMQ的更多消息,大家可以查看这篇博客

优点:

实现了最终一致性,不需要依赖本地数据库事务。

缺点:

实现难度大,主流MQ不支持,没有.NET客户端,RocketMQ事务消息部分代码也未开源。

9、那你说说Sagas事务模型

Saga模式是一种分布式异步事务,一种最终一致性事务,是一种柔性事务,有两种不同的方式来实

现saga事务,最流行的两种方式是:

一、 事件/编排Choreography:没有中央协调器(没有单点风险)时,每个服务产生并聆听其他

服务的事件,并决定是否应采取行动。

阿里内部资料该实现第一个服务执行一个事务,然后发布一个事件。该事件被一个或多个服务进行监听,这些服

务再执行本地事务并发布(或不发布)新的事件,当最后一个服务执行本地事务并且不发布任何事

件时,意味着分布式事务结束,或者它发布的事件没有被任何Saga参与者听到都意味着事务结束。

处理流程说明:

订单服务保存新订单,将状态设置为pengding挂起状态,并发布名为ORDER_CREATED_EVENT的

事件。

支付服务监听ORDER_CREATED_EVENT,并公布事件BILLED_ORDER_EVENT。

库存服务监听BILLED_ORDER_EVENT,更新库存,并发布ORDER_PREPARED_EVENT。

货运服务监听ORDER_PREPARED_EVENT,然后交付产品。最后,它发布

ORDER_DELIVERED_EVENT。

最后,订单服务侦听ORDER_DELIVERED_EVENT并设置订单的状态为concluded完成。

假设库存服务在事务过程中失败了。进行回滚:

库存服务产生PRODUCT_OUT_OF_STOCK_EVENT

订购服务和支付服务会监听到上面库存服务的这一事件:

①支付服务会退款给客户。

②订单服务将订单状态设置为失败。

阿里内部资料优点:事件/编排是实现Saga模式的自然方式; 它很简单,容易理解,不需要太多的努力来构建,所

有参与者都是松散耦合的,因为他们彼此之间没有直接的耦合。如果您的事务涉及2至4个步骤,则

可能是非常合适的。

二、 命令/协调orchestrator:中央协调器负责集中处理事件的决策和业务逻辑排序。

saga协调器orchestrator以命令/回复的方式与每项服务进行通信,告诉他们应该执行哪些操作。

订单服务保存pending状态,并要求订单Saga协调器(简称OSO)开始启动订单事务。

OSO向收款服务发送执行收款命令,收款服务回复Payment Executed消息。

OSO向库存服务发送准备订单命令,库存服务将回复OrderPrepared消息。

OSO向货运服务发送订单发货命令,货运服务将回复Order Delivered消息。

OSO订单Saga协调器必须事先知道执行“创建订单”事务所需的流程(通过读取BPM业务流程XML配置

获得)。如果有任何失败,它还负责通过向每个参与者发送命令来撤销之前的操作来协调分布式的回

滚。当你有一个中央协调器协调一切时,回滚要容易得多,因为协调器默认是执行正向流程,回滚

时只要执行反向流程即可。

优点:

避免服务之间的循环依赖关系,因为saga协调器会调用saga参与者,但参与者不会调用协调器。

集中分布式事务的编排。

只需要执行命令/回复(其实回复消息也是一种事件消息),降低参与者的复杂性。

在添加新步骤时,事务复杂性保持线性,回滚更容易管理。

阿里内部资料如果在第一笔交易还没有执行完,想改变有第二笔事务的目标对象,则可以轻松地将其暂停在协调

器上,直到第一笔交易结束。

10,分布式ID生成有几种方案?

分布式ID的特性

唯一性:确保生成的ID是全网唯一的。

有序递增性:确保生成的ID是对于某个用户或者业务是按一定的数字有序递增的。

高可用性:确保任何时候都能正确的生成ID。

带时间:ID里面包含时间,一眼扫过去就知道哪天的交易。

分布式ID生成方案

1. UUID

算法的核心思想是结合机器的网卡、当地时间、一个随记数来生成UUID。

优点:本地生成,生成简单,性能好,没有高可用风险

缺点:长度过长,存储冗余,且无序不可读,查询效率低

2. 数据库自增ID

使用数据库的id自增策略,如 MySQL 的 auto_increment。并且可以使用两台数据库分别设置不同

步长,生成不重复ID的策略来实现高可用。

优点:数据库生成的ID绝对有序,高可用实现方式简单

缺点:需要独立部署数据库实例,成本高,有性能瓶颈

3. 批量生成ID

阿里内部资料一次按需批量生成多个ID,每次生成都需要访问数据库,将数据库修改为最大的ID值,并在内存中

记录当前值及最大值。

优点:避免了每次生成ID都要访问数据库并带来压力,提高性能

缺点:属于本地生成策略,存在单点故障,服务重启造成ID不连续

4. Redis生成ID

Redis的所有命令操作都是单线程的,本身提供像 incr 和 increby 这样的自增原子命令,所以能保

证生成的 ID 肯定是唯一有序的。

优点:不依赖于数据库,灵活方便,且性能优于数据库;数字ID天然排序,对分页或者需要排

序的结果很有帮助。

缺点:如果系统中没有Redis,还需要引入新的组件,增加系统复杂度;需要编码和配置的工作

量比较大。

考虑到单节点的性能瓶颈,可以使用 Redis 集群来获取更高的吞吐量。假如一个集群中有5台

Redis。可以初始化每台 Redis 的值分别是1, 2, 3, 4, 5,然后步长都是 5。

5. Twittersnowflflake算法重点

Twitter 利用 zookeeper 实现了一个全局ID生成的服务 Snowflflake

如上图的所示,Twitter 的 Snowflflake 算法由下面几部分组成:

1位符号位:

由于 long 类型在 java 中带符号的,最高位为符号位,正数为 0,负数为 1,且实际系统中所使用

的ID一般都是正数,所以最高位为 0。

41位时间戳(毫秒级):

需要注意的是此处的 41 位时间戳并非存储当前时间的时间戳,而是存储时间戳的差值(当前时间

戳 - 起始时间戳),这里的起始时间戳一般是ID生成器开始使用的时间戳,由程序来指定,所以41

位毫秒时间戳最多可以使用 (1 << 41) / (1000x60x60x24x365) = 69年 。

10位数据机器位:

阿里内部资料包括5位数据标识位和5位机器标识位,这10位决定了分布式系统中最多可以部署 1 << 10 = 1024

s个节点。超过这个数量,生成的ID就有可能会冲突。

12位毫秒内的序列:

这 12 位计数支持每个节点每毫秒(同一台机器,同一时刻)最多生成 1 << 12 = 4096个ID

加起来刚好64位,为一个Long型。

优点:高性能,低延迟,按时间有序,一般不会造成ID碰撞

缺点:需要独立的开发和部署,依赖于机器的时钟

6. 百度UidGenerator

UidGenerator是百度开源的分布式ID生成器,基于于snowflflake算法的实现,看起来感觉还行。不

过,国内开源的项目维护性真是担忧。

7. 美团Leaf

Leaf 是美团开源的分布式ID生成器,能保证全局唯一性、趋势递增、单调递增、信息安全,里面也

提到了几种分布式方案的对比,但也需要依赖关系数据库、Zookeeper等中间件。

11,幂等解决方法有哪些?

什么是幂等?

常见描述:对于相同的请求应该返回相同的结果,所以查询类接口是天然的幂等性接口。

真正的回答方式:幂等指的是相同请求(identical request)执行一次或者多次所带来的副作

用(side-effffects)是一样的。

什么常见会出现幂等?

前端调后端接口发起支付超时,然后再次发起重试。可能会导致多次支付。

Dubbo中也有重试机制。

页面上多次点击。

我们想要的是:接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终

得到的结果是一致的 。

解决方案

在插入数据的时候,插入去重表,利用数据库的唯一索引特性,保证唯一的逻辑。

悲观锁,select for update,整个执行过程中锁定该订单对应的记录。注意:这种在DB读大于写的

情况下尽量少用。

阿里内部资料先查询后修改数据,并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简

单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了。注

意:核心高并发流程不要用这种方法。

状态机幂等,在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机,就是业务单

据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状

态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的

话,保证了有限状态机的幂等。

token机制,防止页面重复提交:

集群环境:采用token加redis(redis单线程的,处理需要排队)或者

单JVM环境:采用token加redis或token加jvm内存

数据提交前要向服务的申请token,token放到redis或jvm内存,设置token有效时间,提交后后台

校验token,同时删除token,生成新的token返回。token特点:要申请,一次有效性,可以限流。

全局唯一ID,如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先

根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局ID,存储到存

储系统中,比如数据库、redis等。如果存在则表示该方法已经执行。

12,常见负载均衡算法有哪些?

13、你知道哪些限流算法?

限流算法有四种常见算法:

计数器算法(固定窗口)

滑动窗口

漏桶算法

令牌桶算法

阿里内部资料14、说说什么是计数器(固定窗口)算法

计数器算法是使用计数器在周期内累加访问次数,当达到设定的限流值时,触发限流策略。下一个

周期开始时,进行清零,重新计数。

此算法在单机还是分布式环境下实现都非常简单,使用redis的incr原子自增性和线程安全即可轻松

实现。

这个算法通常用于QPS限流和统计总访问量,对于秒级以上的时间周期来说,会存在一个非常严重

的问题,那就是临界问题,如下图:

假设1min内服务器的负载能力为100,因此一个周期的访问量限制在100,然而在第一个周期的最

后5秒和下一个周期的开始5秒时间段内,分别涌入100的访问量,虽然没有超过每个周期的限制

量,但是整体上10秒内已达到200的访问量,已远远超过服务器的负载能力,由此可见,计数器算

法方式限流对于周期比较长的限流,存在很大的弊端。

15、说说什么是滑动窗口算法

滑动窗口算法是将时间周期分为N个小周期,分别记录每个小周期内访问次数,并且根据时间滑动

删除过期的小周期。

如下图,假设时间周期为1min,将1min再分为2个小周期,统计每个小周期的访问数量,则可以看

到,第一个时间周期内,访问数量为75,第二个时间周期内,访问数量为100,超过100的访问则

被限流掉了

阿里内部资料由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精

确。

此算法可以很好的解决固定窗口算法的临界问题。

16、说说什么是漏桶算法

漏桶算法是访问请求到达时直接放入漏桶,如当前容量已达到上限(限流值),则进行丢弃(触发

限流策略)。漏桶以固定的速率进行释放访问请求(即请求通过),直到漏桶为空。

阿里内部资料17、说说什么是令牌桶算法

令牌桶算法是程序以r(r=时间周期/限流值)的速度向令牌桶中增加令牌,直到令牌桶满,请求到

达时向令牌桶请求令牌,如获取到令牌则通过请求,否则触发限流策略

阿里内部资料18、数据库如何处理海量数据?

对数据库进行:分库分表,主从架构,读写分离。

水平分库/分表,垂直分库/分表。

水平分库/表,各个库和表的结构一模一样。

垂直分库/表,各个库和表的结构不一样。

读写分离:主机负责写,从机负责读。

19、如何将长链接转换成短链接,并发送短信?

短 URL 从生成到使用分为以下几步:

有一个服务,将要发送给你的长 URL 对应到一个短 URL 上.例如 www.baidu.com -> www.t.cn/

1。

把短 url 拼接到短信等的内容上发送。

用户点击短 URL ,浏览器用 301 / 302 进行重定向,访问到对应的长 URL。

展示对应的内容。

阿里内部资料20、长链接和短链接如何互相转换?

思路是建立一个发号器。每次有一个新的长 URL 进来,我们就增加一。并且将新的数值返回.第一

个来的 url 返回"www.x.cn/0",第二个返回"www.x.cn/1"。

21、长链接和短链接的对应关系如何存储?

如果数据量小且 QPS 低,直接使用数据库的自增主键就可以实现。 还可以将最近/最热门的对应关

系存储在 K-V 数据库中,这样子可以节省空间的同时,加快响应速度。

22、如何提高系统的并发能力?

使用分布式系统。

部署多台服务器,并做负载均衡。

使用缓存(Redis)集群。

数据库分库分表 + 读写分离。

引入消息中间件集群。

网络篇

1HTTP 响应码有哪些?分别代表什么含义?

200:成功,Web 服务器成功处理了客户端的请求。

301:永久重定向,当客户端请求一个网址的时候,Web 服务器会将当前请求重定向到另一个

网址,搜索引擎会抓取重定向后网页的内容并且将旧的网址替换为重定向后的网址。

302:临时重定向,搜索引擎会抓取重定向后网页的内容而保留旧的网址,因为搜索引擎认为

重定向后的网址是暂时的。

400:客户端请求错误,多为参数不合法导致 Web 服务器验参失败。

404:未找到,Web 服务器找不到资源。

500:Web 服务器错误,服务器处理客户端请求的时候发生错误。

503:服务不可用,服务器停机。

504:网关超时。

2Forward Redirect 的区别?

浏览器 URL 地址:Forward 是服务器内部的重定向,服务器内部请求某个 servlet,然后获取

响应的内容,浏览器的 URL 地址是不会变化的;Redirect 是客户端请求服务器,然后服务器给

客户端返回了一个 302 状态码和新的 location,客户端重新发起 HTTP 请求,服务器给客户端

响应 location 对应的 URL 地址,浏览器的 URL 地址发生了变化。

阿里内部资料数据的共享:Forward 是服务器内部的重定向,request 在整个重定向过程中是不变的,

request 中的信息在 servlet 间是共享的。Redirect 发起了两次 HTTP 请求分别使用不同的

request。

请求的次数:Forward 只有一次请求;Redirect 有两次请求。

3 Get Post 请求有哪些区别?

用途:

get 请求用来从服务器获取资源

post 请求用来向服务器提交数据

表单的提交方式:

get 请求直接将表单数据以 name1=value1&name2=value2 的形式拼接到 URL 上(http://www.

baidu.com/action?name1=value1&name2=value2),多个参数参数值需要用 & 连接起来并

且用 ? 拼接到 action 后面;

post 请求将表单数据放到请求头或者请求的消息体中。

传输数据的大小限制:

get 请求传输的数据受到 URL 长度的限制,而 URL 长度是由浏览器决定的;

post 请求传输数据的大小理论上来说是没有限制的。

参数的编码:

get 请求的参数会在地址栏明文显示,使用 URL 编码的文本格式传递参数;

post 请求使用二进制数据多重编码传递参数。

缓存:

get 请求可以被浏览器缓存被收藏为标签;

post 请求不会被缓存也不能被收藏为标签。

4,说说 TCP UDP 的区别,以及各自的优缺点

1、TCP面向连接(如打电话要先拨号建立连接):UDP是无连接的,即发送数据之前不需要建立连

接。

2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序

到达;UDP尽最大努力交付,即不保证可靠交付。tcp通过校验和,重传控制,序号标识,滑动窗

口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通

信。

4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

阿里内部资料5、TCP对系统资源要求较多,UDP对系统资源要求较少。

5,说一下 HTTP HTTPS 的区别

端口不同:HTTP和 HTTPS 的连接方式不同没用的端口也不一样,HTTP是80, HTTPS 用的是443

消耗资源:和HTTP相比,HTTPS通信会因为加解密的处理消耗更多的CPU和内存资源。

开销: HTTPS 通信需要证书,这类证书通常需要向认证机构申请或者付费购买。

6,说说HTTPTCPSocket 的关系是什么?

TCP/IP 代表传输控制协议/网际协议,指的是一系列协议族。

HTTP 本身就是一个协议,是从 Web 服务器传输超文本到本地浏览器的传送协议。

Socket 是 TCP/IP 网络的 API ,其实就是一个门面模式,它把复杂的 TCP/IP 协议族隐藏在

Socket 接口后面。对用户来说,一组简单的接口就是全部,让 Socket 去组织数据,以符合指

定的协议。

综上所述:

需要 IP 协议来连接网络

TCP 是一种允许我们安全传输数据的机制,使用 TCP 协议来传输数据的 HTTP 是 Web 服务器

和客户端使用的特殊协议。

HTTP 基于 TCP 协议,所以可以使用 Socket 去建立一个 TCP 连接。

7,说一下HTTP的长连接与短连接的区别

HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。

短连接

在HTTP/1.0中默认使用短链接,也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连

接,但任务结束就中断连接。如果客户端访问的某个HTML或其他类型的Web资源,如 JavaScript

文件、图像文件、 CSS 文件等。当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话.

长连接

从HTTP/1.1起,默认使用长连接,用以保持连接特性。在使用长连接的情况下,当一个网页打开完

成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭。如果客户端再次访问这个服务

器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时

间,可以在不同的服务器软件(如Apache)中设定这个时间。

8TCP 为什么要三次握手,两次不行吗?为什么?

阿里内部资料TCP 客户端和服务端建立连接需要三次握手,首先服务端需要开启监听,等待客户端的连接请

求,这个时候服务端处于“收听”状态;

客户端向服务端发起连接,选择 seq=x 的初始序列号,此时客户端处于“同步已发送”的状态;

服务端收到客户端的连接请求,同意连接并向客户端发送确认,确认号是 ack=x+1 表示客户

端可以发送下一个数据包序号从 x+1 开始,同时选择 seq=y 的初始序列号,此时服务端处

于“同步收到”状态;

客户端收到服务端的确认后,向服务端发送确认信息,确认号是 ack=y+1 表示服务端可以发

送下一个数据包序号从 y+1 开始,此时客户端处于“已建立连接”的状态;

服务端收到客户端的确认后,也进入“已建立连接”的状态。

从三次握手的过程可以看出如果只有两次握手,那么客户端的起始序列号可以确认,服务端的起始

序列号将得不到确认。

9,说一下 TCP 粘包是怎么产生的?怎么解决粘包问题的?

阿里内部资料上文中讲 TCP 和 UDP 区别的时候提到 TCP 传输数据基于字节流,从应用层到 TCP 传输层的多个数

据包是一连串的字节流是没有边界的,而且 TCP 首部并没有记录数据包的长度,所以 TCP 传输数

据的时候可能会发送粘包和拆包的问题;而 UDP 是基于数据报传输数据的,UDP 首部也记录了数

据报的长度,可以轻易的区分出不同的数据包的边界。

接下来看下 TCP 传输数据的几种情况,首先第一种情况是正常的,既没有发送粘包也没有发生拆

包。

第二种情况发生了明显的粘包现象,这种情况对于数据接收方来说很难处理。

接下来的两种情况发生了粘包和拆包的现象,接收端收到的数据包要么是不完整的要么是多出来一

块儿。

造成粘包和拆包现象的原因:

TCP 发送缓冲区剩余空间不足以发送一个完整的数据包,将发生拆包;

要发送的数据超过了最大报文长度的限制,TCP 传输数据时进行拆包;

要发送的数据包小于 TCP 发送缓冲区剩余空间,TCP 将多个数据包写满发送缓冲区一次发送出

去,将发生粘包;

接收端没有及时读取 TCP 发送缓冲区中的数据包,将会发生粘包。

阿里内部资料粘包拆包的解决方法:

发送端给数据包添加首部,首部中添加数据包的长度属性,这样接收端通过首部中的长度字段

就可以知道数据包的实际长度啦;

针对发送的数据包小于缓冲区大小的情况,发送端可以将不同的数据包规定成同样的长度,不

足这个长度的补充 0,接收端从缓冲区读取固定的长度数据这样就可以区分不同的数据包;

发送端通过给不同的数据包添加间隔符合确定边界,接收端通过这个间隔符合就可以区分不同

的数据包。

10TCP 如何保证可靠性

序列号和确认号机制:

TCP 发送端发送数据包的时候会选择一个 seq 序列号,接收端收到数据包后会检测数据包的完整

性,如果检测通过会响应一个 ack 确认号表示收到了数据包。

超时重发机制:

TCP 发送端发送了数据包后会启动一个定时器,如果一定时间没有收到接受端的确认后,将会重新

发送该数据包。

对乱序数据包重新排序:

从 IP 网络层传输到 TCP 层的数据包可能会乱序,TCP 层会对数据包重新排序再发给应用层。

丢弃重复数据:

从 IP 网络层传输到 TCP 层的数据包可能会重复,TCP 层会丢弃重复的数据包。

流量控制:

TCP 发送端和接收端都有一个固定大小的缓冲空间,为了防止发送端发送数据的速度太快导致接收

端缓冲区溢出,发送端只能发送接收端可以接纳的数据,为了达到这种控制效果,TCP 用了流量控

制协议(可变大小的滑动窗口协议)来实现。

11OSI 的七层模型都有哪些?

OSI七层模型一般指开放系统互连参考模型 (Open System Interconnect 简称OSI)是国际标准化组

织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参考模型,为开放式互连信息系

统提供了一种功能结构的框架。

应用层:各种应用程序协议,比如 HTTP、HTTPS、FTP、SOCKS 安全套接字协议、DNS 域名

系统、GDP 网关发现协议等等。

表示层:加密解密、转换翻译、压缩解压缩,比如 LPP 轻量级表示协议。

会话层:不同机器上的用户建立和管理会话,比如 SSL 安全套接字层协议、TLS 传输层安全协

议、RPC 远程过程调用协议等等。

阿里内部资料传输层:接受上一层的数据,在必要的时候对数据进行分割,并将这些数据交给网络层,保证

这些数据段有效到达对端,比如 TCP 传输控制协议、UDP 数据报协议。

网络层:控制子网的运行:逻辑编址、分组传输、路由选择,比如 IP、IPV6、SLIP 等等。

数据链路层:物理寻址,同时将原始比特流转变为逻辑传输路线,比如 XTP 压缩传输协议、

PPTP 点对点隧道协议等等。

物理层:机械、电子、定时接口通信信道上的原始比特流传输,比如 IEEE802.2 等等。

阿里内部资料12,浏览器中输入:www.woaijava.com之后都发生了什么?

请详细阐述

由域名→IP地址 寻找IP地址的过程依次经过了浏览器缓存、系统缓存、hosts文件、路由器缓

存、 递归搜索根域名服务器。

建立TCP/IP连接(三次握手具体过程)

由浏览器发送一个HTTP请求

经过路由器的转发,通过服务器的防火墙,该HTTP请求到达了服务器

服务器处理该HTTP请求,返回一个HTML文件

浏览器解析该HTML文件,并且显示在浏览器端

这里需要注意:

HTTP协议是一种基于TCP/IP的应用层协议,进行HTTP数据请求必须先建立TCP/IP连接

可以这样理解:HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了

网络通信的能力。

两个计算机之间的交流无非是两个端口之间的数据通信,具体的数据会以什么样的形式展现是以

不同的应用层协议来定义的。

13,如何实现跨域?

当浏览器执行 JS 脚本的时候,会检测脚本要访问的协议、域名、端口号是不是和当前网址一致,如

果不一致就是跨域。跨域是不允许的,这种限制叫做浏览器的同源策略,简单点的说法就是浏览器

不允许一个源中加载脚本与其他源中的资源进行交互。那么如何实现跨域呢?

JSONP、CORS方式、代理方式

1 JSONP 方式

script、img、iframe、link、video、audio 等带有 src 属性的标签可以跨域请求和执行资源,

JSONP 利用这一点“漏洞”实现跨域。

再看下 jQuery 的写法。

<script>

var scriptTag = document.createElement('script');

scriptTag.type = "text/javascript";

scriptTag.src = "http://10.10.0.101:8899/jsonp?callback=f";

document.head.appendChild(scriptTag);

</script>

$.ajax({

// 请求域名

url:'http://10.10.0.101:8899/login',

阿里内部资料JSONP 实现跨域很简单但是只支持 GET 请求方式。而且在服务器端接受到 JSONP 请求后需要设置

请求头,添加 Access-Control-Allow-Origin 属性,属性值为 * ,表示允许所有域名访问,这样浏

览器才会正常解析,否则会报 406 错误。

2 CORS 方式

CORS(Cross-Origin Resource Sharing)即跨域资源共享,需要浏览器和服务器同时支持,这种

请求方式分为简单请求和非简单请求。

当浏览器发出的 XMLHttpRequest 请求的请求方式是 POST 或者 GET,请求头中只包含 Accept、

Accept-Language、Content-Language、Last-Event-ID、Content-Type(application/x-www

form-urlencoded、multipart/form-data、text/plain)时那么这个请求就是一个简单请求。

对于简单的请求,浏览器会在请求头中添加 Origin 属性,标明本次请求来自哪个源(协议 + 域名 +

端口)。

GET

// 标明本次请求来自哪个源(协议+域名+端口)

Origin: http://127.0.0.1:8080

// IP

Host: 127.0.0.1:8080

// 长连接

Connection: keep-alive

Content-Type: text/plain

如果 Origin 标明的域名在服务器许可范围内,那么服务器就会给出响应:

// 请求方式

type:'GET',

// 数据类型选择 jsonp

dataType:'jsonp',

// 回调方法名

jsonpCallback:'callback',

});

// 回调方法

function callback(response) {

console.log(response);

}

response.setHeader("Access-Control-Allow-Origin", "*");

阿里内部资料 // 该值上文提到过,表示允许浏览器指定的域名访问,要么为浏览器传入的 origin,要么为 * 表示

所有域名都可以访问

Access-Control-Allow-Origin: http://127.0.0.1:8080

// 表示服务器是否同意浏览器发送 cookie

Access-Control-Allow-Credentials: true

// 指定 XMLHttpRequest#getResponseHeader() 方法可以获取到的字段

Access-Control-Expose-Headers: xxx

Content-Type: text/html; charset=utf-8

Access-Control-Allow-Credentials: true 表示服务器同意浏览器发送 cookie,另外浏览器也需要

设置支持发送 cookie,否则就算服务器支持浏览器也不会发送。

另外一种是非简单请求,请求方式是 PUT 或 DELETE,或者请求头中添加了 Content

Type:application/json 属性和属性值的请求。

这种请求在浏览器正式发出 XMLHttpRequest 请求前会先发送一个预检 HTTP 请求,询问服务器当

前网页的域名是否在服务器的许可名单之中,只有得到服务器的肯定后才会正式发出通信请求。

预检请求的头信息:

// 预检请求的请求方式是 OPTIONS

OPTIONS

// 标明本次请求来自哪个源(协议+域名+端口)

Origin: http://127.0.0.1:8080

// 标明接下来的 CORS 请求要使用的请求方式

Access-Control-Request-Method: PUT

// 标明接下来的 CORS 请求要附加发送的头信息属性

Access-Control-Request-Headers: X-Custom-Header

// IP

Host: 127.0.0.1:8080

// 长连接

Connection: keep-alive

如果服务器回应预检请求的响应头中没有任何 CORS 相关的头信息的话表示不支持跨域,如果允许

跨域就会做出响应,响应头信息如下:

HTTP/1.1 200 OK

// 该值上文提到过,表示允许浏览器指定的域名访问,要么为浏览器传入的 origin,要么为 * 表示所

var xhr = new XMLHttpRequest();

// 设置发送的请求是否带 cookie

xhr.withCredentials = true;

xhr.open('post', 'http://10.10.0.101:8899/login', true);

xhr.setRequestHeader('Content-Type', 'text/plain');

阿里内部资料有域名都可以访问

Access-Control-Allow-Origin:http://127.0.0.1:8080

// 服务器支持的所有跨域请求方式,为了防止浏览器发起多次预检请求把所有的请求方式返回给浏览器

Access-Control-Allow-Methods: GET, POST, PUT

// 服务器支持预检请求头信息中的 Access-Control-Request-Headers 属性值

Access-Control-Allow-Headers: X-Custom-Header

// 服务器同意浏览器发送 cookie

Access-Control-Allow-Credentials: true

// 指定预检请求的有效期是 20 天,期间不必再次发送另一个预检请求

Access-Control-Max-Age:1728000

Content-Type: text/html; charset=utf-8

Keep-Alive: timeout=2, max=100

// 长连接

Connection: Keep-Alive

Content-Type: text/plain

接着浏览器会像简单请求一样,发送一个 CORS 请求,请求头中一定包含 Origin 属性,服务器的响

应头中也一定得包含 Access-Control-Allow-Origin 属性。

3 代理方式

跨域限制是浏览器的同源策略导致的,使用 nginx 当做服务器访问别的服务的 HTTP 接口是不需要

执行 JS 脚步不存在同源策略限制的,所以可以利用 Nginx 创建一个代理服务器,这个代理服务器的

域名跟浏览器要访问的域名一致,然后通过这个代理服务器修改 cookie 中的域名为要访问的 HTTP

接口的域名,通过反向代理实现跨域。

Nginx 的配置信息:

server {

# 代理服务器的端口

listen 88;

# 代理服务器的域名

server_name http://127.0.0.1;

location / {

# 反向代理服务器的域名+端口

proxy_pass http://127.0.0.2:89;

# 修改cookie里域名

proxy_cookie_domain http://127.0.0.2 http://127.0.0.1;

index index.html index.htm;

# 设置当前代理服务器允许浏览器跨域

add_header Access-Control-Allow-Origin http://127.0.0.1;

# 设置当前代理服务器允许浏览器发送 cookie

add_header Access-Control-Allow-Credentials true;

阿里内部资料前端代码:

14TCP 为什么要三次握手,两次不行吗?为什么?

CP 客户端和服务端建立连接需要三次握手,首先服务端需要开启监听,等待客户端的连接请

求,这个时候服务端处于“收听”状态;

客户端向服务端发起连接,选择 seq=x 的初始序列号,此时客户端处于“同步已发送”的状态;

服务端收到客户端的连接请求,同意连接并向客户端发送确认,确认号是 ack=x+1 表示客户

端可以发送下一个数据包序号从 x+1 开始,同时选择 seq=y 的初始序列号,此时服务端处

于“同步收到”状态;

客户端收到服务端的确认后,向服务端发送确认信息,确认号是 ack=y+1 表示服务端可以发

送下一个数据包序号从 y+1 开始,此时客户端处于“已建立连接”的状态;

服务端收到客户端的确认后,也进入“已建立连接”的状态。

从三次握手的过程可以看出如果只有两次握手,那么客户端的起始序列号可以确认,服务端的起始

序列号将得不到确认。

}

}

var xhr = new XMLHttpRequest();

// 设置浏览器允许发送 cookie

xhr.withCredentials = true;

// 访问 nginx 代理服务器

xhr.open('get', 'http://127.0.0.1:88', true);

xhr.send();

阿里内部资料15,说一下 TCP 粘包是怎么产生的?怎么解决粘包问题的?

上文中讲 TCP 和 UDP 区别的时候提到 TCP 传输数据基于字节流,从应用层到 TCP 传输层的多个数

据包是一连串的字节流是没有边界的,而且 TCP 首部并没有记录数据包的长度,所以 TCP 传输数

据的时候可能会发送粘包和拆包的问题;而 UDP 是基于数据报传输数据的,UDP 首部也记录了数

据报的长度,可以轻易的区分出不同的数据包的边界。

阿里内部资料造成粘包和拆包现象的原因:

TCP 发送缓冲区剩余空间不足以发送一个完整的数据包,将发生拆包;

要发送的数据超过了最大报文长度的限制,TCP 传输数据时进行拆包;

要发送的数据包小于 TCP 发送缓冲区剩余空间,TCP 将多个数据包写满发送缓冲区一次发送出

去,将发生粘包;

接收端没有及时读取 TCP 发送缓冲区中的数据包,将会发生粘包。

粘包拆包的解决方法:

发送端给数据包添加首部,首部中添加数据包的长度属性,这样接收端通过首部中的长度字段

就可以知道数据包的实际长度啦;

针对发送的数据包小于缓冲区大小的情况,发送端可以将不同的数据包规定成同样的长度,不

足这个长度的补充 0,接收端从缓冲区读取固定的长度数据这样就可以区分不同的数据包;

发送端通过给不同的数据包添加间隔符合确定边界,接收端通过这个间隔符合就可以区分不同

的数据包。

阿里内部资料16HTTP1.0HTTP1.1HTTP2.0的关系和区别

一,对比

二、HTTP1.0

浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连

接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。

三、HTTP1.1

HTTP/1.0中默认使用Connection: close。在HTTP/1.1中已经默认使用Connection: keep-alive,避

免了连接建立和释放的开销,但服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保

证客户端能够区分出每次请求的响应内容。通过Content-Length字段来判断当前请求的数据是否已

经全部接收。不允许同时存在两个并行的响应。

四、HTTP2.0

HTTP/2引入二进制数据帧和流的概念,其中帧对数据进行顺序标识,如下图所示,这样浏览器收到

数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况。同样是因为有了

序列,服务器就可以并行的传输数据,这就是流所做的事情。

流(stream)

已建立连接上的双向字节流 消息 与逻辑消息对应的完整的一系列数据帧 帧 HTTP2.0

通信的最小单位,每个帧包含帧头部,至少也会标识出当前帧所属的流(stream id)。 多路复

用:

1、所有的HTTP2.0通信都在一个TCP连接上完成,这个连接可以承载任意数量的双向数据流。

2、每个数据流以消息的形式发送,而消息由一或多个帧组成。这些帧可以乱序发送,然后再根据

每个帧头部的流标识符(stream id)重新组装。

阿里内部资料举个例子,每个请求是一个数据流,数据流以消息的方式发送,而消息又分为多个帧,帧头部记录

着stream id用来标识所属的数据流,不同属的帧可以在连接中随机混杂在一起。接收方可以根据

stream id将帧再归属到各自不同的请求当中去。

3、另外,多路复用(连接共享)可能会导致关键请求被阻塞。HTTP2.0里每个数据流都可以设置优

先级和依赖,优先级高的数据流会被服务器优先处理和返回给客户端,数据流还可以依赖其他的子

数据流。

4、可见,HTTP2.0实现了真正的并行传输,它能够在一个TCP上进行任意数量HTTP请求。而这个

强大的功能则是基于“二进制分帧”的特性。

头部压缩

在HTTP1.x中,头部元数据都是以纯文本的形式发送的,通常会给每个请求增加500~800字节的负

荷。

HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fifields表,

既避免了重复header的传输,又减小了需要传输的大小。高效的压缩算法可以很大的压缩

header,减少发送包的数量从而降低延迟。

服务器推送:

服务器除了对最初请求的响应外,服务器还可以额外的向客户端推送资源,而无需客户端明确的请

求。

17,说说HTTP协议与TCP/IP协议的关系

HTTP的长连接和短连接本质上是TCP长连接和短连接。

HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议。

IP协议主要解决网络路由和寻址问题,

TCP协议主要解决如何在IP层之上可靠地传递数据包,使得网络上接收端收到发送端所发出的所有

包,并且顺序与发送顺序一致。TCP协议是可靠的、面向连接的。

18,如何理解HTTP协议是无状态的?

HTTP协议是无状态的,指的是协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。

也就是说,打开一个服务器上的网页和上一次打开这个服务器上的网页之间没有任何联系。HTTP是

一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是

UDP协议(无连接)。

19,什么是长连接和短连接?

阿里内部资料在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连

接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的

Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重

新建立一个HTTP会话。

而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加

入这行代码:

Connection:keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连

接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会

永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现

长连接需要客户端和服务端都支持长连接。

HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。

20,长连接和短连接的优缺点?

长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间 。对于频繁请求资源的客户来

说,较适用长连接。不过这里存在一个问题,存活功能的探测周期太长,还有就是它只是探测TCP

连接的存活,属于比较斯文的做法,遇到恶意的连接时,保活功能就不够使了。在长连接的应用场

景下,client端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的

话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需

要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可 以避免一些恶意连接导致

server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接

数,这样可以完全避免某个蛋疼的客户端连累后端服务。

短连接对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如

果客户请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽。

21,说说长连接短连接的操作过程

短连接的操作步骤是:建立连接——数据传输——关闭连接...建立连接——数据传输——关闭连

接长连接的操作步骤是:建立连接——数据传输...(保持连接)...数据传输——关闭连接

22,说说TCP三次握手和四次挥手的全过程

三次握手

阿里内部资料第一次握手:客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二

次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包

(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的

SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入

ESTABLISHED状态,完成三次握手。 握手过程中传送的包里不包含数据,三次握手完毕后,客户端

与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关

闭连接之前,TCP 连接都将被一直保持下去。

四次挥手

与建立连接的“三次握手”类似,断开一个TCP连接则需要“四次握手”。 第一次挥手:主动关闭方发送

一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不

会再给你发数据了(当然,在fifin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关

闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。 第二次挥手:被动关闭方收

到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序

号)。 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也

就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。 第四次挥手:主动关闭方收到

FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

23OSI 的七层模型都有哪些?

OSI(Open System Interconnection)开放系统互连参考模型是国际标准化组织(ISO)制定的一

个用于计算机或通信系统间互联的标准体系。

应用层:各种应用程序协议,比如 HTTP、HTTPS、FTP、SOCKS 安全套接字协议、DNS 域名

系统、GDP 网关发现协议等等。

表示层:加密解密、转换翻译、压缩解压缩,比如 LPP 轻量级表示协议。

会话层:不同机器上的用户建立和管理会话,比如 SSL 安全套接字层协议、TLS 传输层安全协

议、RPC 远程过程调用协议等等。

传输层:接受上一层的数据,在必要的时候对数据进行分割,并将这些数据交给网络层,保证

这些数据段有效到达对端,比如 TCP 传输控制协议、UDP 数据报协议。

网络层:控制子网的运行:逻辑编址、分组传输、路由选择,比如 IP、IPV6、SLIP 等等。

数据链路层:物理寻址,同时将原始比特流转变为逻辑传输路线,比如 XTP 压缩传输协议、

PPTP 点对点隧道协议等等。

物理层:机械、电子、定时接口通信信道上的原始比特流传输,比如 IEEE802.2 等等。

阿里内部资料24OSI这样分层有什么好处?

OSI分层的好处可以从五个方面讲:

1. 人们可以很容易的讨论和学习协议的规范细节。

2. 层间的标准接口方便了工程模块化。

3. 创建了一个更好的互连环境。

4. 降低了复杂度,使程序更容易修改,产品开发的速度更快。

5. 每层利用紧邻的下层服务,更容易记住个层的功能。

25、说说TCP/IP四层网络模型

TCP/IP分层模型(TCP/IP Layening Model)被称作因特网分层模型(Internet Layering Model)、因

特网参考模型(Internet Reference Model)。下图表示了TCP/IP分层模型的四层。

阿里内部资料TCP/IP协议被组织成四个概念层,其中有三层对应于ISO参考模型中的相应层。ICP/IP协议族并不包

含物理层和数据链路层,因此它不能独立完成整个计算机网络系统的功能,必须与许多其他的协议

协同工作。 TCP/IP分层模型的四个协议层分别完成以下的功能:

第一层 网络接口层

网络接口层包括用于协作IP数据在已有网络介质上传输的协议。

协议:ARP,RARP

第二层 网间层

网间层对应于OSI七层参考模型的网络层。负责数据的包装、寻址和路由。同时还包含网间控制报

文协议(Internet Control Message Protocol,ICMP)用来提供网络诊断信息。

协议:本层包含IP协议、RIP协议(Routing Information Protocol,路由信息协议),ICMP协议。

第三层 传输层

传输层对应于OSI七层参考模型的传输层,它提供两种端到端的通信服务。

其中TCP协议(Transmission Control Protocol)提供可靠的数据流运输服务,UDP协议(Use

Datagram Protocol)提供不可靠的用户数据报服务。

第四层 应用层

应用层对应于OSI七层参考模型的应用层和表达层。

阿里内部资料因特网的应用层协议包括Finger、Whois、FTP(文件传输协议)、Gopher、HTTP(超文本传输协

议)、Telent(远程终端协议)、SMTP(简单邮件传送协议)、IRC(因特网中继会话)、NNTP(网络新闻

传输协议)等。

26、说说域名解析详细过程?

1. 浏览器访问 www.baidu.com,询问本地 DNS 服务器是否缓存了该网址解析后的 IP 地址。

2. 如果本地 DNS 服务器没有缓存的话,就去 root-servers.net 根服务器查询该网址对应的 IP 地

址。

3. 根服务器返回顶级域名服务器的网址 gtld-servers.net,然后本地 DNS 服务器去顶级域名服务

器查询该网址对应的 IP 地址。

4. 顶级域名服务器返回 www.baidu.com 主区域服务器的地址,然后本地 DNS 服务器去 www.ba

idu.com 主区域服务器查询此域名对应的 IP 地址。

5. 本地 DNS 服务器拿到 www.baidu.com 解析后的 IP 地址后,缓存起来以便备查,然后把解析

后的 IP 地址返回给浏览器。

27 IP 地址分为几类,每类都代表什么,私网是哪些?

大致上分为公共地址和私有地址两大类,公共地址可以在外网中随意访问,私有地址只能在内网访

问只有通过代理服务器才可以和外网通信。

公共地址:

1.0.0.1~126.255.255.254

128.0.0.1~191.255.255.254

192.0.0.1~223.255.255.254

224.0.0.1~239.255.255.254

240.0.0.1~255.255.255.254

私有地址:

10.0.0.0~10.255.255.255

172.16.0.0~172.31.255.255

192.168.0.0~192.168.255.255

0.0.0.0 路由器转发使用

127.x.x.x 保留

255.255.255.255 局域网下的广播地址

28、说说TCP 如何保证可靠性的?

阿里内部资料序列号和确认号机制:

TCP 发送端发送数据包的时候会选择一个 seq 序列号,接收端收到数据包后会检测数据包的完整

性,如果检测通过会响应一个 ack 确认号表示收到了数据包。

超时重发机制:

TCP 发送端发送了数据包后会启动一个定时器,如果一定时间没有收到接受端的确认后,将会重新

发送该数据包。

对乱序数据包重新排序:

从 IP 网络层传输到 TCP 层的数据包可能会乱序,TCP 层会对数据包重新排序再发给应用层。

丢弃重复数据:

从 IP 网络层传输到 TCP 层的数据包可能会重复,TCP 层会丢弃重复的数据包。

流量控制:

TCP 发送端和接收端都有一个固定大小的缓冲空间,为了防止发送端发送数据的速度太快导致接收

端缓冲区溢出,发送端只能发送接收端可以接纳的数据,为了达到这种控制效果,TCP 用了流量控

制协议(可变大小的滑动窗口协议)来实现。

设计模式

阿里内部资料设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它

不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方

案。 1

阿里内部资料1995 年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的

基础》一书,共收录了 23 种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF设计模

式」。

通常面试中会问:

说一下你知道哪些设计模式?

这时候,就得需要平时积累下来的经验了,肯定回答自己会的,你只是知道名词是没用用的。从难

易程度和常用情况来看可以这么回答:

单例模式、代理模式、模板方法模式、装饰器模式、工厂模式、责任链模式、观察者模式、原型模

式。

通常你能回答这么多就已经ok了。但是其他模式,可以适当的了解了解,不然面试官问你还有其他

设计模式吗?

这时候,你就可以回答名词了,他再问,你就说这些设计模式只是了解过,在工作中用的不是很

多。

1、说说什么是单例模式

答:单例模式是一种常用的软件设计模式,在应用这个模式时,单例对象的类必须保证只有一个实

例存在,整个系统只能使用一个对象实例。

优点:不会频繁地创建和销毁对象,浪费系统资源。

可能这会需要你手写一个单例模式,这就得自己去学了,因为单例模式有很多种写法,懒汉模式,

饿汉模式,双重检查模式等。懒汉模式就是用的时候再去创建对象,饿汉模式就是提前就已经加载

好的静态static对象,双重检查模式就是两次检查避免多线程造成创建了多个对象。

单例模式有很多种的写法,我总结一下:

(1)饿汉式单例模式的写法:线程安全

(2)懒汉式单例模式的写法:非线程安全

(3)双检锁单例模式的写法:线程安全

2、说说你对代理模式的理解

代理模式是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

优点

代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;

可以灵活地隐藏被代理对象的部分功能和服务,也增加额外的功能和服务。

阿里内部资料缺点

由于使用了代理模式,因此程序的性能没有直接调用性能高;

使用代理模式提高了代码的复杂度。

黄牛卖火车票:没有流行网络购票的年代是很喜欢找黄牛买火车票的,因为工作忙的原因,没时间

去买票,然后就托黄牛给你买张回家过年的火车票。这个过程中黄牛就是代理人,火车票就是被代

理的对象。

婚姻介绍所:婚姻介绍所的工作人员,搜集单身人士信息,婚介所的工作人员为这个单身人士找对

象,这个过程也是代理模式的生活案例。对象就是被代理的对象。

注意了,问代理模式的时候,很有可能会问:动态代理。在Spring篇中已经讲述过,如果你把动态

代理讲了后,很有可能还会问什么是静态代理?一个洞一个是静,大致也能才出来,就是中间代理

层使我们手动写的,通常说的代理模式就是静态代理。

3、说说工厂模式

答:简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类,对实现了同一接口的一些类进行

实例的创建。比如,一台咖啡机就可以理解为一个工厂模式,你只需要按下想喝的咖啡品类的按钮

(摩卡或拿铁),它就会给你生产一杯相应的咖啡,你不需要管它内部的具体实现,只要告诉它你

的需求即可。

优点

工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除

直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分

割,它提供了专门的工厂类用于创建对象;

客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于

一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;

通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一

定程度上提高了系统的灵活性。

缺点

不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑;

产品类型较多时,工厂的创建逻辑可能过于复杂,一旦出错可能造成所有产品的创建失败,不

利于系统的维护。

4、抽象工厂模式

答:抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让

子类去做决定。

阿里内部资料比如,以上面的咖啡工厂为例,某天我的口味突然变了,不想喝咖啡了想喝啤酒,这个时候如果直

接修改简单工厂里面的代码,这种做法不但不够优雅,也不符合软件设计的“开闭原则”,因为每次

新增品类都要修改原来的代码。这个时候就可以使用抽象工厂类了,抽象工厂里只声明方法,具体

的实现交给子类(子工厂)去实现,这个时候再有新增品类的需求,只需要新创建代码即可。

5、装饰器模式是什么

答:装饰器模式是指动态地给一个对象增加一些额外的功能,同时又不改变其结构。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模

式可以动态扩展一个实现类的功能。

装饰器模式的关键:装饰器中使用了被装饰的对象。

比如,创建一个对象“laowang”,给对象添加不同的装饰,穿上夹克、戴上帽子......,这个执行过程

就是装饰者模式。

一句名言:人靠衣裳马靠鞍。都是装饰器模式的生活案列。

6、代理模式和装饰器模式有什么区别?

答:都是结构型模式,代理模式重在访问权限的控制,而装饰器模式重在功能的加强。

7、模板方法模式

答:模板方法模式是指定义一个算法骨架,将具体内容延迟到子类去实现。

优点

提高代码复用性:将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中;

实现了反向控制:通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,

实现了反向控制并且符合开闭原则。

喝茶茶:烧水----放入茶叶---喝茶。放入的茶叶每个人自己的喜好不一样,有的是普洱、有的是铁观

音等。

每日工作:上班打卡----工作---下班打卡。每个人工作的内容不一样,后端开发的、前端开发、测

试、产品每个人的工作内容不一样。

8、知道享元模式吗?

答:顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可

变对象。

阿里内部资料具体来讲,当一个系统中存在大量重复对象的时候,如果这些重复的对象是不可变对象,我们就可

以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用。这样可以减少内

存中对象的数量,起到节省内存的目的。

典型的使用场景:Integer中cache,就是享元模式很经典的实现。

怎么看起来享元模式和单例模式是一毛一样的?面试官很有可能会继续问:

9、享元模式和单例模式的区别?

答:单例模式是创建型模式,重在只能有一个对象。而享元模式是结构型模式,重在节约内存使

用,提升程序性能。

享元模式:把一个或者多可对象霍村起来,用的时候,直接从缓存里获取。也就是说享元模式不一

定只有一个对象。

10、说说策略模式在我们生活的场景?

答:策略模式是指定义一系列算法,将每个算法都封装起来,并且使他们之间可以相互替换。

优点:遵循了开闭原则,扩展性良好。

缺点:随着策略的增加,对外暴露越来越多。

条条大路通罗马,条条大路通北京。

我们去北京的交通方式(策略)很多,比如说坐飞机、坐高铁、自己开车等方式。每一种方式就可

以理解为每一种策略。

这就是生活中的策略模式。

11、知道责任链模式吗?

答:是行为型设计模式之一,其将链中每一个节点看作是一个对象,每个节点处理的请求均不同,

且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给

每一个节点对象,直至有对象处理这个请求为止。

优点

解耦了请求与处理;

请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直

接转发给下一级节点对象;

具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果;

链路结构灵活,可以通过改变链路结构动态地新增或删减责任;

易于扩展新的请求处理类(节点),符合 开闭原则;

缺点

阿里内部资料责任链路过长时,可能对请求传递处理效率有影响;

如果节点对象存在循环引用时,会造成死循环,导致系统崩溃;

生活案列:我们在公司内部发起一个OA审批流程,项目经理审批、部门经理审批。老板审批、人力

审批。这就是生活中的责任链模式,每个角色的责任是不同。

SpringMVC中的拦截器和Mybatis中的插件机制,都是拦截器经典实现。

12、了解过适配器模式么?

答:适配器模式是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而无

法一起工作的两个类能够在一起工作。

优点

可以让两个没有关联的类一起运行,起着中间转换的作用;

灵活性好,不会破坏原有的系统。

缺点:过多地使用适配器,容易使代码结构混乱,如明明看到调用的是 A 接口,内部调用的却是 B

接口的实现。

生活中的插座,为了适应各种插头,然后上面有两个孔的,三个空的,基本都能适应。还有万能充

电器、USB接口等。这些都是生活中的适配器模式。

13、知道观察者模式吗?

答:观察者模式是定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关

依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模

型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模

式。 优点

观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了

更新接口,使得可以有各种各样不同的表示层作为具体观察者角色;

观察者模式在观察目标和观察者之间建立一个抽象的耦合;

观察者模式支持广播通信;

观察者模式符合开闭原则(对拓展开放,对修改关闭)的要求。

缺点

如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多

时间;

如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能

导致系统崩溃;

观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知

道观察目标发生了变化。

阿里内部资料在观察者模式中有如下角色:

Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每

个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象;

ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在

具体主题的内部状态发生改变时,给所有注册过的观察者发送通知;

Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改

通知时更新自己;

ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知

时更新自身的状态。

在Spring中大量的使用的观察者模式,只要看到是以Event结尾或者Publish开头的基本上都是观察

者模式。

上面一共说了11种设计模式,这些设计模式能应对绝大多数人和面试场景来说。建议私下自己用代

码实现一番,便于更好地理解。

maven

1、什么是maven

maven主要服务于基于java平台的项目构建,依赖管理和项目信息管理。

maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理

工具软件。它包含了一个项目对象模型,一组标准集合,一个项目生命周期,一个依赖管理系统和

用来运行定义在生命周期阶段中插件目标的逻辑。当使用Maven的时候,你用一个明确定义的项目

对象模型来描述你的项目,然后Maven可以应用横切的逻辑,这些逻辑来自于一组共享的(或自定

义的)插件。

2Maven能为我们解决什么问题?

①添加第三方jar包

按照最原始的做法,我们是手动复制jar包到项目WEB-INF/lib下,每个项目都会有一份,造成大量

重复文件。而Maven将jar包放在本地仓库中统一管理,需要jar包只需要用坐标的方式引用即可。

②jar包之间的依赖关系

jar包之间往往不是独立的,很多jar需要在其他jar包的支持下才能够正常工作,称为jar包之间的依

赖关系。如果我们手动去导入,要知道jar包之间的依赖关系并一一导入是及其麻烦而且容易出错

的。如果使用Maven,它能够将当前jar包所依赖的其他所有jar包全部导入。

③获取第三方jar包

阿里内部资料开发过程中我们需要用到很多jar包,每个jar包在官网获取的方式不尽相同,给工作带来了额外困

难。但是使用Maven可以以坐标的方式依赖一个jar包,Maven从中央仓库进行下载,并同时下载这

个jar包依赖的其他jar包。

④将项目拆分为多个工程模块

项目的规模越来越大,已经不可能通过package结构来划分模块,必须将项目拆分为多个工程协同

开发。

3、说说maven有什么优缺点?

优点

简化了项目依赖管理

易于上手,对于新手来说了解几个常用命令即可满足日常工作

便于与持续集成工具(jenkins)整合

便于项目升级,无论是项目本身还是项目使用的依赖

maven有很多插件,便于功能扩展,比如生产站点,自动发布版本等

为什么使用Maven中的各点

缺点

Maven是一个庞大的构建系统,学习难度大。(很多都可以这样说,入门容易[优点]但是精通

难[缺点])

Maven采用约定约定优于配置的策略,虽然上手容易但是一旦出现问题,难于调试中网络环境

较差,很多repository无法访问

5、什么是Maven的坐标?

Maven其中一个核心的作用就是管理项目的依赖,引入我们所需的各种jar包等。为了能自动化的解

析任何一个Java构件,Maven必须将这些Jar包或者其他资源进行唯一标识,这是管理项目的依赖的

基础,也就是我们要说的坐标。包括我们自己开发的项目,也是要通过坐标进行唯一标识的,这样

才能才其它项目中进行依赖引用。

maven的坐标通过groupId,artifactId,version唯一标志一个构件。groupId通常为公司或组织名

字,artifactId通常为项目名称,versionId为版本号。

6、讲一下maven的生命周期

Maven的 生命周期:从我们的项目构建,一直到项目发布的这个过程。

每个阶段的说明:

阿里内部资料7、说说你熟悉哪些maven命令?

mvn archetype:generate 创建Maven项目

mvn compile 编译源代码

mvn deploy 发布项目

mvn test-compile 编译测试源代码

mvn test 运行应用程序中的单元测试

mvn site 生成项目相关信息的网站

mvn clean 清除项目目录中的生成结果

mvn package 根据项目生成的jar

mvn install 在本地Repository中安装jar

mvn eclipse:eclipse 生成eclipse项目文件

mvnjetty:run 启动jetty服务

mvntomcat:run 启动tomcat服务

mvn clean package -Dmaven.test.skip=true:清除以前的包后重新打包,跳过测试类

8、如何解决依赖传递引起的版本冲突?

可通过dependency的exclusion元素排除掉依赖。

9、说说maven的依赖原则

最短路径原则(依赖传递的路径越短越优先)

pom文件申明顺序优先(路径长度一样,则先申明的优先)

阿里内部资料覆写原则(当前pom文件里申明的直接覆盖父工程传过来的)

10、说说依赖的解析机制?

当依赖的范围是 system 的时候,Maven 直接从本地文件系统中解析构件。

根据依赖坐标计算仓库路径,尝试直接从本地仓库寻找构件,如果发现对应的构件,就解析成功。

如果在本地仓库不存在相应的构件,就遍历所有的远程仓库,发现后,下载并解析使用。

如果依赖的版本是 RELEASE 或 LATEST,就基于更新策略读取所有远程仓库的元数据文件

(groupId/artifactId/maven-metadata.xml),将其与本地仓库的对应元合并后,计算出

RELEASE 或者 LATEST 真实的值,然后基于该值检查本地仓库,或者从远程仓库下载。

如果依赖的版本是 SNAPSHOT,就基于更新策略读取所有远程仓库的元数据文件,将它与本地仓库

对应的元数据合并,得到最新快照版本的值,然后根据该值检查本地仓库,或从远程仓库下载。

如果最后解析得到的构件版本包含有时间戳,先将该文件下载下来,再将文件名中时间戳信息删

除,剩下 SNAPSHOT 并使用(以非时间戳的形式使用)。

11、说说插件的解析机制

与依赖的构件一样,插件也是基于坐标保存在Maven仓库中。在用到插件的时候会先从本地仓库查

找插件,如果本地仓库没有则从远程仓库查找插件并下载到本地仓库。与普通的依赖构件不同的

是,Maven会区别对待普通依赖的远程仓库与插件的远程仓库。前面提到的配置远程仓库只会对普

通的依赖有效果。当Maven需要的插件在本地仓库不存在时是不会去我们以前配置的远程仓库查找

插件的,而是需要有专门的插件远程仓库。

ElasticSearch

1、谈谈分词与倒排索引的原理

首先说分词是给检索用的。

英文:一个单词一个词,很简单。I am a student,词与词之间空格分隔。

中文:我是学生,就不能一个字一个字地分,我-是-学生。这是好分的。还有歧义的,使用户

放心,使用-户,使-用户。人很容易看出,机器就难多了。所以市面上有各种各样的分词器,

一个强调的效率一个强调的准确率。

倒排索引:倒排针对的是正排。

1. 正排就是我记得我电脑有个文档,讲了 ES 的常见问题总结。那么我就找到文档,从上往下翻

页,找到 ES 的部分。通过文档找文档内容。

阿里内部资料2. 倒排:一个 txt 文件 ES 的常见问题 -> D:/分布式问题总结.doc。

所以倒排就是文档内容找文档。当然内容不是全部的,否则也不需要找文档了,内容就是几个分词

而已。这里的 txt 就是搜索引擎。

2、说说分段存储的思想

Lucene 是著名的搜索开源软件,ElasticSearch 和 Solr 底层用的都是它。

分段存储是 Lucene 的思想。

早期,都是一个整个文档建立一个大的倒排索引。简单,快速,但是问题随之而来。

文档有个很小的改动,整个索引需要重新建立,速度慢,成本高,为了提高速度,定期更新那么时

效性就差。

现在一个索引文件,拆分为多个子文件,每个子文件是段。修改的数据不影响的段不必做处理。

3、谈谈你对段合并的策略思想的认识

分段的思想大大的提高了维护索引的效率。但是随之就有了新的问题。

每次新增数据就会新增加一个段,时间久了,一个文档对应的段非常多。段多了,也就影响检索性

能了。

检索过程:

1. 查询所有短中满足条件的数据

2. 对每个段的结果集合并

所以,定期的对段进行合理是很必要的。真是天下大势,分久必合合久必分。

策略:将段按大小排列分组,大到一定程度的不参与合并。小的组内合并。整体维持在一个合理的

大小范围。当然这个大到底应该是多少,是用户可配置的。这也符合设计的思想。

4、了解文本相似度 TF-IDF

简单地说,就是你检索一个词,匹配出来的文章,网页太多了。比如 1000 个,这些内容再该怎么

呈现,哪些在前面哪些在后面。这需要也有个对匹配度的评分。

TF-IDF 就是干这个的。

TF = Term Frequency 词频,一个词在这个文档中出现的频率。值越大,说明这文档越匹配,

正向指标。

IDF = Inverse Document Frequency 反向文档频率,简单点说就是一个词在所有文档中都出

现,那么这个词不重要。比如“的、了、我、好”这些词所有文档都出现,对检索毫无帮助。反

向指标。

阿里内部资料TF-IDF = TF / IDF

复杂的公式,就不写了,主要理解他的思想即可。

5、能说说ElasticSearch 写索引的逻辑吗?

ElasticSearch 是集群的 = 主分片 + 副本分片。

写索引只能写主分片,然后主分片同步到副本分片上。但主分片不是固定的,可能网络原因,之前

还是 Node1 是主分片,后来就变成了 Node2 经过选举成了主分片了。

客户端如何知道哪个是主分片呢?

看下面过程。

1. 客户端向某个节点 NodeX 发送写请求

2. NodeX 通过文档信息,请求会转发到主分片的节点上

3. 主分片处理完,通知到副本分片同步数据,向 Nodex 发送成功信息。

4. Nodex 将处理结果返回给客户端。

6、熟悉ElasticSearch 集群中搜索数据的过程吗?

1. 客户端向集群发送请求,集群随机选择一个 NodeX 处理这次请求。

2. Nodex 先计算文档在哪个主分片上,比如是主分片 A,它有三个副本 A1,A2,A3。那么请求

会轮询三个副本中的一个完成请求。

3. 如果无法确认分片,比如检索的不是一个文档,就遍历所有分片。

补充一点,一个节点的存储量是有限的,于是有了分片的概念。但是分片可能有丢失,于是有了副

本的概念。

比如:

ES 集群有 3 个分片,分片 A、分片 B、分片 C,那么分片 A + 分片 B + 分片 C = 所有数据,每个分

片只有大概 1/3。分片 A 又有副本 A1 A2 A3,数据都是一样的。

7、了解ElasticSearch 深翻页的问题及解决吗?

深翻页:比如我们检索一次,轮询所有分片,汇集结果,根据 TF-IDF 等算法打分,排序后将前 10

条数据返回。用户感觉不错,说我看看下一页。ES 依然是轮询所有分片,汇集结果,根据 TF-IDF

等算法打分,排序后将前 11-20 条数据返回。

对用户来说,翻页应该很快啊,但是实际上,第一次检索多复杂,下一次检索就多复杂。

解决的话,可以把用户的检索结果,存入 Redis 中 10 分钟。这样分页就很快,超过 10 分钟,用户

不翻页,也就不会翻页了,数据就可以清除了。

8、熟悉ElasticSearch 性能优化

阿里内部资料1. 批量提交

背景是大量的写操作,每次提交都是一次网络开销。网络永久是优化要考虑的重点。

2. 优化硬盘

索引文件需要落地硬盘,段的思想又带来了更多的小文件,磁盘 IO 是 ES 的性能瓶颈。一个固态硬

盘比普通硬盘好太多。

3. 减少副本数量

副本可以保证集群的可用性,但是严重影响了 写索引的效率。写索引时不只完成写入索引,还要完

成索引到副本的同步。ES 不是存储引擎,不要考虑数据丢失,性能更重要。 如果是批量导入,建

议就关闭副本。

9ElasticSearch 查询优化手段有哪些?

设计阶段调优

(1)根据业务增量需求,采取基于日期模板创建索引,通过 roll over API 滚动索引;

(2)使用别名进行索引管理;

(3)每天凌晨定时对索引做 force_merge 操作,以释放空间;

(4)采取冷热分离机制,热数据存储到 SSD,提高检索效率;冷数据定期进行 shrink操作,以缩

减存储;

(5)采取 curator 进行索引的生命周期管理;

(6)仅针对需要分词的字段,合理的设置分词器;

(7)Mapping 阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。……..

写入调优

(1)写入前副本数设置为 0;

(2)写入前关闭 refresh_interval 设置为-1,禁用刷新机制;

(3)写入过程中:采取 bulk 批量写入;

(4)写入后恢复副本数和刷新间隔;

(5)尽量使用自动生成的 id。

查询调优

(1)禁用 wildcard;

(2)禁用批量 terms(成百上千的场景);

阿里内部资料(3)充分利用倒排索引机制,能 keyword 类型尽量 keyword;

(4)数据量大时候,可以先基于时间敲定索引再检索;

(5)设置合理的路由机制。

其他调优

部署调优,业务调优等。

上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。

10elasticsearch 是如何实现 master 选举的?

面试官:想了解 ES 集群的底层原理,不再只关注业务层面了。

前置前提:

(1)只有候选主节点(master:true)的节点才能成为主节点。

(2)最小主节点数(min_master_nodes)的目的是防止脑裂。

核对了一下代码,核心入口为 fifindMaster,选择主节点成功返回对应 Master,否则返回 null。选

举流程大致描述如下:

第一步:确认候选主节点数达标,elasticsearch.yml 设置的值

discovery.zen.minimum_master_nodes;

第二步:比较:先判定是否具备 master 资格,具备候选主节点资格的优先返回;

若两节点都为候选主节点,则 id 小的值会主节点。注意这里的 id 为 string 类型。

题外话:获取节点 id 的方法。

GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name

ip port heapPercent heapMax id name

11elasticsearch 索引数据多了怎么办,如何调优,部署?

面试官:想了解大数据量的运维能力。

解答:索引数据的规划,应在前期做好规划,正所谓“设计先行,编码在后”,这样才能有效的避免

突如其来的数据激增导致集群处理能力不足引发的线上客户检索或者其他业务受到影响。

如何调优:

动态索引层面

阿里内部资料基于模板+时间+rollover api 滚动创建索引,举例:设计阶段定义:blog 索引的模板格式为:

blog_index_时间戳的形式,每天递增数据。这样做的好处:不至于数据量激增导致单个索引数据量

非常大,接近于上线 2 的32 次幂-1,索引存储达到了 TB+甚至更大。

一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑+及早避免。

存储层面

冷热数据分离存储,热数据(比如最近 3 天或者一周的数据),其余为冷数据。

对于冷数据不会再写入新数据,可以考虑定期 force_merge 加 shrink 压缩操作,节省存储空间和

检索效率。

部署层面

一旦之前没有规划,这里就属于应急策略。

结合 ES 自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主

节点等规划合理,不需要重启集群也能完成动态新增的。

12、说说你们公司 es 的集群架构,索引数据大小,分片有多少?

面试官:想了解应聘者之前公司接触的 ES 使用场景、规模,有没有做过比较大规模的索引设计、

规划、调优。

解答:如实结合自己的实践场景回答即可。

比如:ES 集群架构 13 个节点,索引根据通道不同共 20+索引,根据日期,每日递增 20+,索引:

10 分片,每日递增 1 亿+数据,每个通道每天索引大小控制:150GB 之内。

13、什么是ElasticSearch

Elasticsearch是一个基于Lucene的搜索引擎。它提供了具有HTTP Web和无架构JSON文档的分布

式,多租户能力的全文搜索引擎。Elasticsearch是用Java开发的,根据[Apache]许可条款作为开源

发布。

14ElasticSearch中的集群、节点、索引、文档、类型是什么?

群集是一个或多个节点(服务器)的集合,它们共同保存您的整个数据,并提供跨所有节点的

联合索引和搜索功能。群集由唯一名称标识,默认情况下为“elasticsearch”。此名称很重要,

因为如果节点设置为按名称加入群集,则该节点只能是群集的一部分。

节点是属于集群一部分的单个服务器。它存储数据并参与群集索引和搜索功能。

索引就像关系数据库中的“数据库”。它有一个定义多种类型的映射。索引是逻辑名称空间,映

射到一个或多个主分片,并且可以有零个或多个副本分片。 MySQL =>数据库 ElasticSearch

=>索引

阿里内部资料文档类似于关系数据库中的一行。不同之处在于索引中的每个文档可以具有不同的结构(字

段),但是对于通用字段应该具有相同的数据类型。 MySQL => Databases => Tables =>

Columns / Rows ElasticSearch => Indices => Types =>具有属性的文档

类型是索引的逻辑类别/分区,其语义完全取决于用户。

15ElasticSearch中的分片是什么?

在大多数环境中,每个节点都在单独的盒子或虚拟机上运行。

索引 - 在Elasticsearch中,索引是文档的集合。

分片 -因为Elasticsearch是一个分布式搜索引擎,所以索引通常被分割成分布在多个节点上的

被称为分片的元素。

阿里内部资料16ElasticSearch中的副本是什么?

一个索引被分解成碎片以便于分发和扩展。副本是分片的副本。一个节点是一个属于一个集群的

ElasticSearch的运行实例。一个集群由一个或多个共享相同集群名称的节点组成。

19ElasticSearch中的分析器是什么?

在ElasticSearch中索引数据时,数据由为索引定义的Analyzer在内部进行转换。 分析器由一个

Tokenizer和零个或多个TokenFilter组成。编译器可以在一个或多个CharFilter之前。分析模块允许

您在逻辑名称下注册分析器,然后可以在映射定义或某些API中引用它们。

Elasticsearch附带了许多可以随时使用的预建分析器。或者,您可以组合内置的字符过滤器,编译

器和过滤器器来创建自定义分析器。

20,什么是ElasticSearch中的编译器?

阿里内部资料编译器用于将字符串分解为术语或标记流。一个简单的编译器可能会将字符串拆分为任何遇到空格

或标点的地方。Elasticsearch有许多内置标记器,可用于构建自定义分析器。

21,什么是ElasticSearch中的过滤器?

数据由Tokenizer处理后,在编制索引之前,过滤器会对其进行处理。

22,启用属性,索引和存储的用途是什么?

enabled属性适用于各类ElasticSearch特定/创建领域,如index和size。用户提供的字段没有“已启

用”属性。 存储意味着数据由Lucene存储,如果询问,将返回这些数据。

存储字段不一定是可搜索的。默认情况下,字段不存储,但源文件是完整的。因为您希望使用默认

值(这是有意义的),所以不要设置store属性 该指数属性用于搜索。

索引属性只能用于搜索。只有索引域可以进行搜索。差异的原因是在分析期间对索引字段进行了转

换,因此如果需要的话,您不能检索原始数据。

tomcat

1Tomcat的缺省端口是多少,怎么修改?

默认端口为8080,可以通过在tomcat安装包conf目录下,service.xml中的Connector元素的port

属性来修改端口。

阿里内部资料2tomcat 有哪几种Connector 运行模式(优化)

这三种模式的不同之处如下:

BIO :一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。Tomcat7版本或更低

版本中,在Linux系统中默认使用这种方式。

NIO :利用Java的异步IO处理,可以通过少量的线程处理大量的请求。tomcat8.0.x中默认使用的是

NIO。Tomcat7必须修改Connector配置来启动:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"

connectionTimeout="20000" redirectPort="8443"/>

APR :即Apache Portable Runtime,从操作系统层面解决io阻塞问题。Tomcat7或Tomcat8在

Win7或以上的系统中启动默认使用这种方式。

3Tomcat有几种部署方式?

利用Tomcat的自动部署:把web应用拷贝到webapps目录(生产环境不建议放在该目录

中)。Tomcat在启动时会加载目录下的应用,并将编译后的结果放入work目录下。

使用Manager App控制台部署:在tomcat主页点击“Manager App” 进入应用管理控制台,可

以指定一个web应用的路径或war文件。

修改 conf/server.xml 文件部署:在 server.xml 文件中,增加Context节点可以部署应用。

增加自定义的Web部署文件:在 conf/Catalina/localhost/ 路径下增加 xyz.xml文件,内容是

Context节点,可以部署应用。

4tomcat容器是如何创建servlet类实例?用到了什么原理?

1. 当容器启动时,会读取在webapps目录下所有的web应用中的web.xml文件,然后对 xml文件

进行解析,并读取servlet注册信息。然后,将每个应用中注册的servlet类都进行加载,并通过

反射的方式实例化。(有时候也是在第一次请求时实例化)

2. 在servlet注册时加上1如果为正数,则在一开始就实例化,如果不写或为负数,则第一次请求

实例化。

5tomcat 如何优化?

tomcat作为Web服务器,它的处理性能直接关系到用户体验,下面是几种常见的优化措施:

掉对web.xml的监视,把jsp提前编辑成Servlet。有富余物理内存的情况,加大tomcat使用的jvm的

内存

服务器所能提供CPU、内存、硬盘的性能对处理能力有决定性影响。

对于高并发情况下会有大量的运算,那么CPU的速度会直接影响到处理速度。

阿里内部资料内存在大量数据处理的情况下,将会有较大的内存容量需求,可以用-Xmx -Xms -

XX:MaxPermSize等参数对内存不同功能块进行划分。我们之前就遇到过内存分配不足,导致

虚拟机一直处于full GC,从而导致处理能力严重下降。

硬盘主要问题就是读写性能,当大量文件进行读写时,磁盘极容易成为性能瓶颈。最好的办法

还是利用下面提到的缓存。

利用缓存和压缩

对于静态页面最好是能够缓存起来,这样就不必每次从磁盘上读。这里我们采用了Nginx作为

缓存服务器,将图片、css、js文件都进行了缓存,有效的减少了后端tomcat的访问。

另外,为了能加快网络传输速度,开启gzip压缩也是必不可少的。但考虑到tomcat已经需要处

理很多东西了,所以把这个压缩的工作就交给前端的Nginx来完成。

除了文本可以用gzip压缩,其实很多图片也可以用图像处理工具预先进行压缩,找到一个平衡

点可以让画质损失很小而文件可以减小很多。曾经我就见过一个图片从300多kb压缩到几十

kb,自己几乎看不出来区别。

采用集群

单个服务器性能总是有限的,最好的办法自然是实现横向扩展,那么组建tomcat集群是有效提升性

能的手段。我们还是采用了Nginx来作为请求分流的服务器,后端多个tomcat共享session来协同工

作。可以参考之前写的《利用nginx+tomcat+memcached组建web服务器负载均衡》。

优化线程数优化

找到Connector port="8080" protocol="HTTP/1.1",增加maxThreads和acceptCount属性(使

acceptCount大于等于maxThreads),如下:

<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"

redirectPort="8443"acceptCount="500" maxThreads="400" />

其中:

• maxThreads:tomcat可用于请求处理的最大线程数,默认是200

• minSpareThreads:tomcat初始线程数,即最小空闲线程数

• maxSpareThreads:tomcat最大空闲线程数,超过的会被关闭

• acceptCount:当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过

这个数的请求将不予处理.默认100

使用线程池优化

在server.xml中增加executor节点,然后配置connector的executor属性,如下:

<Executor name="tomcatThreadPool" namePrefix="req-exec-"maxThreads="1000"

minSpareThreads="50"maxIdleTime="60000"/>

<Connector port="8080" protocol="HTTP/1.1"executor="tomcatThreadPool"/>

阿里内部资料其中:

• namePrefix:线程池中线程的命名前缀

• maxThreads:线程池的最大线程数

• minSpareThreads:线程池的最小空闲线程数

• maxIdleTime:超过最小空闲线程数时,多的线程会等待这个时间长度,然后关闭

• threadPriority:线程优先级

注:当tomcat并发用户量大的时候,单个jvm进程确实可能打开过多的文件句柄,这时会报

java.net.SocketException:Too many open fifiles错误。可使用下面步骤检查:

• ps -ef |grep tomcat 查看tomcat的进程ID,记录ID号,假设进程ID为10001

• lsof -p 10001|wc -l 查看当前进程id为10001的 文件操作数

• 使用命令:ulimit -a 查看每个用户允许打开的最大文件数

启动速度优化

删除没用的web应用:因为tomcat启动每次都会部署这些应用。

关闭WebSocket: websocket-api.jar和tomcat-websocket.jar 。

随机数优化:设置JVM参数: -Djava.security.egd=file:/dev/./urandom 。

内存优化

因为tomcat启动起来后就是一个java进程,所以这块可以参照JVM部分的优化思路。堆内存相关参

数,比如说:

• -Xms:虚拟机初始化时的最小堆内存。

• -Xmx:虚拟机可使用的最大堆内存。-Xms与-Xmx设成一样的值,避免JVM因为频繁的GC导致性

能大起大落

• -XX:MaxNewSize:新生代占整个堆内存的最大值。

另外还有方法区参数调整(注意:JDK版本)、垃圾收集器等优化。JVM相关参数请看:手把手教你

设置JVM调优参数

6、熟悉tomcat的哪些配置?

Context (表示一个web应用程序,通常为WAR文件,关于WAR的具体信息见servlet规范)标签。

docBase :该web应用的文档基准目录(Document Base,也称为Context Root),或者是WAR

文件的路径。可以使绝对路径,也可以使用相对于context所属的Host的appBase路径。

path :表示此web应用程序的url的前缀,这样请求的url为 http://localhost:8080/path/**** 。

阿里内部资料reloadable :这个属性非常重要,如果为true,则tomcat会自动检测应用程序的/WEB-INF/lib

和/WEB-INF/classes目录的变化,自动装载新的应用程序,我们可以在不重启tomcat的情况下改变

应用程序。

useNaming :如果希望Catalina为该web应用使能一个JNDI InitialContext对象,设为true。该

InitialialContext符合J2EE平台的约定,缺省值为true。

workDir :Context提供的临时目录的路径,用于servlet的临时读/写。利用

javax.servlet.context.tempdir属性,servlet可以访问该目录。如果没有指定,使用

$CATALINA_HOME/work下一个合适的目录。

swallowOutput :如果该值为true,System.out和System.err的输出被重定向到web应用的

logger。如果没有指定,缺省值为false

debug :与这个Engine关联的Logger记录的调试信息的详细程度。数字越大,输出越详细。如果没

有指定,缺省为0。

host (表示一个虚拟主机)标签。

name :指定主机名。

appBase :应用程序基本目录,即存放应用程序的目录。

unpackWARs :如果为true,则tomcat会自动将WAR文件解压,否则不解压,直接从WAR文件中运

行应用程序。

Logger (表示日志,调试和错误信息)标签。

className :指定logger使用的类名,此类必须实现org.apache.catalina.Logger接口。

prefix :指定log文件的前缀。

suffix :指定log文件的后缀。

timestamp :如果为true,则log文件名中要加入时间,如下例:localhost_log.2001-10-04.txt。

7Tomcat是什么?

Tomcat 服务器Apache软件基金会项目中的一个核心项目,是一个免费的开放源代码的Web 应用服

务器(Servlet容器),属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被

普遍使用,是开发和调试JSP 程序的首选。

8,什么是Servlet呢?

阿里内部资料Servlet是JavaEE规范的一种,主要是为了扩展Java作为Web服务的功能,统一接口。由其他内部厂

商如tomcat,jetty内部实现web的功能。如一个http请求到来:容器将请求封装为servlet中的

HttpServletRequest对象,调用init(),service()等方法输出response,由容器包装为httpresponse

返回给客户端的过程。

9,什么是Servlet规范?

从 Jar 包上来说,Servlet 规范就是两个 Jar 文件。servlet-api.jar 和 jsp-api.jar,Jsp 也是一种

Servlet。

从package上来说,就是 javax.servlet 和 javax.servlet.http 两个包。

从接口来说,就是规范了 Servlet 接口、Filter 接口、Listener 接口、ServletRequest 接口、

ServletResponse 接口等。类图如下:

阿里内部资料10、为什么我们将tomcat称为Web容器或者Servlet容器 ?

我们用一张图来表示他们之间的关系:

简单的理解:启动一个ServerSocket,监听8080端口。Servlet容器用来装我们开发的Servlet。

11tomcat是如何处理Http请求流程的?

假设来我们在浏览器上输入

http://localhost:8080/my-web-mave/index.jsp

在tomcat中是如何处理这个请求流程的:

1. 我们的请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得。

2. Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应 。

阿里内部资料3. Engine获得请求localhost/my-web-maven/index.jsp,匹配它所拥有的所有虚拟主机Host ,

我们的虚拟主机在server.xml中默认配置的就是localhost。

4. Engine匹配到name=localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host

被定义为该Engine的默认主机)。

5. localhost Host获得请求/my-web-maven/index.jsp,匹配它所拥有的所有Context。

6. Host匹配到路径为/my-web-maven的Context(如果匹配不到就把该请求交给路径名为”"的

Context去处理)。

7. path=”/my-web-maven”的Context获得请求/index.jsp,在它的mapping table中寻找对应的

servlet 。

8. Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类。

9. 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet

或doPost方法 。

10. Context把执行完了之后的HttpServletResponse对象返回给Host 。

11. Host把HttpServletResponse对象返回给Engine 。

12. Engine把HttpServletResponse对象返回给Connector 。

13. Connector把HttpServletResponse对象返回给客户browser 。

12tomcat结构目录有哪些?

bin

启动,关闭和其他脚本。这些 .sh文件(对于Unix系统)是这些.bat文件的功能副本(对于

Windows系统)。由于Win32命令行缺少某些功能,因此此处包含一些其他文件。

比如说:windows下启动tomcat用的是startup.bat,另外Linux环境中使用的是startup.sh。对应

还有相应的shutdown关闭脚本。

conf

tomcat的配置文件和相关的DTD。这里最重要的文件是server.xml。它是容器的主要配置文件。

catalina.policy :tomcat:安全策略文件,控制JVM相关权限,具体可以参考

java.security.Permission。

阿里内部资料catalina.properties :tomcat Catalina 行为控制配置文件,比如:Common ClassLoader。

logging.properties :tomcat日志配置文件。里面的日志采用的是JDK Logging。

server.xml :tomcat server配置文件(对于我开发人员来说是非常重要)。

context.xml :全局context配置文件,监视并加载资源文件,当监视的文件发生发生变化时,自

动加载 。

tomcat-user.xml :tomcat角色配置文件。

web.xml :Servlet标准的web.xml部署文件,tomcat默认实现部分配置 入内:

org.apache.catalina.servlets.DefaultServlet。

org.apache.jasper.servlet.JspServlet

logs

日志文件默认位于此处。

localhost 有用,当你们的tomcat启动不了的时候,多看这个文件。比如:

NoClassDefFoundError

ClassNotFoundException

access 最没用。

catalina.{date} 主要是控制台输出,全部日志都在这里面。

webapps

这是您的webapp所在的位置。其实这里面这几个都是一个项目。

简化web部署的方式。在线上环境中我们的应用是不会放在这里的。最好的办法就是外置。

lib:tomcat存放共用的类库。比如:

ecj-4.17.jar: eclipse Java编译器

jasper.jar:JSP编译器。

work

存放tomcat运行时编译后的文件,比如JSP编译后的文件 。

temp

存放运行时产生的临时文件。

Git

阿里内部资料Git

SVN

1. Git是一个分布式的版本控制工具

1. SVN 是集中版本控制工具

2.它属于第3代版本控制工具

2.它属于第2代版本控制工具

3.客户端可以在其本地系统上克隆整个存储库

3.版本历史记录存储在服务器端存储库中

4.即使离线也可以提交

4.只允许在线提交

5.Push/pull 操作更快

5.Push/pull 操作较慢

6.工程可以用 commit 自动共享

6.没有任何东西自动共享

1GitSVN有什么区别?

2、什么是Git

我建议你先通过了解 git 的架构再来回答这个问题,如下图所示,试着解释一下这个图:

Git 是分布式版本控制系统(DVCS)。它可以跟踪文件的更改,并允许你恢复到任何特定版本

的更改。

与 SVN 等其他版本控制系统(VCS)相比,其分布式架构具有许多优势,一个主要优点是它不

依赖于中央服务器来存储项目文件的所有版本。

每个开发人员都可以“克隆”我在图中用“Local repository”标注的存储库的副本,并且在他的硬

盘驱动器上具有项目的完整历史记录,因此当服务器中断时,你需要的所有恢复数据都在你队

友的本地 Git 存储库中。

还有一个中央云存储库,开发人员可以向其提交更改,并与其他团队成员进行共享,如图所

示,所有协作者都在提交更改“远程存储库”。

3、在 Git 中提交的命令是什么?

阿里内部资料答案非常简单。 用于写入提交的命令是 git commit -a

现在解释一下 -a 标志,

通过在命令行上加 -a 指示 git 提交已修改的所有被跟踪文件的新内容。

还要提一下,如果你是第一次需要提交新文件,可以在在 git commit -a 之前先 git add

4、什么是 Git 中的裸存储库

你应该说明 “工作目录” 和 “裸存储库” 之间的区别。

Git 中的 “裸” 存储库只包含版本控制信息而没有工作文件(没有工作树),并且它不包含特殊的

.git 子目录。相反,它直接在主目录本身包含 .git 子目录中的所有内容,其中工作目录包括:

1. 一个 .git 子目录,其中包含你的仓库所有相关的 Git 修订历史记录。

2. 工作树,或签出的项目文件的副本。

5 Git 是用什么语言编写的?

你需要说明使用它的原因,而不仅仅是说出语言的名称。我建议你这样回答:

Git使用 C 语言编写。 GIT 很快,C 语言通过减少运行时的开销来做到这一点。

6、在Git中,你如何还原已经 push 并公开的提交?

There can be two answers to this question and make sure that you include both because any

of the below options can be used depending on the situation: 1 这个问题可以有两个答案,你

回答时也要保包含这两个答案,因为根据具体情况可以使用以下选项:

删除或修复新提交中的错误文件,并将其推送到远程存储库。这是修复错误的最自然方式。对

文件进行必要的修改后,将其提交到我将使用的远程存储库

git commit -m "commit message"

创建一个新的提交,撤消在错误提交中所做的所有更改。可以使用命令:

git revert <name of bad commit>

7git pull git fetch 有什么区别?

git pull 命令从中央存储库中提取特定分支的新更改或提交,并更新本地存储库中的目标分支。

git fetch 也用于相同的目的,但它的工作方式略有不同。当你执行 git fetch 时,它会从所需

的分支中提取所有新提交,并将其存储在本地存储库中的新分支中。如果要在目标分支中反映这些

更改,必须在 git fetch 之后执行 git merge 。只有在对目标分支和获取的分支进行合并后才会

更新目标分支。为了方便起见,请记住以下等式:

阿里内部资料git pull = git fetch + git merge

8git中的“staging area”“index”是什么?

For this answer try to explain the below diagram as you can see: 可以通过下图进行解释:

在完成提交之前,可以在称为“staging area”或“index”的中间区域中对其进行格式化和审查。从图

中可以看出,每个更改首先在暂存区域中进行验证,我将其称为“stage fifile”,然后将更改提交到存

储库。

9、什么是 git stash?

首先应该解释 git stash 的必要性。

阿里内部资料通常情况下,当你一直在处理项目的某一部分时,如果你想要在某个时候切换分支去处理其他事

情,事情会处于混乱的状态。问题是,你不想把完成了一半的工作的提交,以便你以后就可以回到

当前的工作。解决这个问题的答案是 git stash。

再解释什么是git stash。

stash 会将你的工作目录,即修改后的跟踪文件和暂存的更改保存在一堆未完成的更改中,你可以

随时重新应用这些更改。

10、什么是git stash drop

通过说明我们使用 git stash drop 的目的来回答这个问题。

git stash drop 命令用于删除隐藏的项目。默认情况下,它将删除最后添加的存储项,如果提供

参数的话,它还可以删除特定项。

下面举个例子。

如果要从隐藏项目列表中删除特定的存储项目,可以使用以下命令:

git stash list它将显示隐藏项目列表,如:

stash@{0}: WIP on master: 049d078 added the index fifile stash@{1}: WIP on master: c264051

Revert “added fifile_size” stash@{2}: WIP on master: 21d80a5 added number to log

如果要删除名为 stash@{0} 的项目,请使用命令 git stash drop stash@{0}

11.、如何找到特定提交中已更改的文件列表?

对于这个问题,不能仅仅是提供命令,还要解释这个命令究竟做了些什么。

要获取特定提交中已更改的列表文件,请使用以下命令:

git diffff-tree -r {hash}

给定提交哈希,这将列出在该提交中更改或添加的所有文件。 -r 标志使命令列出单个文件,而不

是仅将它们折叠到根目录名称中。

你还可以包括下面提到的内容,虽然它是可选的,但有助于给面试官留下深刻印象。

输出还将包含一些额外信息,可以通过包含两个标志把它们轻松的屏蔽掉:

git diffff-tree –no-commit-id –name-only -r {hash}

这里 -no-commit-id 将禁止提交哈希值出现在输出中,而 -name-only 只会打印文件名而不是它们

的路径。

12git confifig 的功能是什么?

阿里内部资料首先说明为什么我们需要 git config 。

git 使用你的用户名将提交与身份相关联。 git config 命令可用来更改你的 git 配置,包括你的用

户名。

下面用一个例子来解释。

假设你要提供用户名和电子邮件 ID 用来将提交与身份相关联,以便你可以知道是谁进行了特定提

交。为此,我将使用:

git confifig –global user.name "Your Name": 此命令将添加用户名。

git confifig –global user.email "Your E-mail Address": 此命令将添加电子邮件ID。

13、提交对象包含什么?

Commit 对象包含以下组件,你应该提到以下这三点:

一组文件,表示给定时间点的项目状态

引用父提交对象

SHAI 名称,一个40个字符的字符串,提交对象的唯一标识。

14、 如何在Git中创建存储库?

这可能是最常见的问题,答案很简单。

要创建存储库,先为项目创建一个目录(如果该目录不存在),然后运行命令 git init。通过运行此

命令,将在项目的目录中创建 .git 目录。

15、怎样将 N 次提交压缩成一次提交?

将N个提交压缩到单个提交中有两种方式:

如果要从头开始编写新的提交消息,请使用以下命令:

git reset –soft HEAD~N &&

git commit

如果你想在新的提交消息中串联现有的提交消息,那么需要提取这些消息并将它们传给 git

commit,可以这样:

git reset –soft HEAD~N &&

git commit –edit -m"$(git log –format=%B –reverse .HEAD@{N})"

阿里内部资料16、 什么是 Git bisect?如何使用它来确定(回归)错误的来

源?

我建议你先给出一个Git bisect 的小定义。

Git bisect 用于查找使用二进制搜索引入错误的提交。 Git bisect的命令是

git bisect <subcommand> <options>

既然你已经提到过上面的命令,那就解释一下这个命令会做什么。

此命令用了二进制搜索算法来查找项目历史记录中的哪个提交引入了错误。你可以通过告诉它已知

包含该错误的“错误”提交以及在引入错误之前已知的“良好”提交来使用它。然后 git bisect 在这两个

端点之间选择一个提交,并询问你所选的提交是“好”还是“坏”。它继续缩小范围,直到找到引入更改

的确切提交。

17、如果想要在提交之前运行代码性检查工具,并在测试失败时

阻止提交,该怎样配置 Git 存储库?

我建议你先介绍一下完整性检查。

完整性或冒烟测试用来确定继续测试是否可行和合理。

下面解释如何实现这一目标。

这可以通过与存储库的 pre-commit hook 相关的简单脚本来完成。git 会在提交之前触发 pre

commit hook。你可以在这个脚本中运行其他工具,例如 linters,并对提交到存储库中的更改执行

完整性检查。

最后举个例子,你可以参考下面的脚本:

#!/bin/sh

files=$(git diff –cached –name-only –diff-filter=ACM | grep ‘.go$’)

if [ -z files ]; then

exit 0

fi

unfmtd=$(gofmt -l $files)

if [ -z unfmtd ]; then

exit 0

fi

echo “Some .go files are not fmt’d”

exit 1

阿里内部资料这段脚本检查是否需要通过标准 Go 源代码格式化工具 gofmt 传递所有即将提交的 .go 文件。如果

脚步以非 0 状态退出,脚本会有效地阻止提交操作。

18.、描述一下你所使用的分支策略?

这个问题被要求用Git来测试你的分支经验,告诉他们你在以前的工作中如何使用分支以及它的用途

是什么,你可以参考以下提到的要点:

功能分支(Feature branching)

要素分支模型将特定要素的所有更改保留在分支内。当通过自动化测试对功能进行全面测试和

验证时,该分支将合并到主服务器中。

任务分支(Task branching)

在此模型中,每个任务都在其自己的分支上实现,任务键包含在分支名称中。很容易看出哪个

代码实现了哪个任务,只需在分支名称中查找任务键。

发布分支(Release branching)

一旦开发分支获得了足够的发布功能,你就可以克隆该分支来形成发布分支。创建该分支将会

启动下一个发布周期,所以在此之后不能再添加任何新功能,只有错误修复,文档生成和其他

面向发布的任务应该包含在此分支中。一旦准备好发布,该版本将合并到主服务器并标记版本

号。此外,它还应该再将自发布以来已经取得的进展合并回开发分支。

最后告诉他们分支策略因团队而异,所以我知道基本的分支操作,如删除、合并、检查分支等。

19、如果分支是否已合并为master,你可以通过什么手段知道?

答案很直接。

要知道某个分支是否已合并为master,你可以使用以下命令:

git branch –merged 它列出了已合并到当前分支的分支。

git branch –no-merged 它列出了尚未合并的分支。

20、 什么是SubGit

SubGit 是将 SVN 到 Git迁移的工具。它创建了一个可写的本地或远程 Subversion 存储库的 Git 镜

像,并且只要你愿意,可以随意使用 Subversion 和 Git。

这样做有很多优点,比如你可以从 Subversion 快速一次性导入到 Git 或者在 Atlassian Bitbucket

Server 中使用SubGit。我们可以用 SubGit 创建现有 Subversion 存储库的双向 Git-SVN 镜像。你

可以在方便时 push 到 Git 或提交 Subversion。同步由 SubGit 完成。

21、列举工作中常用的几个git命令?

阿里内部资料新增文件的命令:git add fifile或者git add . 提交文件的命令:git commit –m或者git commit –a 查

看工作区状况:git status –s 拉取合并远程分支的操作:git fetch/git merge或者git pull 查看提交

记录命令:git reflflog

22、如果本次提交误操作,如何撤销?

如果想撤销提交到索引区的文件,可以通过git reset HEAD fifile;如果想撤销提交到本地仓库的文

件,可以通过git reset –soft HEAD^n恢复当前分支的版本库至上一次提交的状态,索引区和工作

空间不变更;可以通过git reset –mixed HEAD^n恢复当前分支的版本库和索引区至上一次提交的

23、你使用过git stash命令吗?你一般什么情况下会使用它?

命令git stash是把工作区修改的内容存储在栈区。 以下几种情况会使用到它:

解决冲突文件时,会先执行git stash,然后解决冲突;

遇到紧急开发任务但目前任务不能提交时,会先执行git stash,然后进行紧急任务的开发,然

后通过git stash pop取出栈区的内容继续开发;

切换分支时,当前工作空间内容不能提交时,会先执行git stash再进行分支切换;

24、如何查看分支提交的历史记录?查看某个文件的历史记录

呢?

查看分支的提交历史记录:

命令git log –number:表示查看当前分支前number个详细的提交历史记录;

命令git log –number –pretty=oneline:在上个命令的基础上进行简化,只显示sha-1码和提交

信息;

命令git reflflog –number: 表示查看所有分支前number个简化的提交历史记录;

命令git reflflog –number –pretty=oneline:显示简化的信息历史信息;

如果要查看某文件的提交历史记录,直接在上面命令后面加上文件名即可。

注意:如果没有number则显示全部提交次数。

25、使用过git mergegit rebase吗?它们之间有什么区别?

简单的说,git merge和git rebase都是合并分支的命令。 git merge branch会把branch分支的差异

内容pull到本地,然后与本地分支的内容一并形成一个committer对象提交到主分支上,合并后的

分支与主分支一致; git rebase branch会把branch分支优先合并到主分支,然后把本地分支的

commit放到主分支后面,合并后的分支就好像从合并后主分支又拉了一个分支一样,本地分支本身

不会保留提交历史。

26、使用过git cherry-pick,有什么作用?

命令git cherry-pick可以把branch A的commit复制到branch B上。 在branch B上进行命令操作:

阿里内部资料复制单个提交:git cherry-pick commitId

复制多个提交:git cherry-pick commitId1…commitId3

注意:复制多个提交的命令不包含commitId1

软实力篇

本篇文章除了教大家用Markdown如何写一份程序员专属的简历,后面还会给大家推荐一些不错的

用来写Markdown简历的软件或者网站,以及如何优雅的将Markdown格式转变为PDF格式或者其

他格式。

推荐大家使用Markdown语法写简历,然后再将Markdown格式转换为PDF格式后进行简历投递。

如果你对Markdown语法不太了解的话,可以花半个小时简单看一下Markdown语法说明:

http://www.markdown.cn 。

1、为什么说简历很重要?

一份好的简历可以在整个申请面试以及面试过程中起到非常好的作用。 在不夸大自己能力的情况

下,写出一份好的简历也是一项很棒的能力。为什么说简历很重要呢?

2、先从面试来说

假如你是网申,你的简历必然会经过HR的筛选,一张简历HR可能也就花费10秒钟看一下,然后HR

就会决定你这一关是Fail还是Pass。

假如你是内推,如果你的简历没有什么优势的话,就算是内推你的人再用心,也无能为力。

另外,就算你通过了筛选,后面的面试中,面试官也会根据你的简历来判断你究竟是否值得他花费

很多时间去面试。

所以,简历就像是我们的一个门面一样,它在很大程度上决定了你能否进入到下一轮的面试中。

3、再从面试说起

我发现大家比较喜欢看面经 ,这点无可厚非,但是大部分面经都没告诉你很多问题都是在特定条件

下才问的。举个简单的例子:一般情况下你的简历上注明你会的东西才会被问到(Java、数据结

构、网络、算法这些基础是每个人必问的),比如写了你会 redis,那面试官就很大概率会问你 redis

的一些问题。比如:redis的常见数据类型及应用场景、redis是单线程为什么还这么快、 redis 和

memcached 的区别、redis 内存淘汰机制等等。

所以,首先,你要明确的一点是:你不会的东西就不要写在简历上。另外,你要考虑你该如何才能

让你的亮点在简历中凸显出来,比如:你在某某项目做了什么事情解决了什么问题(只要有项目就

一定有要解决的问题)、你的某一个项目里使用了什么技术后整体性能和并发量提升了很多等等。

阿里内部资料面试和工作是两回事,聪明的人会把面试官往自己擅长的领域领,其他人则被面试官牵着鼻子走。

虽说面试和工作是两回事,但是你要想要获得自己满意的 offffer ,你自身的实力必须要强。

4、必知必会的几点

大部分公司的HR都说我们不看重学历(骗你的!),但是如果你的学校不出众的话,很难在一堆简

历中脱颖而出,除非你的简历上有特别的亮点,比如:某某大厂的实习经历、获得了某某大赛的奖

等等。

大部分应届生找工作的硬伤是没有工作经验或实习经历,所以如果你是应届生就不要错过秋招和春

招。一旦错过,你后面就极大可能会面临社招,这个时候没有工作经验的你可能就会面临各种碰

壁,导致找不到一个好的工作

写在简历上的东西一定要慎重,这是面试官大量提问的地方;

将自己的项目经历完美的展示出来非常重要。

5、必须了解的两大法则

STAR法则(Situation Task Action Result

Situation

事情是在什么情况下发生;

Task:

你是如何明确你的任务的;

Action

针对这样的情况分析,你采用了什么行动方式;

Result

结果怎样,在这样的情况下你学习到了什么。

简而言之,STAR法则,就是一种讲述自己故事的方式,或者说,是一个清晰、条理的作文模板。不

管是什么,合理熟练运用此法则,可以轻松的对面试官描述事物的逻辑方式,表现出自己分析阐述

问题的清晰性、条理性和逻辑性。

FAB 法则(Feature Advantage Benefifit

Feature

是什么;

Advantage

比别人好在哪些地方;

Benefifit

如果雇佣你,招聘方会得到什么好处。

简单来说,这个法则主要是让你的面试官知道你的优势、招了你之后对公司有什么帮助。

6、项目经历怎么写

简历上有一两个项目经历很正常,但是真正能把项目经历很好的展示给面试官的非常少。对于项目

经历大家可以考虑从如下几点来写:

1. 对项目整体设计的一个感受

2. 在这个项目中你负责了什么、做了什么、担任了什么角色

3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用

阿里内部资料4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或

者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了

什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。

7、专业技能怎么写

先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛

选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几

天时间学习一下,然后在简历上可以写上自己了解这个技能。比如你可以这样写(下面这部分内容摘

自我的简历,大家可以根据自己的情况做一些修改和完善):

计算机网络、数据结构、算法、操作系统等课内基础知识:掌握

Java 基础知识:掌握

JVM 虚拟机(Java内存区域、虚拟机垃圾算法、虚拟垃圾收集器、JVM内存管理):掌握

高并发、高可用、高性能系统开发:掌握

Struts2、Spring、Hibernate、Ajax、Mybatis、JQuery :掌握

SSH 整合、SSM 整合、 SOA 架构:掌握

Dubbo:

掌握

Zookeeper: 掌握

常见消息队列: 掌握

Linux:掌握

MySQL常见优化手段:掌握

Spring Boot +Spring Cloud +Docker:了解

Hadoop 生态相关技术中的 HDFS、Storm、MapReduce、Hive、Hbase :了解

Python 基础、一些常见第三方库比如OpenCV、wxpy、wordcloud、matplotlib:熟悉

8、排版注意事项

1. 尽量简洁,不要太花里胡哨;

2. 一些技术名词不要弄错了大小写比如MySQL不要写成mysql,Java不要写成java。这个在我看

来还是比较忌讳的,所以一定要注意这个细节;

3. 中文和数字英文之间加上空格的话看起来会舒服一点;

9、其他一些小tips

1. 尽量避免主观表述,少一点语义模糊的形容词,尽量要简洁明了,逻辑结构清晰。

2. 如果自己有博客或者个人技术栈点的话,写上去会为你加分很多。

3. 如果自己的Github比较活跃的话,写上去也会为你加分很多。

4. 注意简历真实性,一定不要写自己不会的东西,或者带有欺骗性的内容

5. 项目经历建议以时间倒序排序,另外项目经历不在于多,而在于有亮点。

6. 如果内容过多的话,不需要非把内容压缩到一页,保持排版干净整洁就可以了。

阿里内部资料7. 简历最后最好能加上:

“感谢您花时间阅读我的简历,期待能有机会和您共事。”这句话,显的

你会很有礼貌。

10、你对我们公司有什么想问的吗?

背景

面试,是双方互相试探的一个过程。因此,不止求职者想了解面试官对咱的感观,面试官同样也想

听一下你对企业的看法。所以,在结束前,经常会被问到这样一个问题:

“你对公司有啥想法?

说实话,小编以前面试的时候,很怕被问到“对公司有什么想法?”/“你还有什么要问的?”/“你的职业

规划是什么?

”之类的问题。太假大空了,真心没意思。可没办法,面试官问了,咱总不能不答,于

是只能硬着头皮“胡邹乱噪”。顺利的时候还好,不顺的时候,经常被挑刺,从而失去即将到手的机

会。慢慢的,越来越认识到此类面试题的重要性,于是,总结出了一套应对方法,拿出来给大家分

享。那啥,仅供参考。

常规回答:谈公司的历史,产品

想必,绝大多数的求职者,在面试前会做准备功课。而对公司历史、产品的了解,则是必须掌握的

一项内容。如果你真的不知道该如何回答“你对公司有什么想法”这样的问题的话,不妨先说一说你

了解的公司概况,让面试官知道,你是有备而来,而不是来打酱油的。

进一步回答:说公司概况+个人规划

趋利避害,是每个人共同的特性。在面对不能很好掌控的面试题时,最好的办法,是换个角度,将

答案引向自己擅长的领域。在被问到上述问题是,你可以先阐述一下你所了解的公司情况,然后结

合一些内容,说说自己到岗后的规划,和所能展开的工作。比如能把工作做到什么样的程度,公司

会用什么形式来回报之类的东西,反正多谈谈自己真实的想法和目前的成就,保持平常心,只要努

力做些课前作业,肯定会给人家留下好印像的

参考答案

因为贵公司是在我印象中是理想的公司,并为我提供了就业的岗位,可以说,我是对公司的企业文

化建设及公司的经营情况有着比较客观的了解。员工的工资、收入稳定。公司的管理规范,很好的

后勤服务等都是不错的看点。给我感触最深的是:企业的各级管理人员都是那么的热情,给我感觉

就像家一样。我觉得在这样的公司工作是任何一个人都向往的!

11、很多人都倒在自我介绍上

案例一:如何把握自我介绍的时间?

研究生毕业的小刘很健谈,口才甚佳,对自我介绍,他自认为不在话下,所以他从来不准备,

看什么人说什么话。他的求职目标是地产策划,有一次,应聘本地一家大型房地产公司,在自我介

绍时,他大谈起了房地产行业的走向,由于跑题太远,面试官不得不把话题收回来。自我介绍也只

能“半途而止”。

阿里内部资料建议:一分钟谈一项内容

自我介绍的时间一般为3分钟,在时间的分配上,第一分钟可谈谈学历等个人基本情况,第二

分钟可谈谈工作经历,对于应届毕业生而言可谈相关的社会实践,第三分钟可谈对本职位的理想和

对于本行业的看法。如果自我介绍要求在1分钟内完成,自我介绍就要有所侧重,突出一点,不及

其余。

在实践中,有些应聘者不了解自我介绍的重要性,只是简短地介绍一下自己的姓名、身份,其

后补充一些有关自己的学历、工作经历等情况,大约半分钟左右就结束了自我介绍,然后望着考

官,等待下面的提问,这是相当不妥的,白白浪费了一次向面试官推荐自己的宝贵机会。而另一些

应聘者则试图将自己的全部经历都压缩在这几分钟内,这也是不明智的做法。合理地安排自我介绍

的时间,突出重点是首先要考虑的问题。

案例二:自我介绍要如何准备?

小芳去应聘南方某媒体,面试在一个大的办公室内进行,五人一小组,围绕话题自由讨论。面

试官要求每位应聘者先作自我介绍,小芳是第二位,与前面应聘者一句一顿的介绍不同,她早做了

准备,将大学四年里所干的事,写了一段话,还作了一些修饰,注重韵脚,听起来有些押韵。(职

场创业 www.lz13.cn)小芳的介绍极流利,但美中不足的是给人背诵的感觉。

建议:切勿采用背诵口吻

人力资源专家指出,自我介绍可以事前准备,也可以事前找些朋友做练习,但自我介绍应避免

书面语言的严整与拘束,而应使用灵活的口头语进行组织。切忌以背诵朗读的口吻介绍自己,如果

那样的话,对面试官来说,将是无法忍受的。自我介绍还要注意声线,尽量让声调听来流畅自然,

充满自信。

案例三:在自我介绍的时候如何谈成绩?

小王去应聘某电视节目制作机构的文案写作,面试时,对方首先让他谈谈相关的实践经历。小

王所学的专业虽说是新闻传播类,但偏向于纸质媒体,对电视节目制作这一块实践不多。怎么办?

小王只好将自己平时参加的一些校园活动说了一大通,听起来挺丰富,但几乎与电视沾不上边。

建议:只说与职位相关的优点

自我介绍时要投其所好摆成绩,这些成绩必须与现在应聘公司的业务性质有关。在面试中,你

不仅要告诉考官你是多么优秀的人,更要告诉考官,你如何地适合这个工作岗位。那些与面试无关

的内容,即使是你引以为荣的优点和长处,你也要忍痛舍弃。

在介绍成绩时,说的次序也极为重要,应该把你最想让面试官知道的事情放在前面,这样的事

情往往是你的得意之作,也可以让面试官留下深刻的印象。

案例四:在自我介绍的时候学会用点小技巧

阿里内部资料阿枫参加了去年某大型国企的校园招聘会,那天是在一个大体育场里进行,队伍排到了出口

处,每一位应聘者与面试官只有几分钟的交谈时间,如何在这么短的时间里,取得面试官的好感,

进入下一轮呢?阿枫放弃了常规的介绍,而是着重给面试官介绍自己完成的一个项目,他还引用了

导师的评价作为佐证。由于运用了一点小技巧,阿枫顺利闯过这种“海选”般的面试。

建议:以说真话为前提

自我介绍时,要突出个人的优点和特长,你可以使用一些小技巧,比如可以介绍自己做过什么

项目来验证具有某种能力,也可以适当引用别人的言论,如老师、朋友等的评论来支持自己的描

述。但无论使用哪种小技巧,都要坚持以事实说话,少用虚词、感叹词之类。自吹自擂一般是很难

逃过面试官的眼睛的。至于谈弱点时则要表现得坦然、乐观、自信。

案例五:自我介绍要如何摆脱怯场?

阿宏毕业于中部城市的某大学,带着憧憬南下广东。由于自己是一位专科生,在研究生成堆的

人才市场里,阿宏的自信心有点不足,面对面试官常常表现出怯场的情绪,有时很紧张,谈吐不自

然。他也明白这种情况不利于面试,但却找不到方法来调控自己。

建议:谈吐运用“3P原则

人力资源专家指出,自我介绍时的谈吐,应该记住“3P原则”:自信(Positive),个性

(Personal),中肯(Pertinent)。回答要沉着,突出个性,强调自己的专业与能力,语气中肯,

不要言过其实。

在自我介绍时要调适好自己的情绪,在介绍自己的基本情况时面无表情、语调生硬;在谈及优

点时眉飞色舞、兴奋不已;而在谈论缺点时无精打采、萎靡不振,这些都是不成熟的表现。对于表

达,建议阿宏可以找自己的朋友练习一下,也可以先对着镜子练习几遍,再去面试。

13,如何与 HR 交谈,如何谈薪水

谈薪资之前必须要先了解行情 知己知彼才能够百战百胜,所以在面试之前大家必须要了解清楚你应

聘的这个行业的薪资标准 是怎么样的。大家可以去各大招聘网站下看看你所应聘的工作岗位给出的

工资水平是怎么样 的。除了在招聘网站上了解你应聘的职位的薪资水平之外,大家也需要向一些做

这类工作的朋 友或者同学了解一下。了解清楚薪资的水平后你就不会在谈薪水的时候显得特别没底

气了。

要有底气不要害怕和 HR 聊薪资 谈薪资这个阶段在求职面试过程中不可避免,我们必须要有底气,

不要表现得畏畏缩缩的。要 记住只要你够专业,没有什么不好的表现,那么面试官就不会因为薪水

问题不给你 Offffer 的。 所以在谈薪资的时候要大胆一些,让对方看到你底气。就算最后HR真的没有

录用你也没有关 系,大不了就重新再找!谈薪是很考验大家的谈判技巧和心态的,大家千万别慌才

能够为自己 谋取到利益!

阿里内部资料谈薪资时千万别过早揭露底牌 谈薪过程中大家的底牌也不能过早揭露,因为一旦揭露了底牌那么你

就失去了主动权。陷入被 动的你很可能就会失去谈出高薪的机会!因此,你在面试的时候千万别过

早去跟 HR 去谈论薪 资问题,就算他一开始就问你对薪资的要求了你也应该委婉地转移话题。在不

确定公司对你很 感兴趣,很希望你能加入他们的时候过早揭露底牌其实是很吃亏的。

了解公司的薪酬体系再作评估 在 HR 问你对薪资的要求的时候大家不要急着给出自己的心理价格,

你可以先问一下贵公司的 薪酬体系是怎么样的,然后再结合自己的实际情况谈薪资。首先你需要根

据公司的薪资水平以 及其他的福利对你的心理价格进行再一次评估,最终给出合适的薪资区间。给

出薪资的区间大 家就要守住自己的底线,不要轻易做出退让了。

14HR 最喜欢问程序员的 20 个问题

以下整理出 HR 最喜欢问的 20 个问题,答案供大家思维发散,大家只需了解这些问题,提前想一

下,即可,就能在面试中不被打的措手不及。大家有疑问的,也可以在读者圈中提出,我可以进行

解答。

1. 请你自我介绍一下你自己?

2. 你对加班的看法?

3. 你对薪资的要求?

4. 你的职业规划?

5. 你还有什么问题要问吗?

6. 如果通过这次面试我们单位录用了你,但工作一段时间却发现你根本不适合这个职位,你怎么

办?

7. 在完成某项工作时,你认为领导要求的方式不是最好的,自己还有更好的方法,你应该怎么

做?

8. 如果你的工作出现失误,给本公司造成经济损失,你认为该怎么办?

9. 谈谈你对跳槽的看法?

10. 工作中你难以和同事、上司相处,你该怎么办?

11. 为什么要离职?

12. 对工作的期望与目标何在?

13. 就你申请的这个职位,你认为你还欠缺什么?

14. 你和别人发生过争执吗?你是怎样解决的?

15. 如果我录用你,你将怎样开展工作?

16. 如果你在这次面试中没有被录用,你怎么打算?

17. 谈谈如何适应办公室工作的新环境?

18. 工作中学习到了些什么?

19. 除了本公司外,还应聘了哪些公司?

20. 何时可以到职?

这些问题在面试之前,尤其是相对有点规模的公司,HR说话的分量蛮重的,所以建议把这些问题都

大致想想,如果面试中遇到如何应对。

阿里内部资料15、面试中的礼仪与举止

注意细节

平复一下紧张的情绪,然后从容地走进面试地点,轻轻敲一下门,得到允许后进 去,开关门动作要

轻柔缓和,面对面试官微笑主动打招呼示好,称呼得体,现在一般流行叫老 师,那么你可以称呼各

位老师好。不要急于落座,面试官示意你请坐的时候再道谢坐下,坐下 后身体保持挺直,不要显得

大大咧咧,满不在乎,避免引起对方的反感。面试过程中微笑并仔 细聆听,面试结束微笑起立,道

谢并再见。 谈话技巧

认真聆听对方的问题和介绍,适当点头示意或提问,回答问题时要口齿清晰、音量 适中、语言简

练、意思明确。切忌打断面试官的问话,或者跟面试官在某一问题上发生争执,

如果意见不统一可

保持沉默,切记不要急躁地与对方辩解,这样既浪费时间又浪费情绪。对于 某些自己不知道的问

题,可以如实回答,不要胡侃乱诌。让面试官纠缠于你不愿回答的问题 时,也不要表现得不耐烦,

保持自己应有的风度。 举止大方

不仅在语言方面能体现一个人的内在修养,举止大方得体,谦逊有礼也能体现出你 的品质修养。所

以在面试过程中,应有的姿态是举止文雅大方,谈吐谦虚谨慎,态度积极热 情。回答问题时,注视

对方的眼眸以示尊重。眼神要坚定自信,不要飘忽不定,否则会显得不 自信甚至轻浮,双方意见不

统一也不要情绪激动地与人争辩,要不卑不亢、从容不迫。如果是 某些特殊的岗位,不排除有人故

意这样试探,如果你情绪不对,那么有可能功亏一篑。 忌小动作

这一条应该是划分到上一条的,但是鉴于很多人下意识的行为,所以特意提出来。 很多人都有做小

动作的习惯,有些是刻意、有些是下意识的,心理紧张的时候,小动作会更 多。过多的小动作表明

你很紧张,也不自信,而且会干扰人的注意力,给人留下不好的印象。 比如挠头、搓手、挖鼻、跺

脚等。

java后端内部面试题相关推荐

  1. java后端工程师面试题(笔试):2022-11-04 经历(一)

    java后端工程师面试题(笔试):2022-11-04: 面试题:总分100 1.关于盒子模型(5分) 1)盒子模型的种类有几种?分别是什么?(1分) 2种,分别是1.W3C标准盒子模型 2.IE盒子 ...

  2. Java后端真实面试题大全(有详细答案)--高频/真题

    原文网址:Java后端真实面试题大全(有详细答案)--高频/真题_IT利刃出鞘的博客-CSDN博客 简介 说明 本文分享Java后端真实高频面试题,有详细答案,保你稳过面试.题目包括:Java基础.多 ...

  3. Java 面试必问题目,Java 后端校招面试题

    字节跳动一面: 自我介绍,主要讲讲做了什么和擅长什么 看你项目做 Spring 比较多, 问一下 Spring 相关的东西, IoC 是什么概念? Bean 的默认作用范围是什么?其他的作用范围? 索 ...

  4. 各大公司Java后端开发面试题总结

    ThreadLocal(线程变量副本) Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量. 采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一 ...

  5. 百度 Java 后端三轮面试题,这些你会吗?

    前面的话 告别了2018 ,也早已正式进入2019 面试一直都是大家关注的热门话题,俗话说"金三银四",如今已经一月份了,三月份还会远么,如果你打算在年后跳槽,那么是时候该着手准备 ...

  6. 大厂 Java 后端经典面试题:Redis 为什么这么快?

    前言 大家好呀,我们都知道 Redis 很快,它 QPS 可达 10 万(每秒请求数).Redis 为什么这么快呢,本文将跟大家一起学习. 基于内存实现 我们都知道内存读写是比磁盘读写快很多的.Red ...

  7. 面试题:各大公司Java后端开发面试题总结 已看1 背1 有用 链接有必要看看

    ThreadLocal(线程变量副本)       --整理 Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量. 采用空间换时间,它用于线程间的数据隔离,为每一个 ...

  8. java 1.8有没有jshell_收藏了800道Java后端经典面试题,分享给大家,希望你找到自己理想的Offer呀~...

    前言 在茫茫的互联网海洋中寻寻觅觅,我收藏了800+道Java经典面试题,分享给你们.建议大家收藏起来,在茶余饭后拿出来读一读,以备未雨绸缪之需.另外,面试题答案的话,我打算后面慢慢完善在github ...

  9. 收藏了800道Java后端经典面试题,共享给大家

    在茫茫的互联网海洋中寻寻觅觅,我收藏了800+道Java经典面试题,共享给你们.建议大家收藏起来,在茶余饭后拿出来读一读,以备未雨绸缪之需.另外,面试题答案的话,我打算后面慢慢完善在github, 希 ...

最新文章

  1. python解包的概念_Python学习第176课——tar解包和压缩
  2. VS Code前端开发利器-常用快捷键
  3. MATLAB二维数组的创建与元素提取
  4. matlab怎么复制相同的列,怎样将数组中某一列数据相同的行提取出来?
  5. bearer token头_接口认证方式:Bearer Token
  6. linux 删除压缩包_【干货】记住!这些 Linux 命令千万不要运行!
  7. 202007219 Oracle建表语句
  8. 计算机成绩英语翻译,本科成绩单翻译中英文对照
  9. matlab simulink电感,一文教你快速学会在matlab的simulink中调用C语言进行仿真
  10. 新手小白学JAVA_IDEA修改主题 设置背景图片
  11. mongodb java 安装配置_Mongodb的java学习安装部署
  12. 用类描述计算机CPU的速度和硬件的容量
  13. ​一文看尽MAE最新进展!恺明的MAE已经提出大半年,目前发展如何?
  14. MATLAB环境下基于振动信号的轴承状态监测和故障诊断
  15. 历届CSP真题题解-CSP刷真题之路
  16. return的作用,返回函数值和结束程序执行
  17. VBA基础知识整理(字典,自定义函数)
  18. 美国宾州计算机学校,美国留学,看看宾州有哪些顶尖学校?
  19. 企业wifi安全管家,贴身又暖心的wifi管理系统
  20. android 基站定位

热门文章

  1. 物联网充电桩(电动自行车)管理方案
  2. 工程项目建设数字化管理解决方案
  3. nag在逆向中是什么意思_[求助]关于NAG删除资源的问题。
  4. Selenium WebDriver下载安装
  5. Vue-cli搭建SPA项目
  6. 【cookbook pandas】学习笔记 chapter9 grouping,aggregation,filtration,and transformation
  7. C语言编程题:输入多个字符串,输出其中最短的字符串。
  8. 碎片化信息时代系统性学习
  9. MySql服务器忘记密码? 这几步轻松重置密码。
  10. IOS H5页面滑动过于频繁出现短暂白屏