I/O多路复用 + Reactor和Proactor + 一致性哈希

news2025/4/3 17:37:06

网络系统

  • 1. I/O多路复用
    • 1)原始Socket模型通信方式
    • 2)多进程模型
    • 3)多线程模型
    • 4)I/O多路复用
      • select/poll
      • epoll
      • 边缘触发和水平触发
  • 2. Reactor和Proactor
    • 1)Reactor模式
    • 2)Reactor模式四种方案
    • 3)单Reactor单进程:
    • 4)单Reactor多线程:
    • 5)多Reactor多线程
    • 6)Proactor
  • 3. 一致性哈希
      • 分布式系统如何分配请求—>Hash—>扩缩困难—>一致性Hash—>数据节点分布不均衡—>虚拟节点+一致性Hash
  • 4.参考

1. I/O多路复用

1)原始Socket模型通信方式

  • 首先服务端调用socket函数,创建网络协议为IPv4,传输协议为TCP的socket;
  • 调用bind()绑定IP地址和端口号;
  • 调用listen()进行监听;
  • 服务器进入监听状态后,调用accpet()函数,从内核获取客户端的连接,如果没有则会阻塞等待。
  • 客户端这边创建socket后,调用connect(参数为服务端ip和端口号)发起连接,然后开始TCP三次握手。
    • TCP连接过程中服务器内核为每个socket连接维护两个队列,一个是TCP半连接队列,服务端处于syn_rcvd的状态,另一个是TCP全连接队列,此时服务端处于established状态。
    • TCP全连接队列存放的是已连接socket。服务端的accpet()函数会拿一个已连接socket用于数据传输。所以监听有监听socket,传输数据有已连接socket,是两个socket。双方通过read()和write()函数来进行读写。
    • 缺点:原始Socket模型只能一对一通信,服务端没处理完一个客户端的I/O请求或发生读写阻塞时,其他客户端无法连接。

2)多进程模型

  • 父进程只用关心监听socket负责连接,子进程只用关心已连接socket负责通信,因为子进程会复制父进程的文件描述符。
  • 缺点
    • 子进程退出系统仍会保留该进程一些信息,不做好回收工作,会变成僵尸进程慢慢耗尽系统资源;
    • 进程资源开销太大;
    • 进程上下文切换代价较大。

3)多线程模型

  • 服务器与客户端建立连接后,通过pthread_create()函数创建线程,将已连接socket的文件描述符传递给线程函数,接着就可以使用该线程进行通信。
  • 使用线程池避免线程繁重的创建和销毁的开销。

4)I/O多路复用

  • I/O多路复用,一个进程处理多个请求,进程可以调用一个系统函数从内核获取多个事件。

select/poll

  • select:已连接socket的文件描述符集合,调用selcet()拷贝到内核,内核遍历整合集合检查看是否有事件产生,有的话将该socket标记为可读或可写,再将整个集合拷贝到用户态,然后用户态再遍历整个集合,找到可读或可写的socket进行处理。
  • selcet使用固定长度的BitsMap存储文件描述符,最大1024。
  • poll改用链表存储文件描述符,个数仍受系统限制。
  • select/poll都要2次拷贝2次遍历,都使用线性结构存储socket文件描述符,时间复杂度O(n)。

epoll

  • epoll()在内核里使用红黑树来保存socket,有新的socket,只需拷贝这一个到内核,无需像select/poll那样拷贝整个集合到内核。
  • epoll使用事件驱动机制,内核维护了一个链表来记录就绪事件,当已连接socket有事件产生,内核通过回调函数将其加入到链表中,用户调用epoll_wait()函数将链表中的socket拷贝到用户态中,无需再拷贝整个集合且无需再遍历整个集合。
  • epoll用法:
    • 调用epoll_create创建一个epoll对象epfd;
    • 再通过epoll_ctl将需要监听的socket添加到epfd中;
    • 最后调用epoll_wait()等待数据。

边缘触发和水平触发

  • 边缘触发:当被监控的socket有可读事件发生,调用epoll_wait()会触发一次epollin事件(表示有数据可读),需循环读取数据,防止数据未读完,因此搭配非阻塞I/O使用。若未读完,后面再调用epoll_wait()不会再触发epollin事件,直到有新的数据到来。
  • 水平触发:当被监控的socket有可读事件发生,每次调用epoll_wait()都会触发epollin事件,直到缓冲区数据全部读完。若未读完,下一次epoll_wait()会再次触发epollin事件。只要缓冲区有数据没读完,就会一直触发epollin事件。

