文章目录

  • 1. BIO 与 NIO 的区别
  • 2. select 与 poll 的区别
  • 3.请概述 OSI 网络模型
  • 4. TCP 和 UDP 的区别
  • 5.请概述 TCP 的三次握手四次挥手机制
  • 6.为什么 TCP 握手需要三次?
  • 7.为什么 TCP 的挥手需要四次?
  • 8.什么是 DDOS 攻击
  • 9.什么是 SYN 洪水攻击
  • 10. HTTP1.0 和 HTTP1.1 的区别
  • 11. Https 原理是什么?
  • 12. 说说你知道的几种 HTTP 响应码。
  • 13. 如何理解 HTTP 协议的无状态性。
  • 14. Session 和 cookie 的区别。
  • 15. 用户在浏览器输入一个 URL 并回车,这个过程涉 及到哪些网络协议。
  • 16. HTTP2.0 带来的变化。
  • 17. Rest和Http什么关系?你对Rest风格如何理解?
  • 18. 哪些应用比较适合用 udp 实现
  • 19. Netty 的特点?
  • 20. Netty 的线程模型
  • 21. TCP 粘包/拆包的原因及解决方法?
  • 22. 请概要介绍下序列化
  • 23. Netty 的零拷贝实现
  • 24. Netty 的优势有哪些?
  • 25. (高)Netty 高性能表现在哪些方面?
  • 26. Netty 中有哪些重要组件?
  • 27. 如何让单机下 Netty 支持百万长连接?

前    言

本文仅收录了一些常见的网络通讯面试题,如需查看其它java面试题可查看我另一篇博文:

JAVA | 2021最全Java面试题及答案汇总


正    文

1. BIO 与 NIO 的区别

1、bio 同步阻塞 io:在此种方式下,用户进程在发起一个 IO 操作以后,必须等待 IO
操作的完成,只有当真正完成了了 IO 操作以后,用户进程才能运行。JAVA 传统的 IO 模型属于此种方式。
2、nio 同步⾮非阻塞式 I/O:Java NIO 采⽤用了了双向通道进⾏行行数据传输,在通道上我们可以注册我们感兴趣的事件:连接事件、读写事件;
NIO 主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统 IO 基于
字节流和字符流进⾏行行操作,⽽而 NIO 基于 Channel 和 Buffer(缓冲区)进行操作,数据
总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)⽤用于监听多
个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

2. select 与 poll 的区别

A、io 多路复用:
1、概念:IO 多路路复用是指内核一旦发现进程指定的一个或者多个 IO 条件准备读取,
它就通知该进程。
2、优势:与多进程和多线程技术相比,I/O 多路复用技术的最大优势是系统开销小,
系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。
3、系统:目前支持 I/O 多路路复用的系统调用有 select,pselect,poll,epoll。

B、select:
select 目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select
的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在 Linux 上一般为
1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。

C、poll:
它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有一个缺点:
a. 大量的 fd 的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不
是有意义。
b. poll 还有⼀个特点是“水平触发”,如果报告了了 fd 后,没有被处理,那么下次
poll 时会再次报告该 fd。

3.请概述 OSI 网络模型

OSI 网络模型共有 7 层,自上而下分别是:
应用层(数据):确定进程之间通信的性质以满足用户需要以及提供网络与用户应用。
表示层(数据):主要解决用户信息的语法表示问题,如加密解密。在表示层进行代码
/编码转换。
会话层(数据):提供包括访问验证和会话管理在内的建立和维护应用之间通信的机制,
如服务器验证用户登录便是由会话层完成的。在会话层封装会话控制参数。
传输层(段):实现网络不同主机上用户进程之间的数据通信,可靠与不可靠的传输,
传输层的错误检测,流量控制等。在传输层封装传输控制。
网络层(包):提供逻辑地址(IP)、选路,数据从源端到目的端的传输。在网络层加
上逻辑寻址地址。
数据链路层(帧):将上层数据封装成帧,用 MAC 地址访问媒介,错误检测与修正。
在数据链路层封装基于 MAC 的信息。
物理层(比特流):设备之间比特流的传输,物理接口,电气特性等。在物理层连接到
线缆系统进行实际传递。

4. TCP 和 UDP 的区别

TCP 和 UDP 都属于传输层协议,它们之间的区别在于:
TCP 是面向连接的;UDP 是无连接的。
TCP 是可靠的;UDP 是不可靠的。
TCP 只支持点对点通信;UDP 支持一对一、一对多、多对一、多对多的通信模式。
TCP 是面向字节流的;UDP 是面向报文的。
TCP 有拥塞控制机制;UDP 没有拥塞控制,适合媒体通信。
TCP 首部开销(20 个字节),比 UDP 的首部开销(8 个字节)要大。

5.请概述 TCP 的三次握手四次挥手机制

TCP 建立连接的过程。
三次握手:
1.)第一次握手(客户端发送 syn 包到服务器端):客户端发送 syn 包到服务器端,进入
syn_send 状态,等待服务器端的确认;
2.)第二次握手(服务器返回 syn+ack 包给客户端):服务器端收到客户端的 syn 包,发
送 syn+ack 包给客户端,进入 syn_recv 状态;
3.)第三次握手(客服端返回 ack 包给服务端):客户端收到服务器端的 syn+ack 包,发
送个 ack 包到服务器端,至此,客户端与服务器端进入 established 状态;

握手过程中传送的包不包含任何数据,连接建立后才会开始传送数据,理想状态下,TCP 连接一旦建立,在通信双方的任何一方主动关闭连接前,TCP
连接都会一直保持下去。

**
四次挥手:**

  • 第一次挥手:主动关闭方发送 fin 包到被动关闭方,告诉被动关闭方我不会再给你
    发送数据了;

  • 第二次挥手:被动关闭方收到 syn 包,发送 ack 给对方,确认序号为收到序号+1;

  • 第三次挥手:被动关闭方也也发送 fin 包给主动关闭方,告诉对方我也不会给你发
    送数据了;

  • 第四次挥手:主动关闭方收到 syn 包,发送 ack 给对方,至此,完成四次挥手;

