就是八股文
容器
什么是docker
docker 是一个超轻量级的虚拟机,也是实现容器化技术的一种应用工具。Docker 是使用时下很火的Golang 语言进行开发的。
隔离的进程独立于宿主和其它的隔离进程,因此也被称为容器。
然后说说优势:
- 资源占用小,因为不需要硬件虚拟,也不需要运行完整操作系统额外的资源开销,比传统虚拟机内存消耗更小。
- 启动速度快,直接运行在宿主机上面。
- 迁移轻松,确保执行环境的一致性,测试环境和生产环境一致,避免环境问题。
- 持续交付和部署方便,通过定时应用镜像实现持续集成,持续交付、部署,开发人员直接通过dockerfile进行镜像构建就可以了。
再说说核心组件:
- 镜像:就是Linux的文件系统,包含完整的运行环境
- 容器:就是从镜像创建的运行实例,可以被启动、开始、停止、删除,每个容器相互隔离,保障数据不污染。
- 仓库:几种存放镜像文件的地方。
系统
CPU 飙高系统反应慢怎么排查?
先说:
- CPU 是整个电脑的核心计算资源,对于一个应用进程来说,CPU 的最小执行单元是线程。
- . 导致CPU 飙高的原因有几个方面
- . CPU 上下文切换过多,对于CPU 来说,同一时刻下每个CPU 核心只能运行一个线程,如果有多个线程要执行,CPU 只能通过上下文切换的方式来执行不同的线程。上下文切换需要做两个事情,一是:保存运行线程的执行状态,二是:让处于等待中的线程执行。
- CPU资源过度消耗,也就是在程序中创建了大量的线程,或者有线程一直占用CPU资源无法释放,比如死循环了。从而影响程序的执行效率
然后说解决方案:
- 通过top命令查看cpu利用率较高的进程,然后再找到进程中CPU消耗过高的线程
- CPU利用率过高的线程是同一个,说明这个线程长期占用CPU没有是否,可以通过获得线程的dump日志,定位日志后就可以找到问题的代码。
- CPU利用率过高的线程id不断变化,说明线程创建过多,也是需要定位线程id,定位dump日志,然后去代码中排查。
- 如果CPU只是某一个时段飙高,考虑是否是用户量访问大,导致系统资源不够。
IO 和NIO 有什么区别?
首先,I/O ,指的是IO 流, 它可以实现数据从磁盘中的读取以及写入。 实际上,除了磁盘以外,内存、网络都可以作为I/O 流的数据来源和目的地。
NIO,是JDK1.4 里面新增的一种NEW IO 机制,相比于传统的IO,NIO 在效率上做 了很大的优化,并且新增了几个核心组件。
Cookie 和Session 的区别?
Cookie,它是客户端浏览器用来保存服务端数据的一种机制。
当通过浏览器进行网页访问的时候,服务器可以把某一些状态数据以key-value 的方式写入到Cookie 里面存储到客户端浏览器。然后客户端下一次再访问服务器的时候,就可以携带这些状态数据发送到服务器端,服务端可以根据Cookie 里面携带的内容来识别使用者。
Session 表示一个会话,它是属于服务器端的容器对象,默认情况下,针对每一个浏览器的请求。
总的来看,Cookie 是客户端的存储机制,Session 是服务端的存储机制。
生产环境服务器变慢,如何诊断处理?
生产环境服务器处理效率变慢,我认为主要会涉及到三个纬度:
- CPU 的利用率
- 磁盘IO 效率
- 内存
CPU 利用率过高或者CPU 利用率过低,都会影响程序的处理效率。 利用率过高,说明当前服务器要处理的指令比较多,当CPU 忙不过来的时候,指令的运算效率自然就会下降。反馈在用户上的感受就是程序响应变慢了。针对这个问题,我们可以使用top 命令查询当前系统中占用CPU 过高的进程,以及定位到这个进程中比较活跃的线程。
程序运算过程中,会直接或者间接涉及到一些磁盘IO 相关的操作,比如程序直接读写磁盘,或者程序依赖的第三方组件涉及到磁盘的持久化存储,所以磁盘的IO 效率也会对程序运行效率产生影响。针对这个情况,可以使用iostat 命令查看,如果磁盘负载较高,可以针对性的进行优,如:借助缓存系统,减少磁盘IO次数,用顺序写代替随机写入等等。
内存的瓶颈,内存作为一块临时存储数据的组件,所有CPU 运算的指令都需要从内存中去读写。内存的合理使用,可以减少应用和磁盘的直接IO 频率,以及减少网络IO 的频率,极大提升IO 性能。
什么是IO 的多路复用机制?
IO 多路复用机制,核心思想是让单个线程去监视多个连接,一旦某个连接就绪,也就是触发了读/写事件。就通知应用程序,去获取这个就绪的连接进行读写操作。也就是在应用程序里面可以使用单个线程同时处理多个客户端连接,在对系统资源消耗较少的情况下提升服务端的链接处理数量。
为了避免Server 端在read 客户端数据过程中阻塞,服务端会把该请求注册到Selector复路器上,服务端此时不需要等待,只需要启动一个线程,通过selector.select()阻塞轮询复路器上就绪的channel 即可,也就是说,如果某个客户端连接数据传输完成,那么select()方法会返回就绪的channel,然后执行相关的处理就可以了。
常见的IO 多路复用机制的实现方式有: select 、poll、epoll。
这些都是Linux 系统提供的IO 复用机制的实现,其中select 和poll 是基于轮询的方式去获取就绪连接。
而epoll 是基于事件驱动的方式获取就绪连接。从性能的角度来看,基于事件驱动的方式要优于轮询的方式。
select 和epoll 的区别
它们的区别主要有几个方面: select 是基于轮询的机制,它需要遍历整个监听集合,直到找到就绪的文件描述符。
epoll 是基于事件通知的机制,它只需要遍历当前就绪的文件描述符集合,大大减少了遍历的次数和开销。
请你说一下你对服务降级的理解
服务降级是一种提升系统稳定性和可用性的策略。 服务降级其实就是降低服务的能力等级。在高并发流量下,因为系统资源有限,导致系统无法为高并发流量提供稳定可靠的支撑。所以我们可以把一些非核心服务下掉,或者提供一些默认的处理结果,把这些计算资源腾出来给到核心服务去使用。从而保证核心服务的稳定运行。 比如双十一的时候,那些确认收货等等周边功能就可以降级。
对称加密与非对称加密有什么区别
对称加密:指加密和解密使用同一密钥,优点是运算速度较快,常见的对称加密算法有:DES、AES 等
非对称加密:指的是加密和解密使用不同的密钥,也称为公钥和私钥。公钥与私钥是成对存在的,如果用公钥对数据进行加密,只有对应的私钥才能解密。反之,如果采用私钥加密,只能使用对应的公钥才能解密,RSA 是比较常见的非对称加密算法。
架构
什么是负载均衡?
先说负载均衡的背景:当单体架构无法满足高用户请求时,就会有集群部署架构,把软件分别部署在多个服务器上面,这样就会有问题,客户端如何均匀的发布到多态服务器上,如何检查目标服务器的健康,使客户端请求不向已经宕机的服务器发送情况。为了解决这个,引入了负载均衡。
目前负载均衡有三种实现方式:
基于DNS实现负载均衡
比较简单,只需要在DNS服务器针对某个域名做多个IP映射就可以了,DNS 还可以根据不同的地域分配就近机房的IP,配置简单,实现成本低,无序额外的开发和维护,但是DNS 多级缓存的特性,当我们修改DNS 配置之后,会因为缓存导致IP 变更不及时,从而影响负载均衡的效果。
基于软件实现负载均衡
比如Nginx,一般有轮询、随机、一致性hash等等算法。
请说一下你对分布式和微服务的理解
简单来说,分布式是一组通过网络进行通信,并且为了完成共同的计算任务的计算机节点组成的系统。分布式系统的设计理念,其实是来自于小型机或者大型机的计算能力的瓶颈和成本的增加。在集中式系统里面,要想提升程序的运行性能,只能不断的升级CPU 以及增加内存, 但是硬件的提升本身也是有瓶颈的,所以当企业对于计算要求越来越高的时候,集中式架构已经无法满足需求了。
在这样的背景下, 就产生了分布式计算,(如图),也就是把一个计算任务分配给多个计算机节点去运行。需要把原本的单体应用进行拆分,部署到多个计算机节点上,然后各个服务之间使用远程通信协议实现计算结果的数据交互。针对这种分布式部署的应用架构,我们称为SOA(面向服务)的架构。
微服务架构。其实微服务架构本身就是一种分布式架构,它强调的是对部署在各个计算机上的应用服务的粒度。
它的核心思想是,针对拆分的服务节点做更进一步的解耦。针对SOA 服务化架构下的单个业务服务,以更加细粒度的方式进一步拆分。拆分的好处是使得程序的扩展性更强,开发迭代效率更高。
什么是微服务,说一下你对微服务的理解?
可以回到单体到集群到分布式,最后到微服务。
微服务是一种架构风格,我们可以把应用程序划分为一组小型的、松散耦合的服务,每个服务都运行在自己的进程中,并通过轻量级的通信机制进行通信每个服务都是独立部署、独立扩展、独立更新的,从而提高了应用程序的可伸缩性、可维护性和可测试性由于微服务是属于分布式架构下的一种针对应用架构的一种设计风格。
网络
TCP 协议为什么要设计三次握手?
所谓的三次握手,就是通信双方一共需要发送三次请求,才能确保这个连接的建立。
- 客户端向服务端发送连接请求并携带同步序列号SYN。
- 服务端收到请求后,发送SYN 和ACK, 这里的SYN 表示服务端的同步序列号,ACK 表示对前面收到请求的一个确认,表示告诉客户端,我收到了你的请求。
- 客户端收到服务端的请求后,再次发送ACK,这个ACK 是针对服务端连接的一个确认,表示告诉服务端,我收到了你的请求。
之所以TCP 要设计三次握手,我认为有三个方面的原因:
TCP 是可靠性通信协议,所以TCP 协议的通信双方都必须要维护一个序列号,去标记已经发送出去的数据包,哪些是已经被对方签收的。而三次握手就是通信双方相互告知序列号的起始值,为了确保这个序列号被收到,所以双方都需要有一个确认的操作。
TCP 协议需要在一个不可靠的网络环境下实现可靠的数据传输,意味着通信双方必须要通过某种手段来实现一个可靠的数据传输通道,而三次通信是建立这样一个通道的最小值。当然还可以四次、五次,只是没必要浪费这个资源。
防止历史的重复连接初始化造成的混乱问题,比如说在网络比较差的情况下,客户端连续多次发送建立连接的请求,假设只有两次握手,那么服务端只能选择接受或者拒绝这个连接请求,但是服务端不知道这次请求是不是之前因为网络堵塞而过期的请求,也就是说服务端不知道当前客户端的连接是有效还是无效
请说一下网络四元组
四元组,简单理解就是在TCP 协议中,去确定一个客户端连接的组成要素,它包括源IP 地址、目标IP 地址、源端口号、目标端口号。
服务端通过ServerSocket 建立一个对指定端口号的监听,比如8080。客户端通过目标ip 和端口就可以和服务端建立一个连接,然后进行数据传输。
但一个Server 端可以接收多个客户端的连接,当多个客户端连接到服务端的时候,服务端需要去识别每一个连接。也就是说,当一个客户端和服务端建立一个TCP 连接的时候,通过源IP 地址、目标IP 地址、源端口号、目标端口号来确定一个唯一的TCP 连接。因为服务器的IP 和端口是不变的,只要客户端的IP 和端口彼此不同就OK 了。源端口号是每次建立连接的时候系统自动分配的。
RPC 和HTTP 协议有什么区别?
RPC 全称(Remote Procedure Call),它是一种针对跨进程或者跨网络节点的应用之间的远程过程调用协议。它的核心目标是,让开发人员在进行远程方法调用的时候,就像调用本地方法一样,不需要额外为了完成这个交互做过的编码。所以它有自己的协议、框架。
Http 协议是为Web 浏览器与Web 服务器之间的通信而设计的远程通信协议,它定义了通信协议的报文规范(如图),我们可以使用http 协议来实现跨网络节点的数据传输。
什么是拆包和粘包?怎么解决?
分析:
拆包和粘包是在网络编程中比较常见的现象。
因为TCP 协议底层是面向流的传输,所以数据在传输的过程中会被分割成一个个的数据包
接收端在接收数据时需要重新组装数据包,但是TCP 协议不保证数据包与应用层的数据交互一一对应,所以就可能会造成数据不完整的问题。
拆包指的是把一个完整的数据包拆分成多个小包进行发送。而接收端可能无法一次性接收到所有小包,导致接收到的数据不完整。
粘包指的是把多个数据包粘合在一起一次性发送,而接收端可能无法正确区分每个数据包,导致接收到的数据出现错位或混乱。
就是需要让服务端知道如何判断一个数据包的完整性,因此可以采用以下几种方法:
在数据包中添加特殊字符或特殊标记,表示一个数据包的开始和结尾
通过自定义消息协议,并在协议头中保存数据包的长度信息,接收方可以根据这个长度来解析数据包来保证消息的完整性
基于定长消息,也就是发送端的消息长度是固定的,服务端按照固定长度来解析