2. Reactor和Proactor

1)Reactor模式

  • 通过面向对象的思想对I/O多路复用做了一层封装。
  • Reactor模式由Reactor和处理资源池组成。Reactor负责监听和分发事件,事件类型包含连接事件和读写事件。处理资源池可以是单个进/线程,也可以是多个进/线程,负责处理事件,如:read()—>业务逻辑—>send()。

2)Reactor模式四种方案

  • 单reactor单进/线程;
  • 单reactor多进/线程;
  • 多reactor单进/线程(无应用);
  • 多reactor多进/线程;

3)单Reactor单进程:

  • Reactor对象的作用是监听和分发事件,select()监听,dispatch()分发;

  • Acceptor对象通过accept()方法获取连接;

  • Handler对象的作用是处理事件,read()—>业务逻辑—>send()。

  • 工作流程:

    • Reactor对象通过select()监听事件,收到事件后,根据事件类型,是连接事件还是读写事件,通过dispatch()进行分发;
    • 如果是连接事件分发给Acceptor对象,Acceptor对象会调用accept()方法,建立连接,并创建一个Handler对象用于处理事件;
    • 如果是读写事件,则直接分发给Handler对象进行处理。
      在这里插入图片描述
  • 缺点:

    • 无法利用多核CPU的性能;
    • Handler对象在处理业务时,整个进程无法处理其他连接的事件,如果业务处理耗时长,怎么造成响应的延迟。
    • 所以单Reactor单进/线程不适合计算机密集型的场景,只适用于业务逻辑处理非常快速的场景,如Redis6.0之前的版本。

4)单Reactor多线程:

  • 工作流程:

    • 前面步骤和单Reactor单线/进程一样;
    • 不同的是:Handler对象只负责数据的接收和发送,不再进行业务处理,read()数据后发送给线程池里的子线程的Processor对象进行业务处理。
    • 处理完结果由主线程的Handler对象通过send()将响应结果发送给客户端。
      在这里插入图片描述
  • 优点:能够充分利用多核CPU的性能。

  • 缺点:一个Reactor承担所有事件的监听和分发,且只在主线程中运行,在瞬间高并发的场景下,容易成为性能瓶颈。

5)多Reactor多线程

  • 工作流程:

    • 主线程中的MainReactor对象通过select()监听事件,收到事件后通过Acceptor对象中的accept()建立连接,并将先建立的连接分配给子线程。
    • 子线程中的SubReactor对象将MainReactor对象分配的连接加入select()继续监听,并创建Handler()对象用于事件处理。
    • 新的读写事件到来,SubReactor会调用dispatch()分发给相应的Handler对象进行处理。
      在这里插入图片描述
  • 多Reactor多线程实际实现比单Reactor多线程简单的原因:

    • 主线程和子线程分工明确,主线程只负责接收新连接,子线程负责连接的事件监听和处理.
    • 主线程和子线程交互简单,主线程只需将新连接传给子线程;子线程处理完结果无需返回给主线程,直接返回给客户端。
  • 应用:

    • 多Reactor多线程:
      • Netty(高性能的NIO网络框架,用于构建高并发的应用);
      • Memcache(分布式缓存系统,主要用于存储键值对);
    • 多Reactor多进程
      • Nginx

6)Proactor

  • Reactor和Proactor都是一种基于事件分发的网络模式;
  • Reactor非阻塞网络同步模式,Proactor是异步网络模式;
  • Reactor模式是基于待完成的I/O事件,而Proactor模式则是基于已完成的I/O事件。
  • 阻塞I/O阻塞等待的是:内核数据准备好的过程。
  • 无论是阻塞I/O还是非阻塞I/O,都是同步调用,同步调用就是指数据从内核态缓冲区拷贝到用户态缓冲区这个过程是需要等待的。
  • 而异步I/O无需等待这个过程,发起异步I/O之后,这两个动作由内核自动完成,应用程序不需要主动发起拷贝动作。
  • Proactor工作流程:
    • 收到请求Proactor Initiatord创建一个Proactor和Handler,并将它们通过Asynchronous Operation Processer注册到内核;
    • Asynchronous Operation Processer负责处理注册请求和I/O请求,Asynchronous Operation Processer完成I/O请求(数据已经拷贝到用户缓冲区)后通知Proactor;
    • Proactor根据事件类型回调应用进程中的Handler完成业务处理。
      在这里插入图片描述