6.为什么 TCP 握手需要三次?

TCP 是可靠的传输控制协议,三次握手能保证数据可靠传输又能提高传输效率。
如果 TCP 的握手是两次:
<1>若建立连接只需两次握手,客户端并没有太大的变化,仍然需要获得服务端的应答
后才进入 ESTABLISHED 状态,而服务端在收到连接请求后就进入 ESTABLISHED 状态。此时如
果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务
端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连
接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入 ESTABLISHED 状态,等
待发送数据或主动发送数据。但此时的客户端早已进入 CLOSED 状态,服务端将会一直等待
下去,这样浪费服务端连接资源。
如果 TCP 的握手是四次:

  • 1.client 给 server 发送 SYN 同步报文;
  • 2.server 收到 SYN 后,给 client 回复 ACK 确认报文;
  • 3.server 给 client 发送 SYN 同步报文;
  • 4.client 给 server 发送 ACK 确认报文。
    第 2.3 步之间,server 和 client 没有任何的数据交互,分开发送相当于多发了一次 TCP报文段,SYN 和 ACK 标识只是 TCP 报头的一个标识位。很明显,这两步可以合并,从而提高连接的速度和效率。

7.为什么 TCP 的挥手需要四次?

因为 TCP 连接是全双工的网络协议,允许同时通信的双方同时进行数据的收发,同样
也允许收发两个方向的连接被独立关闭,以避免 client 数据发送完毕,向 server 发送 FIN
关闭连接,而 server 还有发送到 client 的数据没有发送完毕的情况。所以关闭 TCP 连接
需要进行四次握手,每次关闭一个方向上的连接需要 FIN 和 ACK 两次握手。

8.什么是 DDOS 攻击

DDOS 攻击利用合理的服务请求占用过多的服务资源,使正常用户的请求无法得到相应。
常见的 DDOS 攻击有计算机网络带宽攻击和连通性攻击。
带宽攻击指以极大的通信量冲击网络,使得所有可用网络资源都被消耗殆尽,最后导致
合法的用户请求无法通过。
连通性攻击指用大量的连接请求冲击计算机,使得所有可用的操作系统资源都被消耗殆
尽,最终计算机无法再处理合法用户的请求。

9.什么是 SYN 洪水攻击

SYN 洪水攻击属于 DOS 攻击的一种,它利用 TCP 协议缺陷,通过发送大量的半连接请求,耗费 CPU 和内存资源。
客户端在短时间内伪造大量不存在的 IP 地址,向服务器不断地发送 SYN 报文,服务器
回复 ACK 确认报文,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的 SYN 报文被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。

10. HTTP1.0 和 HTTP1.1 的区别

主要是如下的 8 点:
可拓展性。
缓存。
带宽优化,带来了分块传输。
长连接,HTTP1.1 支持长连接(默认开启 Connect: keep-alive)和请求的流水线处理,
在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。
消息传递。
Host 头域。
错误提示。
内容协商。

11. Https 原理是什么?

HTTPS 协议就是基于 SSL 的 HTTP 协议,HTTPS 使用与 HTTP 不同的端口(HTTP80 ,
HTTPS443)
提供了身份验证与加密通信方法,被广泛用于互联网上安全敏感的通信。
1、客户端请求 SSL 连接,并将自⼰己⽀支持的加密规则发给网站。
2、服务器端将自⼰己的身份信息以证书形式发回给客户端。证书里面包含了网站地址,
加密公钥,以及证书的颁发机构。
3、获得证书后,客户要做以下工作:验证证书合法性,如果证书受信任,客户端会生
成一串随机数的密码,并用证书提供的公钥进行加密。将加密好的随机数发给服务器。
4、获得到客户端发的加密了的随机数之后,服务器用自己的私钥进行解密,得到这个
随机数,把这个随机数作为对称加密的密钥。(利用非对称加密传输对称加密的密钥)
5、之后服务器与客户之间就可以用随机数对各自的信息进行加密,解密。
注意的是:证书是一个公钥,这个公钥是进行加密用的。而私钥是进行解密用的。公钥
任何都知道,私钥只有自己知道。这是非对称加密。
而对称加密就是钥匙只有一把,我们都知道。之所以用到对称加密,是因为对称加密的
速度更快。而非对称加密的可靠性更高。

12. 说说你知道的几种 HTTP 响应码。

HTTP 响应码主要分为五种:
1XX:请求处理中,请求已被接收,正在处理。
2XX:请求成功,请求被成功处理。比如 200,OK,表示客户端请求成功。
3XX:重定向,要完成请求必须进行进一步处理。比如 301,MovedPermanently,永久
重定向,使用域名跳转;302,Found,临时重定向,未登录的用户访问用户中心重定向到登
陆界面。
4XX:客户端错误,请求不合符。比如 400,Bad Request,客户端请求有语法错误,不
能被服务器所理解; 401 , Unauthrized ,请求未经授权, 这个状态代码必须和
WWW-Authenticate 报头域一起使用;403,Forbidden,服务器收到请求,但是拒绝提供服
务;404,Not Found,请求资源不存在,输入了错误的 URL。
5XX:服务器端错误,服务器不能处理合法请求。比如 500,Internal Servel Error,
服务器发生不可预期的错误;503,Server Unavailable,服务器当前不能处理客户端的请
求,一段时间后可能恢复正常。

13. 如何理解 HTTP 协议的无状态性。

无状态,是指协议对于事务处理没有记忆功能。HTTP 是一个无状态协议,这意味着每
个请求都是独立的,Keep-Alive 没能改变这个结果。无状态意味着如果后续处理需要前面
的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不
需要先前信息时它的应答就很快。
无状态,更容易做服务的扩容,支撑更大的访问量。

14. Session 和 cookie 的区别。

