🔵 Socket & Server¶
约 7959 个字 1 张图片 预计阅读时间 40 分钟
select poll epoll 的区别与联系?¶
select, poll 和 epoll 都是 I/O 多路复用技术,它们用于同时处理多个 I/O 操作,特别是在高并发网络编程中。
select¶
select 是最早的 I/O 多路复用技术,它可以同时监视多个文件描述符(file descriptor, FD)的 I/O 状态(如可读、可写、异常等)。select 函数使用一个文件描述符集合(通常是一个位图)来表示要监视的文件描述符,当有 I/O 事件发生时,select 会返回对应的文件描述符集合。
select 的主要限制¶
- 文件描述符数量限制:select 使用一个位图来表示文件描述符集合,这限制了它能够处理的文件描述符数量(通常是 1024 个)
- 效率问题:当文件描述符数量较大时,select 需要遍历整个文件描述符集合来查找就绪的文件描述符,这会导致较低的效率
- 非实时性:每次调用 select 时,需要重新设置文件描述符集合,这会增加函数调用的开销
poll¶
poll 是为了 克服 select 的限制 而引入的一种 I/O 多路复用技术。poll 使用一个文件描述符数组(通常是一个结构体数组)来表示要监视的文件描述符。与 select 类似,poll 可以监视多个文件描述符的 I/O 状态。
poll 的优点¶
- 文件描述符数量不受限制:由于 poll 使用一个动态数组来表示文件描述符,因此它可以处理 任意数量 的文件描述符
- 效率相对较高:poll 在查找就绪的文件描述符时,只需要遍历实际使用的文件描述符数组,而不是整个文件描述符集合
poll 存在的问题¶
- 效率问题:尽管 poll 相对于 select 具有较高的效率,但当文件描述符数量很大时,它仍然需要遍历整个文件描述符数组
- 非实时性:与 select 类似,每次调用 poll 时,需要重新设置文件描述符数组
epoll¶
epoll 是 Linux 特有的一种高效 I/O 多路复用技术,它克服了 select 和 poll 的主要限制。epoll 使用一个事件驱动(event-driven)的方式来处理 I/O 操作,它只会返回就绪的文件描述符,而不是遍历整个文件描述符集合。
epoll 的优点¶
- 高效:epoll 使用 事件驱动 的方式来处理 I / O 操作,因此它在处理大量文件描述符时具有很高的效率。当有 I/O 事件发生时,epoll 可以立即得到通知,而无需遍历整个文件描述符集合。这使得 epoll 在高并发场景中具有更好的性能
- 可扩展性:与 poll 类似,epoll 可以处理 任意数量 的文件描述符,因为它使用一个 动态数据结构 来表示文件描述符
- 实时性:epoll 使用一个内核事件表来记录要监视的文件描述符和事件,因此在每次调用 epoll 时无需重新设置文件描述符集合。这可以减少函数调用的开销,并提高实时性
epoll 具有诸多优点,但它目前仅在 Linux 平台上可用。对于其他平台,可能需要使用类似的 I/O 多路复用技术,如 BSD 中的 kqueue。
总结¶
select 是最早的 I/O 多路复用技术,但受到文件描述符数量和效率方面的限制。poll 克服了文件描述符数量的限制,但仍然存在一定的效率问题。epoll 是一种高效的 I/O 多路复用技术,尤其适用于高并发场景,但它仅在 Linux 平台上可用。一般来说, epoll 的效率要比 select 和 poll 高,但是对于活动连接较多的情景,由于回调函数触发的很频繁,其效率不一定比 select 和 poll 高。所以 epoll 在连接数量很多,但活动连接较小的情况性能体现的比较明显:
| 系统调用 | select | poll | epoll |
|---|---|---|---|
| 事件集合 | 用户通过三个参数分别传入感兴趣的可读可写以及异常等事件,内核通过对这些参数的在线修改来反馈其中就绪的事件。如果用户需要的话需要创建三个 fdset 以监听不同类型的事件 | 统一处理 所有的事件类型,因此只需要一个事件集参数。用户通过 pollfd.events 来传入感兴趣的事件,内核通过修改 pollfd.revents 反馈其中就绪的事件 | 内核通过一个事件表直接管理用户感兴趣的所有事件。每次调用 epoll_wait,内核直接在调用参数的 events 中注册就绪事件 |
| 应用程序索引效率 | 轮询, O(n) | 轮询, O(n) | 回调, O(1) |
| 最大支持文件描述符数 | 一般 1024 | 65535 | 65535 |
| 工作模式 | 条件触发 | 条件触发 | 条件触发或边缘触发 |
边缘触发与条件触发分别是什么?¶
边缘触发(Edge-triggered)和条件触发(Level-triggered)是两种常见的 事件触发方式,主要应用于 I/O 多路复用和中断处理等场景。
边缘触发¶
边缘触发是指在 事件状态发生变化的时刻触发一次,例如从无事件变为有事件。在 I / O 多路复用中,边缘触发意味着当某个文件描述符发生 I/O 事件(如变为可读或可写)时,我们只会收到一次通知。当收到通知后,我们需要处理该文件描述符上的所有数据,直到数据全部处理完毕,否则不会再收到通知。
边缘触发的优点是 只在事件状态改变时触发,可以减少事件通知的次数。然而,边缘触发的缺点是我们 需要确保在收到通知后处理所有相关数据,否则可能会遗漏某些事件。
条件触发¶
条件触发是指只要事件状态保持满足某种条件,就会持续触发。在 I/O 多路复用中,条件触发意味着只要某个文件描述符的 I/O 事件状态满足条件(如可读或可写),我们就会不断收到通知。
条件触发的优点是它可以 确保我们不会遗漏任何事件,因为只要条件满足,就会持续触发。然而,条件触发的缺点是它 可能导致大量的事件通知,从而增加处理开销。
讲一讲 client-server 通信双方 API 调用过程?¶
Client-server 通信是 客户端与服务器之间进行数据交互 的一种常见方式。客户端和服务器分别调用各自的 API 来建立连接、发送请求、接收响应以及关闭连接。以下是典型的 Client-server 通信过程中的 API 调用:
服务器端 API 调用过程¶
- 创建套接字(socket):服务器端首先创建一个套接字。在 C 语言中,可以使用 socket() 函数创建一个新的套接字
- 绑定地址(bind):服务器将套接字绑定到指定的 IP 地址和端口。这可以使用 bind() 函数完成
- 监听连接(listen):服务器将套接字设置为监听模式,以便接受来自客户端的连接请求。这可以通过调用 listen() 函数实现
- 接受连接(accept):当客户端发起连接请求时,服务器使用 accept() 函数接受该连接。accept() 函数返回一个新的套接字,用于与客户端进行通信
- 接收数据(recv):服务器使用 recv() 或类似的函数从客户端接收数据。这些函数通常会阻塞,直到收到数据
- 发送数据(send):服务器根据客户端的请求处理数据并生成响应。然后,服务器使用 send() 或类似的函数将响应数据发送回客户端
- 关闭连接(close):完成通信后,服务器使用 close() 或类似的函数关闭与客户端的连接。服务器可以继续接受其他客户端的连接
客户端 API 调用过程¶
- 创建套接字(socket):与服务器类似,客户端使用 socket() 函数创建一个新的套接字
- 连接服务器(connect):客户端使用 connect() 函数发起对服务器的连接请求。这需要指定服务器的 IP 地址和端口
- 发送数据(send):连接建立后,客户端使用 send() 或类似的函数向服务器发送请求数据
- 接收数据(recv):客户端使用 recv() 或类似的函数接收来自服务器的响应数据。这些函数通常会阻塞,直到收到数据
- 关闭连接(close):通信完成后,客户端使用 close() 或类似的函数关闭与服务器的连接
阻塞 IO、非阻塞 IO 有什么区别?怎么判断写文件时 Buffer 已经写满?¶
阻塞 IO 和非阻塞 IO 是两种不同的 I/O 处理方式,它们主要区别在于 I/O 操作是否会导致调用者等待。
阻塞 IO¶
在阻塞 IO 模式下,当一个 I/O 操作(如读或写)发起时,如果数据还没有准备好(例如,等待数据从硬盘读取或从网络接收),则调用者(通常是一个线程或进程)会被阻塞,直到数据准备好为止。在此期间, 调用者无法执行其他任务,只能等待 I/O 操作完成。
阻塞 IO 的优点是 编程简单,容易实现。然而,它的缺点是当 I/O 操作耗时较长时,会导致调用者的 低效率和资源浪费,尤其在高并发场景中。
非阻塞 IO¶
在非阻塞 IO 模式下,当一个 I/O 操作发起时,如果数据还没有准备好,调用者不会被阻塞,而是立即返回一个错误码(例如,表示资源不可用)。调用者可以继续执行其他任务,然后在适当的时间点再次尝试 I/O 操作。
非阻塞 IO 的优点是可以 提高调用者的效率和资源利用率,尤其适用于高并发场景。然而,它的缺点是 编程复杂度较高,需要使用 I/O 多路复用技术(如 select, poll 或 epoll )来处理多个 I/O 操作。
关于判断写文件时 Buffer 是否已经写满,通常是通过以下方式:
在 阻塞 IO 模式 下,当写入操作发起时,如果 Buffer 已满,调用者会被阻塞,直到 Buffer 有足够的空间容纳新的数据。在这种情况下不需要担心 Buffer 是否已满,因为操作系统会 自动处理 这个问题。
在 非阻塞 IO 模式 下,当写入操作发起时,如果 Buffer 已满,调用者会立即收到一个错误码(例如,表示资源不可用)。在这种情况下 需要根据错误码来判断 Buffer 是否已满,并在适当的时间点再次尝试写入操作。通常,你可以结合 I/O 多路复用技术来监听文件描述符的可写事件,以便在 Buffer 有空间时得到通知。
同步与异步的区别,阻塞与非阻塞的区别?¶
同步和异步主要关注的是 调用者与被调用者之间的关系。
- 同步(Synchronous):在同步操作中,调用者发起一个请求后, 需要等待被调用者处理完毕并返回结果,期间调用者不能进行其他操作。换句话说,调用者与被调用者的执行是串行的。同步操作的典型例子是普通的函数调用
- 异步(Asynchronous):在异步操作中,调用者发起一个请求后, 无需等待被调用者处理完毕,可以继续执行其他操作。被调用者在处理完请求后,通常通过回调函数、事件或消息队列等方式通知调用者结果。换句话说,调用者与被调用者的执行是并行的。异步操作的典型例子是 JavaScript 中的 Ajax 请求
阻塞和非阻塞主要关注的是 I/O 操作或系统调用的行为。
- 阻塞(Blocking):在阻塞操作中,如果数据还没有准备好(例如,等待数据从硬盘读取或从网络接收),则调用者(通常是一个线程或进程)会被阻塞,直到数据准备好为止。在此期间, 调用者无法执行其他任务,只能等待 I/O 操作完成。阻塞 I/O 操作的典型例子是普通的文件读写
- 非阻塞(Non-blocking):在非阻塞操作中,如果数据还没有准备好,调用者不会被阻塞,而是立即返回一个错误码(例如,表示资源不可用)。 调用者可以继续执行其他任务,然后在适当的时间点再次尝试 I/O 操作。非阻塞 I/O 操作的典型例子是使用 select,poll 或 epoll 等 I/O 多路复用技术处理的网络通信
讲一讲 Rector 模式与 Proactor 模式?¶
Reactor 模式和 Proactor 模式都是处理并发 I/O 事件的设计模式。它们各自的核心思想是将 I/O 操作与实际处理逻辑解耦,以便在高并发环境下更有效地处理请求。下面分别介绍这两种模式:
Reator 模式¶
Reactor 模式基于事件驱动和异步 I/O 操作。其核心组件包括 Reactor、事件处理器和资源(如套接字)。Reactor 模式的工作原理如下:
- Reactor 负责监视多个资源(如套接字)上的 I/O 事件。当某个资源上发生 I/O 事件时,Reactor 将事件通知对应的事件处理器。
- 事件处理器负责处理这些 I/O 事件,如接受连接、读取数据、写入数据等。事件处理器将 I/O 操作与实际的业务逻辑解耦,使程序更易于管理和扩展。
- Reactor 模式通常使用非阻塞 I/O 操作。当资源不可用时,事件处理器不会阻塞,而是返回并允许 Reactor 继续监视其他资源。
Reactor 模式适用于 I/O 密集型应用,特别是当 I/O 操作可能导致阻塞时。其主要优点是简化了并发 I/O 处理,提高了程序的可扩展性和性能
Proactor 模式¶
Proactor 模式是 Reactor 模式的扩展,采用异步 I/O 操作和操作系统级别的异步通知机制。Proactor 模式的核心组件包括 Proactor、异步操作处理器和资源(如套接字)。Proactor 模式的工作原理如下:
- Proactor 负责启动异步 I/O 操作(如读取、写入等)。异步 I/O 操作在后台进行,不会阻塞主程序的执行。
- 当异步 I/O 操作完成时,操作系统将通知 Proactor。Proactor 随后调用相应的异步操作处理器来处理已完成的操作。
- 异步操作处理器负责处理已完成的异步 I/O 操作。与 Reactor 模式类似,这些处理器将 I/O 操作与实际的业务逻辑解耦,使程序更易于管理和扩展。
Proactor 模式的主要优点是充分利用了操作系统的异步 I/O 功能,进一步简化了并发 I/O 处理,提高了程序的可扩展性和性能。但是,Proactor 模式对操作系统的支持程度不同,因此可能需要考虑跨平台兼容性。
如何调试服务器内存占用过高的问题?¶
服务器内存占用过高可能是由多种原因引起的,如内存泄漏、程序逻辑错误等:
- 监控内存使用情况:首先,使用操作系统提供的工具(如 Linux 上的 top,htop 或 free 命令)来实时监控服务器的内存使用情况。这可以帮助确定问题是否确实是由内存占用过高导致的,以及问题的严重程度
- 确定问题进程:接下来,通过监控工具找出内存占用过高的进程。可以通过 top 或 ps 命令查看进程的详细信息,例如进程 ID、用户、CPU 使用率、内存使用率等
- 分析进程内存使用:使用进程内存分析工具(如 pmap 或 smem)来查看问题进程的内存使用情况。这可以帮助你了解进程的内存使用分布,例如堆、栈、共享库等。通过这些信息,你可以初步判断问题可能出在哪个模块或功能
- 分析内存泄漏:如果怀疑问题是由内存泄漏导致的,可以使用内存泄漏检测工具(如 valgrind 或 gperftools)对进程进行分析。这些工具可以帮助你找出内存泄漏的位置,以及泄漏的详细信息
- 分析程序代码:根据前面的分析结果,仔细审查程序代码,检查是否存在内存分配和释放不当、数据结构设计不合理等问题。这可能需要深入理解程序的逻辑和算法
- 优化程序:针对发现的问题,优化程序代码,修复内存泄漏或逻辑错误。在修复后,重新监控内存使用情况,确保问题得到解决
- 定期检查:即使问题得到解决,也建议定期检查服务器的内存使用情况,以便及时发现潜在的问题。可以通过编写脚本或使用第三方监控工具来自动化这一过程
Linux 下如何查到端口被哪个进程占用?¶
两个方法查看占用端口进程:
- lsof -i:端口号
- netstat -tunlp | grep 端口号
什么是 DMA 技术?¶
DMA(Direct Memory Access,直接内存访问)技术 是在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。
为什么要有 DMA 技术? 在没有 DMA 技术前,I/O 的过程是这样的:
- CPU 发出对应的指令给磁盘控制器,然后返回
- 磁盘控制器收到指令后,于是就开始准备数据,会把数据放入到磁盘控制器的内部缓冲区中,然后产生一个 中断
- CPU 收到中断信号后,停下手头的工作,接着把磁盘控制器的缓冲区的数据一次一个字节地读进自己的寄存器,然后再把寄存器里的数据写入到内存,而在数据传输的期间 CPU 是无法执行其他任务的
可以看到,整个数据的传输过程,都要需要 CPU 亲自参与搬运数据的过程,而且这个过程,CPU 是不能做其他事情的。简单的搬运几个字符数据那没问题,但是如果我们用千兆网卡或者硬盘传输大量数据的时候,都用 CPU 来搬运的话,肯定忙不过来。
使用 DMA 控制器进行数据传输的过程:
- 用户进程调用 read 方法,向操作系统发出 I/O 请求,请求读取数据到自己的内存缓冲区中,进程进入阻塞状态
- 操作系统收到请求后,进一步将 I/O 请求发送 DMA,然后让 CPU 执行其他任务
- DMA 进一步将 I/O 请求发送给磁盘
- 磁盘收到 DMA 的 I/O 请求,把数据从磁盘读取到磁盘控制器的缓冲区中,当磁盘控制器的缓冲区被读满后,向 DMA 发起中断信号,告知自己缓冲区已满
- DMA 收到磁盘的信号,将磁盘控制器缓冲区中的数据拷贝到内核缓冲区中,此时不占用 CPU,CPU 可以执行其他任务
- 当 DMA 读取了足够多的数据,就会发送中断信号给 CPU
- CPU 收到 DMA 的信号,知道数据已经准备好,于是将数据从内核拷贝到用户空间,系统调用返回
可以看到,整个数据传输的过程,CPU 不再参与数据搬运的工作,而是全程由 DMA 完成,但是 CPU 在这个过程中也是必不可少的,因为传输什么数据,从哪里传输到哪里,都需要 CPU 来告诉 DMA 控制器。
早期 DMA 只存在在主板上,如今由于 I/O 设备越来越多,数据传输的需求也不尽相同,所以每个 I/O 设备里面都有自己的 DMA 控制器。
Linux 零拷贝的原理?¶
零拷贝是一种 避免 CPU 将数据从一块存储拷贝到另外一块存储的技术。通过减少用户态与内核态上下文切换和减少内存拷贝次数实现,通常实现方式有 3 种: mmap+write、sendfile、sendfile+DMA scatter/gather:
传统文件传输的问题:传统 I/O 的工作方式是,数据读取和写入是从用户空间到内核空间来回复制,而内核空间的数据是通过操作系统层面的 I/O 接口从磁盘读取或写入。传统文件传输会经历:
- 4 次用户态与内核态的上下文切换:因为发生了两次系统调用,一次是
read(),一次是write(),每次系统调用都得先从用户态切换到内核态,等内核完成任务后,再从内核态切换回用户态 -
4 次数据拷贝:其中两次是 DMA 的拷贝,另外两次则是通过 CPU 拷贝的:
- 第一次拷贝:把磁盘上的数据拷贝到操作系统内核的缓冲区里,这个拷贝的过程是通过 DMA 搬运的
- 第二次拷贝:把内核缓冲区的数据拷贝到用户的缓冲区里,于是我们应用程序就可以使用这部分数据了,这个拷贝到过程是由 CPU 完成的
- 第三次拷贝:把刚才拷贝到用户的缓冲区里的数据,再拷贝到内核的 socket 的缓冲区里,这个过程依然还是由 CPU 搬运的
- 第四次拷贝:把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程又是由 DMA 搬运的
这种简单又传统的文件传输方式,存在冗余的上下文切换和数据拷贝,在高并发系统里是非常糟糕的,多了很多不必要的开销,会严重影响系统性能。所以,要想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数。
-
mmap + write:mmap() 系统调用函数会 直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作。 包含 2 次系统调用,3 次数据拷贝(2 次 DMA 和 1 次 CPU 拷贝):
- 用户进程通过 mmap 方法向操作系统内核发起 IO 调用,上下文从用户态切换为内核态
- CPU 利用 DMA 控制器,把数据从硬盘中拷贝到内核缓冲区
- 上下文从内核态切换回用户态,mmap 方法返回
- 用户进程通过 write 方法向操作系统内核发起 IO 调用,上下文从用户态切换为内核态
- CPU 将内核缓冲区的数据拷贝到的 socket 缓冲区
- CPU 利用 DMA 控制器,把数据从 socket 缓冲区拷贝到网卡,上下文从内核态切换回用户态,write 调用返回
-
sendfile:在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile()。它可以替代前面的 read() 和 write() 这两个系统调用,减少一次系统调用。 包含 1 次系统调用,3 次数据拷贝(2 次 DMA 和 1 次 CPU 拷贝):
- 用户进程发起 sendfile 系统调用,上下文(切换 1)从用户态转向内核态
- DMA 控制器,把数据从硬盘中拷贝到内核缓冲区
- CPU 将读缓冲区中数据拷贝到 socket 缓冲区
- DMA 控制器,异步把数据从 socket 缓冲区拷贝到网卡
- 上下文(切换 2)从内核态切换回用户态,sendfile 调用返回
-
sendfile+DMA scatter/gather:Linux 2.4 版本之后,对 sendfile 做了优化升级,引入 SG-DMA 技术,其实就是对 DMA 拷贝加入了 scatter/gather 操作,它可以直接从内核空间缓冲区中将数据读取到网卡。使用这个特点搞零拷贝,即还可以多省去一次 CPU 拷贝。 包含 1 次系统调用,2 次数据拷贝(2 次 DMA 拷贝):
- 用户进程发起 sendfile 系统调用,上下文(切换 1)从用户态转向内核态。
- DMA 控制器,把数据从硬盘中拷贝到内核缓冲区。
- CPU 把内核缓冲区中的文件描述符信息(包括内核缓冲区的内存地址和偏移量)发送到 socket 缓冲区。
- DMA 控制器根据文件描述符信息,直接把数据从内核缓冲区拷贝到网卡。
- 上下文(切换 2)从内核态切换回用户态,sendfile 调用返回
LVS 的 NAT、TUN、DR 原理及区别¶
LVS 是 Linux Virtual Server 的简写,意即 Linux 虚拟服务器,是一个虚拟的服务器集群系统,使用负载均衡技术将多台服务器组成一个虚拟服务器。虚拟服务器的体系结构由一组服务器通过高速的局域网或者地理分布的广域网相互连接,在它们的前端有一个负载调度器(Load Balancer),负载调度器能无缝地将网络请求调度到真实服务器上。
NAT(网络地址转换模式)¶
原理:把客户端发来的数据包的 IP 头的目的地址,在负载均衡器上换成其中一台 RS 的 IP 地址,并发至此 RS 来处理,RS 处理完成后把数据交给经过负载均衡器,负载均衡器再把数据包的原 IP 地址改为自己的 IP,将目的地址改为客户端 IP 地址即可。
TUN(IP 隧道模式)¶
原理:隧道模式就是把客户端发来的数据包,封装一个新的 IP 头标记(仅目的 IP)发给 RS,RS 收到后,先把数据包的头解开,还原数据包。处理后直接返回给客户端,不需要再经过负载均衡器。注意:由于 RS 需要对负载均衡器发过来的数据包进行还原,所以说必须支持 IPTUNNEL 协议。 在 RS 的内核中,必须编译支持 IPTUNNEL 这个选项。
各集群节点可以跨越不同的网络, 不用在同一个 VLAN。
调度器根据各个服务器的负载情况,动态地选择一台服务器,将请求报文封装在另一个 IP 报文中,再将封装后的 IP 报文转发给选出的服务器
服务器收到报文后先将报文解封获得原来目标地址为 VIP 的报文,服务器发现 VIP 地址被配置在本地的 IP 隧道设备上,所以就处理这个请求,然后根据路由表将响应报文直接返回给客户。
DR(直接路由模式)¶
原理:负载均衡器和 RS 都使用同一个 IP 对外服务,但只有 DR 对 ARP 请求进行响应,所有 RS 对本身这个 IP 的 ARP 请求保持静默。也就是说网关会把对这个服务 IP 的请求全部定向给 DR,而 DR 收到数据包后根据调度算法,找出对应的 RS 把目的 MAC 地址改为 RS 的 MAC(因为 IP 一致)并将请求分发给这台 RS。这时 RS 收到这个数据包处理完成之后,由于 IP 一致,可以直接将数据返给客户,则等于直接从客户端收到这个数据包无异,处理后直接返回给客户端。由于负载均衡器要对二层包头进行改换,所以负载均衡器和 RS 之间必须在一个广播域,也可以简单理解为在同一台交换机上。
区别¶
| 优点 | 缺点 | |
|---|---|---|
| NAT | 集群中的物理服务器可以使用任何支持 TCP/IP 操作系统它只需要一个 IP 地址配置在调度器上,服务器组可以用私有的 IP 地址 | 扩展性有限。当服务器节点(普通 PC 服务器)增长过多时,负载均衡器将成为整个系统的瓶颈,因为所有的请求包和应答包的流向都经过负载均衡器。当服务器节点过多时,大量的数据包都交汇在负载均衡器那,速度就会变慢 |
| TUN | 负载均衡器只负责将请求包分发给后端节点服务器,而 RS 将应答包直接发给用户。所以,减少了负载均衡器的大量数据流动,负载均衡器不再是系统的瓶颈,就能处理很巨大的请求量,这种方式,一台负载均衡器能够为很多 RS 进行分发。而且跑在公网上就能进行不同地域的分发 | 隧道模式的 RS 节点需要合法 IP,这种方式需要所有的服务器支持 IP Tunneling(IP Encapsulation)协议,服务器可能只局限在部分 Linux 系统上 |
| DR | VS/DR 跟 VS/TUN 方法相同,负载调度器中只负责调度请求,而服务器直接将响应返回给客户,可以极大地提高整个集群系统的吞吐量 | 要求负载均衡器的网卡必须与物理网卡在一个物理段上 |
| NAT 模式 | IP TUN 模式 | DR 模式 | |
|---|---|---|---|
| 对服务器要求 | 任何操作系统均支持 | 必须支持 IP 隧道协议,目前 只有 Linux 支持 | 支持虚拟网卡,且可以禁用 ARP 响应 |
| 网络要求 | 局域网 | 局域网或广域网 | 局域网 |
| 支持的节点数 | 10~20 个,视 Director 处理能力而定 | 可以支持到 100 个节点 | 可以支持到 100 个节点 |
| 安全性 | 较高,可隐藏 real server | 较差,real server 容易暴露 | 较差,real server 容易暴露 |
| IP 要求 | 仅需要一个合法 IP 地址作为 VIP | 除 VIP 外, 每个服务器需要拥有合法 IP 地址 可以直接路由至客户端 | 除 VIP 外, 每个服务器需要拥有合法 IP 地址 可以直接路由至客户端 |
| 拓展性 | 差 | 很好 | 好 |
| 特点 | 地址转换 | 封装 IP | 修改 MAC 地址 |