3. 一致性哈希

分布式系统如何分配请求—>Hash—>扩缩困难—>一致性Hash—>数据节点分布不均衡—>虚拟节点+一致性Hash

  • 如何分配请求:引入一个负载均衡层,硬件配置好的权重更大,这种算法叫加权轮询,前提是每个服务节点都存储一样的数据。
  • 但是分布式系统,每个服务节点存储的数据都不一样。这时我们想到Hash算法,hash(key)%节点数,进行映射。但若节点数量发生变化,进行扩容或缩容困难,最坏的情况下所有数据都要迁移。
  • 一致性哈希算法,它时对232这个固定值进行取模(首尾相连的有232个点的哈希环),要进行两步hash:
    • 第一步是对存储节点进行hash;
    • 第二步是对数据进行hash;
    • 数据保存在顺时针找到的第一个节点上。
  • 一致性哈希算法对于存储节点增删,只对与该节点顺时针相邻的后继数据节点有影响。
  • 但一致性哈希算法不能保证节点在哈希环上均匀分布,仍存在节点分布不均匀的问题。这时使用虚拟节点提高均衡度。
  • 虚拟节点: 做两层映射,真实存储节点和虚拟存储节点的映射,虚拟存储节点和哈希环的映射。
  • 好处
    • 存储节点数量变多,数据节点分布更均衡。
    • 当存储节点发生变化,有不同的存储节点分担它的数据,稳定性更高。
    • 而且对硬件配置高的存储节点,可以增加其虚拟节点。
    • 因此一致性哈希算法+虚拟节点适用于硬件配置不同的节点场景和节点规模会发生变化的场景。
  • 总结:分布式系统如何分配请求—>Hash—>扩缩困难—>一致性Hash—>数据节点分布不均衡—>虚拟节点+一致性Hash
    在这里插入图片描述

4.参考

https://www.xiaolincoding.com/os/8_network_system/selete_poll_epoll.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2327377.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决小程序video控件在真机和上线后黑屏不播放问题

小程序上线后,mp4格式的视频无法点击是黑屏,但是测试得时候在微信开发者工具中能够打开正常播放 原因:编码格式不能是vp9 微信开发者工具本地设置中把这个打开勾选。 排查:可以换一个视频尝试能不能真机播放,如果能&a…

java项目分享-分布式电商项目附软件链接

今天来分享一下github上最热门的开源电商项目安装部署,star 12.2k,自行安装部署历时两天,看了这篇文章快的话半天搞定!该踩的坑都踩完了,软件也打包好了就差喂嘴里。 项目简介 mall-swarm是一套微服务商城系统&#xf…

【LVS】负载均衡群集部署(DR模式)

部署前IP分配 DR服务器:192.168.166.101 vip:192.168.166.100 Web服务器1:192.168.166.104 vip:192.168.166.100 Web服务器2:192.168.166.107 vip:192.168.166.100 NFS服务器:192.168.166.108 …

链表的操作-反转链表