Session 和 cookie 都是实现对话管理的方案。主要区别在于:
Session 在服务端,Cookie 存储在客户端。
Session 的运行依赖 Session ID,而 Session ID 是存在 Cookie 中的,也就是说,如
果浏览器禁用了 Cookie,同时 Session 也会失效,但是,可以通过其他方式实现,比如在
url 参数中传递 Session ID。
Tomcat 中的 Session 是存在服务器内存中,不过也可以通过特殊的方式做持久化处理
(memcache,redis),方便 Session 共享。
cookie 不是很安全,别人可以分析存放在本地的 cookie 并进行 cookie 欺骗,考虑到
安全应当使用 session。

15. 用户在浏览器输入一个 URL 并回车,这个过程涉 及到哪些网络协议。

浏览器输入一个 URL 并回车:

  1. 首先进行域名解析,浏览器搜索自己的 DNS 缓存,缓存中维护一张域名与 IP 地址
    的对应表。若没有,则搜索操作系统的 DNS 缓存;若没有,则将域名发送至本地域名服务器(递归查询方式),本地域名服务器查询自己的 DNS 缓存,查找成功则返回结果,否则,本地的 DNS 服务器向根域名服务器发出查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名服务器发送查询请求,然后依次类推直到查询到该域名的 IP 地址。DNS 服务器是基于 UDP 的,因此会用到 UDP 协议。
  2. 得到 IP 地址以后,浏览器就要与服务器建立一个 HTTP 连接,因此要用到 HTTP 协
    议。HTTP 生成一个 GET 请求报文。
  3. 接下来到了传输层,选择传输协议,TCP 或者 UDP,TCP 是可靠的传输控制协议,对 HTTP 请求进行封装,加入了端口号等信息。
  4. 然后到了网络层,通过IP 协议将IP 地址封装为IP 数据报;然后此时会用到ARP 协
    议,主机发送信息时将包含目标 IP 地址的 ARP 请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址,找到目的 MAC 地址。
  5. 接下来到了数据链路层,把网络层交下来的 IP 数据报添加首部和尾部,封装为 MAC
    帧,现在根据目的 mac 开始建立 TCP 连接,三次握手,接收端在收到物理层上交的比特流后,根据首尾的标记,识别帧的开始和结束,将中间的数据部分上交给网络层,然后层层向上传递到应用层。
  6. 服务器响应请求并请求客户端要的资源,传回给客户端。
  7. 断开 TCP 连接,浏览器对页面进行渲染呈现给客户端。

16. HTTP2.0 带来的变化。

HTTP2.0 和 HTTP1.x 相比的新特性为:
新的二进制格式,HTTP1.x 的解析是基于文本。基于文本协议的格式解析存在天然缺陷,
文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认 0 和 1
的组合。基于这种考虑 HTTP2.0 的协议解析决定采用二进制格式,实现方便且健壮。
多路复用,即连接共享,做到同一个连接并发处理多个请求,而且并发请求的数量比
HTTP1.1 大了好几个数量级。
多个请求可以同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其他连
接的正常执行。这块和 HTTP1.1 的长连接有区别,长连接是串行化执行多个请求。
首部压缩,HTTP1.1 不支持 header 数据的压缩,HTTP2.0 使用 HPACK 算法对 header 的
数据进行压缩,这样数据体积小了,在网络上传输就会更快。
服务器推送,当我们对支持 HTTP2.0 的 web server 请求数据的时候,服务器会顺便把
一些客户端需要的资源(比如 css、js 文件)一起推送到客户端,免得客户端再次创建连
接发送请求到服务器端获取。这种方式非常合适加载静态资源。还没有收到浏览器的请求,
服务器就把各种资源推送给浏览器了。

17. Rest和Http什么关系?你对Rest风格如何理解?

Http 是一种协议,Rest 是一种软件架构风格。REST 架构风格并不是绑定在 HTTP 上,
只不过目前 HTTP 是唯一与 REST 相关的实例。
REST (英文: Representational State Transfer, 简称 REST,表现层状态转化),指
的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。
Rest 作为一种软件架构风格而不是标准,只是提供了一组设计原则和约束条件。它主
要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更
易于实现缓存等机制。
Restful 架构中
(1) 每一个 URI 代表一种资源;
(2) 客户端和服务器之间,传递这种资源的某种表现层;
(3) 客户端通过四个 HTTP 动词(GET 用来获取资源,POST 用来新建资源(也可以用于更
新资源),PUT 用来更新资源,DELETE 用来删除资源。), 对服务器端资源进行操作,实现"
表现层状态转化”。

18. 哪些应用比较适合用 udp 实现

多播的信息一定要用 udp 实现,因为 tcp 只支持一对一通信。
如果一个应用场景中大多是简短的信息,适合用 udp 实现,因为 udp 是基于报文段的,
它直接对上层应用的数据封装成报文段,然后丢在网络中,如果信息量太大,会在链路层中
被分片,影响传输效率。
如果一个应用场景重性能甚于重完整性和安全性,那么适合于 udp,比如多媒体应用,
缺一两帧不影响用户体验,但是需要流媒体到达的速度快,因此比较适合用 udp
如果要求快速响应,那么 udp 听起来比较合适
如果又要利用 udp 的快速响应优点,又想可靠传输,那么只能考上层应用自己制定规则
了。
常见的使用 udp 的例子:ICQ,QQ 的聊天模块。

19. Netty 的特点?

一个高性能、异步事件驱动的 NIO 框架,它提供了对 TCP、UDP 和文件传输的支持
使用更高效的 socket 底层,对 epoll 空轮询引起的 cpu 占用飙升在内部进行了处理,
避免了直接使用 NIO 的陷阱,简化了 NIO 的处理方式。
采用多种 decoder/encoder 支持,对 TCP 粘包/分包进行自动化处理
可使用接受/处理线程池,提高连接效率,对重连、心跳检测的简单支持
可配置 IO 线程数、TCP 参数, TCP 接收和发送缓冲区使用直接内存代替堆内存,通过
内存池的方式循环利用 ByteBuf
通过引用计数器及时申请释放不再引用的对象,降低了 GC 频率
使用单线程串行化的方式,高效的 Reactor 线程模型
大量使用了 volitale、使用了 CAS 和原子类、线程安全类的使用、读写锁的使用