链表 160相交链表 代码 class Solution { public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode* h1headA;ListNode* h2headB;while(h1&&h2){if(h1!h2){h1h1->next;h2h2->next;}else{return h1;}}if(h1nullptr){h1headB;}else{h…

Linux安装Cmake (Centos 7.9)

cmake安装 这个虽然已经更新到了4.0.0版本了,但是我们要用3.5版本的,因为这个比较稳定 官方地址:https://github.com/Kitware/CMake/releases/tag/v3.5.0,选择那个cmake-3.5.0-Linux-x86_64.tar.gz下载, 首先解压文…

Node.js v22.14.0 多平台安装指南:Windows、Linux 和 macOS 详细教程

Node.js作为现代Web开发的基石,持续为开发者带来性能提升和新特性支持。本文将详细介绍在Windows、macOS和Linux系统上安装最新Node.js的多种方法,助您快速搭建高效的JavaScript开发环境。 📦 当前最新版本 截至2025年4月,Node.…

Netty源码—10.Netty工具之时间轮一

大纲 1.什么是时间轮 2.HashedWheelTimer是什么 3.HashedWheelTimer的使用 4.HashedWheelTimer的运行流程 5.HashedWheelTimer的核心字段 6.HashedWheelTimer的构造方法 7.HashedWheelTimer添加任务和执行任务 8.HashedWheelTimer的完整源码 9.HashedWheelTimer的总结…

鸿蒙项目笔记(1)

一、核心内容-商城 1、装饰器的拓展使用,基础组件的熟悉。 2、引入基础动画实战,页面属性动画、页面跳转动画、自定义页面翻页等。 3、一次开发,多端部署。 4、本地数据库实战,涉及多种本地数据存储方式。 5、路由导航&#…

*快排延伸-自省排序

此节是学有余力的人去看,如果没时间,不看也没关系,只要知道代码就可以了! 自省排序的思路是自我侦测和反省,快速排序如果递归深度太深,其算法的效率可能被大幅度削弱,这就需要借助其他的算法进…

三.微服务架构中的精妙设计:服务注册/服务发现-Eureka

一.使用注册中心背景 1.1服务远程调用问题 服务之间远程调⽤时, 我们的URL是写死的 String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 缺点: 当更换机器, 或者新增机器时, 这个URL就需要跟着变更, 就需要去通知所有的相关服…

python-leetcode 63.搜索二维矩阵

题目: 给一个满足两条属性的m*n的整数矩阵: 每行中的整数从左到右按非严格递增顺序排列 每行的第一个整数大于前一行的最后一个整数 给一个整数target,如果target在矩阵中,返回true,否则返回false 方法一:两次二分查找 由于每…

音视频入门基础:MPEG2-TS专题(26)——通过FFmpeg命令使用RTP发送TS流

音视频入门基础:MPEG2-TS专题系列文章: 音视频入门基础:MPEG2-TS专题(1)——MPEG2-TS官方文档下载 音视频入门基础:MPEG2-TS专题(2)——使用FFmpeg命令生成ts文件 音视频入门基础…

blender二次元上色

前: 后:(脸自己会发光) 参考:05-模型导入与材质整理_哔哩哔哩_bilibili

2025年2月一区SCI-壮丽细尾鹩莺算法Superb Fairy-wren Optimization-附Matlab免费代码

引言 本期介绍一种新的元启发式算法——壮丽细尾鹩莺优化算法Superb Fairy-wren Optimization algorithm,SFOA。该算法结合了壮丽细尾鹩莺群体中幼鸟的发育,繁殖后喂养幼鸟的行为,以及它们躲避捕食者的策略,于2025年2月最新发表在…

Hadoop•踩过的SHIT

听说这里是目录哦 ssh登录Permission denied, please try again💩要发癫🥲 centos7 yum报错:cannot find a valid baseurl for repo:base/7/x86_64💩FinalShell重连失效💩ssh免密登录显示 No route to host&#x1f4a…

闭环SOTA!北航DiffAD:基于扩散模型实现端到端自动驾驶「多任务闭环统一」

端到端自动驾驶目前是有望实现完全自动驾驶的一条有前景的途径。然而,现有的端到端自动驾驶系统通常采用主干网络与多任务头结合的方式,但是它们存在任务协调和系统复杂度高的问题。为此,本文提出了DiffAD,它统一了各种驾驶目标并…

Docker Registry 清理镜像最佳实践

文章目录 registry-clean1. 简介2. 功能3. 安装 docker4. 配置 docker5. 配置域名解析6. 部署 registry7. Registry API 管理8. 批量清理镜像9. 其他10. 参考registry-clean 1. 简介 registry-clean 是一个强大而高效的解决方案,旨在简化您的 Docker 镜像仓库管理。通过 reg…

JavaScript重难点突破:期约与异步函数

同步和异步 ​同步(Synchronous)​ ​定义:任务按顺序依次执行,前一个任务完成前,后续任务必须等待。 ​特点:阻塞性执行,程序逻辑直观,但效率较低 ​异步(Asynchron…

蓝桥杯高频考点——高精度(含C++源码)

高精度 前言高精度加法例题思路及代码solution 1(初阶版 40分)solution 2(完全体 AC) 高精度乘法例题思路及代码solution 1(TLE 但是代码很清晰)solution 1的问题solution 2(优化 AC&#xff09…

【机器人】复现 GraspNet 端到端抓取点估计 | PyTorch2.3 | CUDA12.1

GraspNet是通用物体抓取的大规模基准的基线模型,值得学习和复现。 本文分享使用较新版本的PyTorch和CUDA,来搭建开发环境。 论文地址:GraspNet-1Billion: A Large-Scale Benchmark for General Object Grasping 开源地址:https:…