20. Netty 的线程模型

Netty 通过 Reactor 模型基于多路复用器接收并处理用户请求,内部实现了两个线程池,
boss 线程池和 work 线程池,其中 boss 线程池的线程负责处理请求的 accept 事件,当接收
到 accept 事件的请求时,把对应的 socket 封装到一个 NioSocketChannel 中,并交给 work
线程池,其中 work 线程池负责请求的 read 和 write 事件,由对应的 Handler 处理。
单线程模型:所有 I/O 操作都由一个线程完成,即多路复用、事件分发和处理都是在一
个 Reactor 线程上完成的。既要接收客户端的连接请求,向服务端发起连接,又要发送/读取
请求或应答/响应消息。一个 NIO 线程同时处理成百上千的链路,性能上无法支撑,速度慢,
若线程进入死循环,整个程序不可用,对于高负载、大并发的应用场景不合适。
多线程模型:有一个 NIO 线程(Acceptor) 只负责监听服务端,接收客户端的 TCP 连
接请求;NIO 线程池负责网络 IO 的操作,即消息的读取、解码、编码和发送;1 个 NIO 线
程可以同时处理 N 条链路,但是 1 个链路只对应 1 个 NIO 线程,这是为了防止发生并发操
作问题。但在并发百万客户端连接或需要安全认证时,一个 Acceptor 线程可能会存在性能
不足问题。
主从多线程模型: Acceptor 线程用于绑定监听端口,接收客户端连接,将
SocketChannel 从主线程池的 Reactor 线程的多路复用器上移除,重新注册到 Sub 线程池
的线程上,用于处理 I/O 的读写等操作,从而保证 mainReactor 只负责接入认证、握手等
操作;

21. TCP 粘包/拆包的原因及解决方法?

TCP 是以流的方式来处理数据,一个完整的包可能会被 TCP 拆分成多个包进行发送,也
可能把小的封装成一个大的数据包发送。
TCP 粘包/分包的原因:
应用程序写入的字节大小大于套接字发送缓冲区的大小,会发生拆包现象,而应用程序
写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘
包现象;
进行 MSS 大小的 TCP 分段,当 TCP 报文长度-TCP 头部长度>MSS 的时候将发生拆包
以太网帧的 payload(净荷)大于 MTU(1500 字节)进行 ip 分片。
解决方法
消息定长:FixedLengthFrameDecoder 类
包尾增加特殊字符分割:行分隔符类:LineBasedFrameDecoder 或自定义分隔符类 :
DelimiterBasedFrameDecoder
将消息分为消息头和消息体:LengthFieldBasedFrameDecoder 类。分为有头部的拆包
与粘包、长度字段在前且有头部的拆包与粘包、多扩展头部的拆包与粘包。

22. 请概要介绍下序列化

序列化(编码)是将对象序列化为二进制形式(字节数组),主要用于网络传输、数据
持久化等;而反序列化(解码)则是将从网络、磁盘等读取的字节数组还原成原始对象,主
要用于网络传输对象的解码,以便完成远程调用。
影响序列化性能的关键因素:序列化后的码流大小(网络带宽的占用)、序列化的性能
(CPU 资源占用);是否支持跨语言(异构系统的对接和开发语言切换)。
Java 默认提供的序列化:无法跨语言、序列化后的码流太大、序列化的性能差
XML,优点:人机可读性好,可指定元素或特性的名称。缺点:序列化数据只包含数据
本身以及类的结构,不包括类型标识和程序集信息;只能序列化公共属性和字段;不能序列
化方法;文件庞大,文件格式复杂,传输占带宽。适用场景:当做配置文件存储数据,实时
数据转换。
JSON,是一种轻量级的数据交换格式,优点:兼容性高、数据格式比较简单,易于读写、
序列化后数据较小,可扩展性好,兼容性好、与 XML 相比,其协议比较简单,解析速度比较
快。缺点:数据的描述性比 XML 差、不适合性能要求为 ms 级别的情况、额外空间开销比较
大。适用场景(可替代XML):跨防火墙访问、可调式性要求高、基于 Web browser 的
Ajax 请求、传输数据量相对小,实时性要求相对低(例如秒级别)的服务。
Fastjson,采用一种“假定有序快速匹配”的算法。优点:接口简单易用、目前 Java
语言中最快的 json 库。缺点:过于注重快,而偏离了“标准”及功能性、代码质量不高,
文档不全。适用场景:协议交互、Web 输出、Android 客户端
Thrift,不仅是序列化协议,还是一个 RPC 框架。优点:序列化后的体积小, 速度快、
支持多种语言和丰富的数据类型、对于数据字段的增删具有较强的兼容性、支持二进制压缩
编码。缺点:使用者较少、跨防火墙访问时,不安全、不具有可读性,调试代码时相对困难、
不能与其他传输层协议共同使用(例如 HTTP)、无法支持向持久层直接读写数据,即不适
合做数据持久化序列化协议。适用场景:分布式系统的 RPC 解决方案
Protobuf,将数据结构以.proto 文件进行描述,通过代码生成工具可以生成对应数据
结构的 POJO 对象和 Protobuf 相关的方法和属性。优点:序列化后码流小,性能高、结构化
数据存储格式(XML JSON 等)、通过标识字段的顺序,可以实现协议的前向兼容、结构化
的文档更容易管理和维护。缺点:需要依赖于工具生成代码、支持的语言相对较少,官方只
支持 Java 、C++ 、python。适用场景:对性能要求高的 RPC 调用、具有良好的跨防火墙的
访问属性、适合应用层对象的持久化
其它
protostuff 基于 protobuf 协议,但不需要配置 proto 文件,直接导包即可
Jboss marshaling 可以直接序列化 Java 类, 无须实 Java.io.Serializable 接口
Message pack 一个高效的二进制序列化格式
Hessian 采用二进制协议的轻量级 remoting onhttp 工具
kryo 基于 protobuf 协议,只支持 Java 语言,需要注册(Registration),然后序列化
(Output),反序列化(Input)

23. Netty 的零拷贝实现

Netty 的零拷贝主要包含三个方面:
Netty 的接收和发送 ByteBuffer 采用 DIRECT BUFFERS,使用堆外直接内存进行
Socket 读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)
进行 Socket 读写,JVM 会将堆内存 Buffer 拷贝一份到直接内存中,然后才写入 Socket
中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。
Netty 提供了组合 Buffer 对象,可以聚合多个 ByteBuffer 对象,用户可以像操作一
个 Buffer 那样方便的对组合 Buffer 进行操作,避免了传统通过内存拷贝的方式将几个小
Buffer 合并成一个大的 Buffer。
Netty 的文件传输采用了 transferTo 方法,它可以直接将文件缓冲区的数据发送到目
标 Channel,避免了传统通过循环 write 方式导致的内存拷贝问题。
(高)Netty 是如何解决 JDK 中的 Selector BUG 的?
Selector BUG:若 Selector 的轮询结果为空,也没有 wakeup 或新消息处理,则发生空
轮询,CPU 使用率 100%,
Netty 的解决办法:对 Selector 的 select 操作周期进行统计,每完成一次空的 select
操作进行一次计数,若在某个周期内连续发生 N 次空轮询,则触发了 epoll 死循环 bug。重
建 Selector,判断是否是其他线程发起的重建请求,若不是则将原 SocketChannel 从旧的
Selector 上去除注册,重新注册到新的 Selector 上,并将原来的 Selector 关闭。

24. Netty 的优势有哪些?

使用简单:封装了 NIO 的很多细节,使用更简单。
功能强大:预置了多种编解码功能,支持多种主流协议。
定制能力强:可以通过 ChannelHandler 对通信框架进行灵活地扩展。
性能高:通过与其他业界主流的 NIO 框架对比,Netty 的综合性能最优。
稳定:Netty 修复了已经发现的所有 NIO 的 bug,让开发人员可以专注于业务本身。
社区活跃:Netty 是活跃的开源项目,版本迭代周期短,bug 修复速度快。

25. (高)Netty 高性能表现在哪些方面?

IO 线程模型:同步非阻塞,用最少的资源做更多的事。
内存零拷贝:尽量减少不必要的内存拷贝,实现了更高效率的传输。
内存池设计:申请的内存可以重用,主要指直接内存。内部实现是用一颗二叉查找树管
理内存分配情况。
串形化处理读写:避免使用锁带来的性能开销。即消息的处理尽可能在同一个线程内完
成,期间不进行线程切换,这样就避免了多线程竞争和同步锁。表面上看,串行化设计似乎
CPU 利用率不高,并发程度不够。但是,通过调整 NIO 线程池的线程参数,可以同时启动多
个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列-多个工作线程模
型性能更优。
高性能序列化协议:支持 protobuf 等高性能序列化协议。
高效并发编程的体现:volatile 的大量、正确使用;CAS 和原子类的广泛使用;线程安
全容器的使用;通过读写锁提升并发性能。

26. Netty 中有哪些重要组件?

Channel:Netty 网络操作抽象类,它除了包括基本的 I/O 操作,如 bind、connect、
read、write 等。
EventLoop:主要是配合 Channel 处理 I/O 操作,用来处理连接的生命周期中所发生
的事情。
ChannelFuture : Netty 框架中所有的 I/O 操作都为异步的,因此我们需要
ChannelFuture 的 addListener()注册一个 ChannelFutureListener 监听事件,当操作执
行成功或者失败时,监听就会自动触发返回结果。
ChannelHandler:充当了所有处理入站和出站数据的逻辑容器。ChannelHandler 主要
用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。
ChannelPipeline:为 ChannelHandler 链提供了容器,当 channel 创建时,就会被自
动分配到它专属的 ChannelPipeline,这个关联是永久性的。

27. 如何让单机下 Netty 支持百万长连接?

单机下能不能让我们的网络应用支持百万连接?可以,但是有很多的工作要做。

操作系统

首先就是要突破操作系统的限制。
在 Linux 平台上,无论编写客户端程序还是服务端程序,在进行高并发 TCP 连接处理时,
最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为
每个 TCP 连接都要创建一个 socket 句柄,每个 socket 句柄同时也是一个文件句柄)。
可使用 ulimit 命令查看系统允许当前用户进程打开的文件数限制:
$ ulimit -n
1024
这表示当前用户的每个进程最多允许同时打开 1024 个文件,这 1024 个文件中还得除去
每个进程必然打开的标准输入,标准输出,标准错误,服务器监听 socket,进程间通讯的
unix 域 socket 等文件,那么剩下的可用于客户端 socket 连接的文件数就只有大概
1024-10=1014 个左右。也就是说缺省情况下,基于 Linux 的通讯程序最多允许同时 1014 个
TCP 并发连接。
对于想支持更高数量的 TCP 并发连接的通讯处理程序,就必须修改 Linux 对当前用户
的进程同时打开的文件数量。
修改单个进程打开最大文件数限制的最简单的办法就是使用 ulimit 命令:
$ ulimit –n 1000000
如果系统回显类似于"Operation not permitted"之类的话,说明上述限制修改失败,
实际上是因为在中指定的数值超过了 Linux 系统对该用户打开文件数的软限制或硬限制。因
此,就需要修改 Linux 系统对用户的关于打开文件数的软限制和硬限制。
软限制(soft limit):是指 Linux 在当前系统能够承受的范围内进一步限制用户同时
打开的文件数;
硬限制(hardlimit):是根据系统硬件资源状况(主要是系统内存)计算出来的系统最
多可同时打开的文件数量。
第一步,修改/etc/security/limits.conf 文件,在文件中添加如下行:

  • soft nofile 1000000
  • hard nofile 1000000
    '*'号表示修改所有用户的限制;
    soft 或 hard 指定要修改软限制还是硬限制;1000000 则指定了想要修改的新的限
    制值,即最大打开文件数(请注意软限制值要小于或等于硬限制)。修改完后保存文件。
    第二步,修改/etc/pam.d/login 文件,在文件中添加如下行:
    session required /lib/security/pam_limits.so
    这是告诉 Linux 在用户完成系统登录后,应该调用 pam_limits.so 模块来设置系统对该
    用户可使用的各种资源数量的最大限制(包括用户可打开的最大文件数限制),而
    pam_limits.so 模块就会从/etc/security/limits.conf 文件中读取配置来设置这些限制
    值。修改完后保存此文件。
    第三步,查看 Linux 系统级的最大打开文件数限制,使用如下命令:
    [speng@as4 ~]$ cat /proc/sys/fs/file-max
    12158
    这表明这台 Linux 系统最多允许同时打开(即包含所有用户打开文件数总和)12158
    个文件,是 Linux 系统级硬限制,所有用户级的打开文件数限制都不应超过这个数值。通常
    这个系统级硬限制是 Linux 系统在启动时根据系统硬件资源状况计算出来的最佳的最大同
    时打开文件数限制,如果没有特殊需要,不应该修改此限制,除非想为用户级打开文件数限
    制设置超过此限制的值。
    如何修改这个系统最大文件描述符的限制呢?修改 sysctl.conf 文件

vi /etc/sysctl.conf


# 在末尾添加
fs.file_max = 1000000

立即生效
sysctl -p

Netty 调优

设置合理的线程数
对于线程池的调优,主要集中在用于接收海量设备 TCP 连接、TLS 握手的 Acceptor 线程
池( Netty 通常叫 boss NioEventLoop Group)上,以及用于处理网络数据读写、心跳发送的
1O 工作线程池(Nety 通常叫 work Nio EventLoop Group)上。
对于 Nety 服务端,通常只需要启动一个监听端口用于端侧设备接入即可,但是如果服务
端集群实例比较少,甚至是单机(或者双机冷备)部署,在端侧设备在短时间内大量接入时,需
要对服务端的监听方式和线程模型做优化,以满足短时间内(例如 30s)百万级的端侧设备接
入的需要。
服务端可以监听多个端口,利用主从 Reactor 线程模型做接入优化,前端通过 SLB 做 4
层门 7 层负载均衡。
主从 Reactor 线程模型特点如下:服务端用于接收客户端连接的不再是一个单独的 NO
线程,而是一个独立的 NIO 线程池; Acceptor 接收到客户端 TCP 连接请求并处理后(可能包
含接入认证等),将新创建的 Socketchanne 注册到 I/O 线程池(subReactor 线程池)的某个
IO 线程,由它负责 Socketchannel 的读写和编解码工作; Acceptor 线程池仅用于客户端的
登录、握手和安全认证等,一旦链路建立成功,就将链路注册到后端 sub reactor 线程池的
IO 线程,由 IO 线程负责后续的 IO 操作。
对于 IO 工作线程池的优化,可以先采用系统默认值(即 CPU 内核数×2)进行性能测试,
在性能测试过程中采集 IO 线程的 CPU 占用大小,看是否存在瓶颈对于 O 工作线程池的优化,
可以先采用系统默认值(即 CPU 内核数×2)进行性能
测试,在性能测试过程中采集 IO 线程的 CPU 占用大小,看是否存在瓶颈, 具体可以观察
线程堆栈,如果连续采集几次进行对比,发现线程堆栈都停留在 Selectorlmpl. lock
AndDoSelect,则说明 IO 线程比较空闲,无须对工作线程数做调整。
如果发现 IO 线程的热点停留在读或者写操作,或者停留在 Channelhandler 的执行处,
则可以通过适当调大 Nio EventLoop 线程的个数来提升网络的读写性能。

心跳优化

针对海量设备接入的服务端,心跳优化策略如下。
(1)要能够及时检测失效的连接,并将其剔除,防止无效的连接句柄积压,导致 OOM 等问

(2)设置合理的心跳周期,防止心跳定时任务积压,造成频繁的老年代 GC(新生代和老年
代都有导致 STW 的 GC,不过耗时差异较大),导致应用暂停
(3)使用 Nety 提供的链路空闲检测机制,不要自己创建定时任务线程池,加重系统的负
担,以及增加潜在的并发安全问题。
当设备突然掉电、连接被防火墙挡住、长时间 GC 或者通信线程发生非预期异常时,会导
致链路不可用且不易被及时发现。特别是如果异常发生在凌晨业务低谷期间,当早晨业务高
峰期到来时,由于链路不可用会导致瞬间大批量业务失败或者超时,这将对系统的可靠性产
生重大的威胁。
从技术层面看,要解决链路的可靠性问题,必须周期性地对链路进行有效性检测。目前最
流行和通用的做法就是心跳检测。心跳检测机制分为三个层面
(1)TCP 层的心跳检测,即 TCP 的 Keep-Alive 机制,它的作用域是整个 TCP 协议栈。
(2)协议层的心跳检测,主要存在于长连接协议中,例如 MQTT。
(3)应用层的心跳检测,它主要由各业务产品通过约定方式定时给对方发送心跳消息实
现。
心跳检测的目的就是确认当前链路是否可用,对方是否活着并且能够正常接收和发送消
息。作为高可靠的 NIO 框架,Nety 也提供了心跳检测机制。
一般的心跳检测策略如下。
(1)连续 N次心跳检测都没有收到对方的 Pong应答消息或者 Ping 请求消息,则认为链路
已经发生逻辑失效,这被称为心跳超时。
(2)在读取和发送心跳消息的时候如果直接发生了 IO 异常,说明链路已经失效,这被称
为心跳失败。无论发生心跳超时还是心跳失败,都需要关闭链路,由客户端发起重连操作,保
证链路能够恢复正常。
Nety 提供了三种链路空闲检测机制,利用该机制可以轻松地实现心跳检测
(1)读空闲,链路持续时间 T 没有读取到任何消息。
(2)写空闲,链路持续时间 T 没有发送任何消息
(3)读写空闲,链路持续时间 T 没有接收或者发送任何消息
对于百万级的服务器,一般不建议很长的心跳周期和超时时长

接收和发送缓冲区调优

在一些场景下,端侧设备会周期性地上报数据和发送心跳,单个链路的消息收发量并不
大,针对此类场景,可以通过调小TCP的接收和发送缓冲区来降低单个TCP连接的资源占用率
当然对于不同的应用场景,收发缓冲区的最优值可能不同,用户需要根据实际场景,结合
性能测试数据进行针对性的调优

合理使用内存池

随着 JVM 虚拟机和 JT 即时编译技术的发展,对象的分配和回收是一个非常轻量级的工
作。但是对于缓冲区 Buffer,情况却稍有不同,特别是堆外直接内存的分配和回收,是一个耗
时的操作。
为了尽量重用缓冲区,Nety 提供了基于内存池的缓冲区重用机制。
在百万级的情况下,需要为每个接入的端侧设备至少分配一个接收和发送缓冲区对象,
采用传统的非池模式,每次消息读写都需要创建和释放 ByteBuf 对象,如果有 100 万个连接,
每秒上报一次数据或者心跳,就会有 100 万次/秒的 ByteBuf 对象申请和释放,即便服务端的
内存可以满足要求,GC 的压力也会非常大。
以上问题最有效的解决方法就是使用内存池,每个 NioEventLoop 线程处理 N 个链路,在
线程内部,链路的处理是串行的。假如 A 链路首先被处理,它会创建接收缓冲区等对象,待解
码完成,构造的 POJO 对象被封装成任务后投递到后台的线程池中执行,然后接收缓冲区会被
释放,每条消息的接收和处理都会重复接收缓冲区的创建和释放。如果使用内存池,则当 A
链路接收到新的数据报时,从 NioEventLoop 的内存池中申请空闲的 ByteBuf,解码后调用
release 将 ByteBuf 释放到内存池中,供后续的 B 链路使用。
Nety 内存池从实现上可以分为两类:堆外直接内存和堆内存。由于 Byte Buf 主要用于
网络 IO 读写,因此采用堆外直接内存会减少一次从用户堆内存到内核态的字节数组拷贝,所
以性能更高。由于 DirectByteBuf 的创建成本比较高,因此如果使用 DirectByteBuf,则需
要配合内存池使用,否则性价比可能还不如 Heap Byte。
Netty 默认的 IO 读写操作采用的都是内存池的堆外直接内存模式,如果用户需要额外使
用 ByteBuf,建议也采用内存池方式;如果不涉及网络 IO 操作(只是纯粹的内存操作),可以
使用堆内存池,这样内存的创建效率会更高一些。

IO 线程和业务线程分离

如果服务端不做复杂的业务逻辑操作,仅是简单的内存操作和消息转发,则可以通过调 大 NioEventLoop 工作线程池的方式,直接在 IO 线程中执行业务 Channelhandler,这样便减
少了一次线程上下文切换,性能反而更高。
如果有复杂的业务逻辑操作,则建议 IO 线程和业务线程分离,对于 IO 线程,由于互相之
间不存在锁竞争,可以创建一个大的 NioEvent Loop Group 线程组,所有 Channel 都共享同
一个线程池。
对于后端的业务线程池,则建议创建多个小的业务线程池,线程池可以与 IO 线程绑定,
这样既减少了锁竞争,又提升了后端的处理性能。

针对端侧并发连接数的流控

无论服务端的性能优化到多少,都需要考虑流控功能。当资源成为瓶颈,或者遇到端侧设
备的大量接入,需要通过流控对系统做保护。流控的策略有很多种,比如针对端侧连接数的
流控。在 Nety 中,可以非常方便地实现流控功能:新增一个 FlowControlchannelhandler,
然后添加到 ChannelPipeline 靠前的位置,覆盖 channelActiveO 方法,创建 TCP 链路后,执
行流控逻辑,如果达到流控阈值,则拒绝该连接,调用 ChannelHandler Context 的 close(方
法关闭连接。

JVM 层面相关性能优化

当客户端的并发连接数达到数十万或者数百万时,系统一个较小的抖动就会导致很严重
的后果,例如服务端的 GC,导致应用暂停(STW)的 GC 持续几秒,就会导致海量的客户端设备掉
线或者消息积压,一旦系统恢复,会有海量的设备接入或者海量的数据发送很可能瞬间就把
服务端冲垮。
JVM 层面的调优主要涉及 GC 参数优化,GC 参数设置不当会导致频繁 GC,甚至 OOM 异常,
对服务端的稳定运行产生重大影响。

确定 GC 优化目标

1.GC(垃圾收集)有三个主要指标。
(1)吞吐量:是评价GC能力的重要指标,在不考虑GC引起的停顿时间或内存消耗时,吞吐
量是 GC 能支撑应用程序达到的最高性能指标。
(2)延迟:GC 能力的最重要指标之一,是由于 GC 引起的停顿时间,优化目标是缩短延迟时
间或完全消除停顿(STW),避免应用程序在运行过程中发生抖动。
(3)内存占用:GC 正常时占用的内存量。

JVM GC 调优的三个基本原则如下。
(1) Minor go 回收原则:每次新生代 GC 回收尽可能多的内存,减少应用程序发生 Full gc
的频率。
2)GC 内存最大化原则:垃圾收集器能够使用的内存越大,垃圾收集效率越高,应用程序
运行也越流畅。但是过大的内存一次 Full go 耗时可能较长,如果能够有效避免 FullGC,就
需要做精细化调优。
(3)3 选 2 原则:吞吐量、延迟和内存占用不能兼得,无法同时做到吞吐量和暂停时间都
最优,需要根据业务场景做选择。对于大多数应用,吞吐量优先,其次是延迟。当然对于时延
敏感型的业务,需要调整次序。

2.确定服务端内存占用
在优化 GC 之前,需要确定应用程序的内存占用大小,以便为应用程序设置合适的内存,
提升 GC 效率。内存占用与活跃数据有关,活跃数据指的是应用程序稳定运行时长时间存活的
Java 对象。活跃数据的计算方式:通过 GC 日志采集 GC 数据,获取应用程序稳定时老年代占
用的Java堆大小,以及永久代(元数据区)占用的Java堆大小,两者之和就是活跃数据的内存
占用大小。

GC 优化过程

1、GC 数据的采集和研读
2、设置合适的 JVM 堆大小
3、选择合适的垃圾回收器和回收策略
当然具体如何做,请参考 JVM 相关课程。而且 GC 调优会是一个需要多次调整的过程,
期间不仅有参数的变化,更重要的是需要调整业务代码。

网络通讯面试题及答案相关推荐

  1. 计算机与网络技术基础试题及答案,计算机与网络技术基础试题及答案(2003年10月)...

    计算机与网络技术基础试题及答案(2003年10月) 以下是部分内容预览,注意图片没有显示出来,WORD里是有的.请到下载区下载完整的试题及答案. 全国2003年10月高等教育自学考试 计算机与网络技术 ...

  2. 陕西计算机软考试题及答案,2013陕西省上半年软考网络工程师下午试题及答案...

    2013陕西省上半年软考网络工程师下午试题及答案 1.Linux系统中的块设备文件在使用命令ls -l查询时用什么符号表示_______?(B) A.c B.b C.l D.d 2.当在Windows ...

  3. 计算机三级考试题库网络,计算机三级网络试题及答案解析

    计算机三级网络试题及答案解析 关于2016年计算机等级考试时间是3月26日-29日,以下小编特意为大家整理出计算机三级网络考试题,希望对大家的复习有帮助! 1)FDDI采用一种新的编码技术,是____ ...

  4. 2014年3月计算机四级网络工程师考试试题及答案,某年3月计算机等级考试四级网络工程师笔试试题...

    2009年3月计算机等级考试四级网络工程师笔试试题(附参考答案)附:2008年9月的sniffer图 附:08年4月sniffer解析 附:08年9月sniffer解析 从sniffer抓包图可以看出 ...

  5. 常见网络编程面试题以及答案(网络面试30题)

    面试宝典到手,搞定面试,不再是难题,系列文章传送地址,请点击本链接. 目录 1.常说的四层.五层.七层网络模型有什么区别? 2.TCP/IP 网络模型中的五层模型,每层分别有什么用? 3.介绍一下 H ...

  6. 职称计算机 将计算机broad_1下的e盘映射为k盘网络驱动器,职称计算机考试网络基础操作试题及答案(2)...

    为了帮助考生系统的复习职称计算机考试课程 全面的了解职称计算机考试教材的相关重点,小编特编辑汇总了2011年职称计算机考试复习的重点资料,希望对您参加本次考试有所帮助! 1-10. 添加局域网中的计算 ...

  7. 北师大网络教育计算机试题六答案,北京师范大学网络教育---小学数学教学论答案...

    <小学数学教学论>作业 本课程作业由两部分组成.第一部分为"客观题部分",由15个选择题组成,每题1分,共15分.第二部分为"主观题部分",由简答题 ...

  8. 网络中服务器是指为网络提供资源,并对这些资源进行管理的计算机,2016年职称计算机考试Internet冲刺试题及答案3...

    1.Internet的通信协议是( A ) A.TCP/IP B.OSI/ISO C.NetBEUI D.NWLink 2.把计算机网络分为有线和无线网的主要分类依据是(C) A.网络成本 B.网络的 ...

  9. 西安网络教育学院计算机答案,西安电子科技大学网络与继续教育学院《计算机应用基础(一)》考试试题及答案...

    西安电子科技大学网络与继续教育学院 2012学年下学期 <计算机应用基础(一)>期末考试试题 一.填空题(每题4分,共40分,请将答案写在试卷后的答题纸上) 1.按计算机性能高低和规模大小 ...

最新文章

  1. 数据结构与算法:09 栈与递归
  2. js过滤HTML标签以及空格
  3. 古巴雪茄高希霸世纪1.2.3.4.5.6.半世纪7款雪茄的区别?
  4. HTML 标签简写及全称
  5. 张颐武:周小平的意义
  6. python 新闻摘要_每日新闻摘要:Microsoft内部禁止应用程序,这样就可以了
  7. docker 镜像 导入导出
  8. CCTextureCache的多线程加载原理和使用
  9. 右手残疾学计算机学什么专业好,我是右手和右脚残疾 左手和左脚好的 可以学残疾人驾照吗...
  10. 对left join on and、left join on where的理解
  11. paper 88:人脸检测和识别的Web服务API
  12. QGIS教程—缓冲区buffer
  13. QT ——添加多国语言
  14. 高中计算机会考操作试题,高中信息技术会考(上机操作题要点)
  15. UI设计---化繁为简
  16. 研究生阶段如何学习、做研究(超棒)
  17. 蓝桥杯——测试次数·摔手机(2018JavaB组第4题,17分)
  18. Android | 打印堆栈
  19. 什么是单例模式以及单例模式的几种实现
  20. 潮起潮落,自助餐还是被“吃”垮了

热门文章

  1. 《世界因你不同》字句节选
  2. python异步编程案例之协程执行和停止
  3. 读入一个三位数,计算其各位数字之和。例如: 123,各位数字之和为6
  4. vue3 + element-plus 实现一键换肤
  5. 浏览器与css的兼容,CSS浏览器兼容性与解决
  6. 音乐咖android,有音乐的料理店,即将开档!
  7. miui12怎么自定义开机动画_一篇文章看懂Redmi Note 7/7 Pro新增MIUI 12十大暖心功能...
  8. xmind可以画流程图吗_如何在XMind 中绘制流程图?
  9. 双项荣耀|海泰方圆斩获第二届密码丰会“成长力企业奖”“创新力企业奖”
  10. 工业网络交换机选购时的一些关键参数