linux下高级IO模型

高级IO

  • 1.高级IO模型
    • 基本概念
    • 1.1 阻塞IO
    • 1.2 非阻塞IO
    • 1.3 信号驱动IO
    • 1.4 IO多路转接
    • 1.5 异步IO
  • 2. 模型代码实现
    • 2.1 非阻塞IO
    • 2.2 多路转接-select
      • select函数介绍
      • 什么才叫就绪呢?
      • demo
      • select特点
    • 2.3 多路转接-poll
      • poll函数介绍
      • poll优缺点
      • demo
    • 2.4 多路转接-epoll(重点)
      • epoll系列的接口
      • epoll原理
      • demo
      • epoll工作方式
      • ET和LT对比
      • ET模式和非阻塞文件描述符的关系
      • epoll的使用场景
      • epoll的惊群问题
      • ET模式的demo

1.高级IO模型

非阻塞IO、记录锁、系统V流机制、IO多路转接、readv和writev函数以及存储映射IO(mmap),这些统称为高级IO。

任何IO过程中,都包含两个步骤。第一个是等待,第二个是拷贝。在实际的应用场景中,等待消耗的时间往往都远高于拷贝的时间。为了让IO更高效,最核心的办法就是让等待的时间尽量少。

基本概念

同步通信和异步通信:

  • 同步就是在发出一个调用时,在没有得到结果之前,该调用就不返回。一旦调用返回,就得到返回值了。(由调用者主动等待这个调用的结果)。
  • 异步则相反,调用在发出后,这个调用就直接返回了,所以没有返回结果;(当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或者通过回调函数处理这个调用)。

区分 进程同步与互斥:

  • 进程/线程同步也是进程/线程之间直接的制约关系。
  • 为了完成某种任务而建立的多个线程,需要在某些位置协调他们的工作次序而等待、传递信息所产生的制约关系。

阻塞和非阻塞

  • 关注的是程序在等待调用结果(消息、返回值)时的状态。
  • 阻塞调用是指在调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
  • 非阻塞调用是指在不能立刻得到结果之前,该调用不会阻塞当前线程。

1.1 阻塞IO

在内核将数据准备好之前,系统调用会一直等待。所有套接字,默认都是阻塞方式。
在这里插入图片描述

1.2 非阻塞IO

如果内核没有将数据准备好,系统调用仍然直接返回,并且返回EWOULDBLOCK错误码。
非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符(轮询的方式)。这对CPU浪费较大。

在这里插入图片描述

1.3 信号驱动IO

内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作。
在这里插入图片描述

1.4 IO多路转接

虽热从流程图上看起来和阻塞IO类似。实际上最核心在于多路转接能够同时等待多个IO文件描述符的就绪状态。
在这里插入图片描述

1.5 异步IO

由内核在数据拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据)。
在这里插入图片描述

2. 模型代码实现

2.1 非阻塞IO

一个文件描述符,默认都是阻塞IO(比如说read,accept等,都是一直等的)

# include<unistd.h>
# include<fcntl.h>int fcntl(int fd, int cmd, .../ *arg */);

传入的cmd的值不同,后面追加的参数也不相同。
fcntl函数有5个功能:

  • 复制一个现有的描述符(cmd=F_DUPFD)
  • 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)
  • 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL )
  • 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)
  • 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)

将文件描述符设置为非阻塞状态,需要使用第三个个标记。如下:

#include<iostream>
#include<unistd.h>
#include <fcntl.h>
#include <cstring>
using namespace std;void SetNonBlock(int fd)
{int f1 = fcntl(fd, F_GETFL);  //使用F_GETFL将当前文件描述符的属性提取出来(这是一个位图)if(f1<0){perror("fcntl");return ;}fcntl(fd, F_SETFL, f1 | O_NONBLOCK);    //将该文件状态多设置一个非阻塞,然后设置给fdcout<< " set "<< fd << "nonblock done"<<endl;
}int main()
{char buffer[1024];SetNonBlock(0);while(true){ssize_t n = read(0, buffer, sizeof(buffer)-1);if(n>0){buffer[n-1] = 0;cout<<" echo: "<<buffer<<endl;}else if(n == 0){cout<<"read done!"<<endl;break;}else{// 1.设置成非阻塞之后,如果底层fd数据没有就绪,recv/read/write/send,返回值会以出错的形式返回//2. a 真的出错   b.底层没有就绪// 3.怎么区分程序是真的出错了还是fd没有就绪呢?if(errno==EWOULDBLOCK){cout<<"0 fd data not ready, try again!"<<endl;// do_other_thing();sleep(1);}else{cerr<<" read error, n = "<< n <<"errno code: "<<errno<<", error str"<<strerror(errno)<<endl;}}}return 0;
}

2.2 多路转接-select

select函数介绍

功能:系统调用select函数可以实现多路复用输入/输出模型。

  • select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;
  • 程序会停在select等待,直到被监视的文件描述符有一个或者多个发生了状态改变。
#include<sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds,/fd_set *exceptfds, struct timeval *timeout);

参数解释:

  • 参数nfds是需要监视的最大的文件描述符+1;
  • rdset,wrset,exset分别是要监视的可读、可写、异常的文件描述符的集合;
  • 参数timeout为结构timeval,用来设置select的等待时间

参数timeout解释:

  • NULL:表示select()没有timeout,select会一直被阻塞,直到某个文件描述符发生了事件;
  • 0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的状态。
  • 特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回

关于fd_set位图的操作接口:
在这里插入图片描述
**timeval结构体: **
timeval用于描述一段时间长度,如果在这个时间内,需要监视的文件描述符没有事件发生则函数返回,返回值为0.
在这里插入图片描述
函数返回值:

  • 执行成功则返回文件描述符状态已改变的个数。
  • 如果返回0代表在描述符状态改变前已超过timeout时间,没有返回。
  • 如果有错误发生返回-1,错误原因存在errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
    – 错误值可能是:EBADF文件描述符无效或该文件已关闭。EINTR:此调用被信号所中断。EINVAL:参数n为负值。ENOMEM:核心内存不足

什么才叫就绪呢?

读就绪:

  • socket内核中,接收缓冲区的字节数,大于等于低水位标记SO_RCVLOWAT。此时可以无阻塞的读该文件描述符,并且返回值大于0;
  • socketTCP中,对端关闭连接,此时对socket读,返回0;
  • 监听的socket有新的连接请求
  • socket上有未处理的错误

写就绪:

  • socket内核中,发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小),大于等于低水位标记SO_SNDLOWAT,此时可以无阻塞的写,并且返回值大于0;
  • socket的写操作被关闭(close或者shutdown)。对一个写操作被关闭的socket进行读写,会触发SIGPIPE信号。
  • socket使用非阻塞connect连接成功或者失败之后;
  • socket有未读取的错误;

异常就绪:

  • socket上收到带外数据(和TCP紧急模式相关);
    带外数据解释

demo

连接逻辑:
使用select去等待fd的状态改变,当状态改变时,使用事件派发器去派发任务!

使用telnet命令连接8080号端口,进行发消息
源码地址

select特点

特点:

  • 可监控的文件描述符取决于sizeof(fd_set)的值。
  • 将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集的fd。
    – 一个作用是用于再select返回后,array作为源数据和fd_set进行FD_ISSET判断
    在这里插入图片描述
    –另一个作用是rfds是输入输出型参数,select返回后,会将以前的值清空,因此每次开始时需要重新设置rfds,这就需要用到这个辅助数组。

缺点:

  • 每次调用select,都要手动设置fd集合。麻烦
  • 每次调用select,都需要把fd集合从用户态拷贝到内核态。当fd很多时候,开销大。
  • 每次调用都需要在内核遍历传进来的所有fd。当fd很多时候,开销大。
  • 支持的文件描述符有限。

2.3 多路转接-poll

poll函数介绍

poll函数是select的改进。

#include<poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);

struct pollfd结构体:
在这里插入图片描述
参数说明:

  • fds是一个poll函数监听的结构列表。每一个元素中,包含了三部分内容:文件描述符,监听的事件集合,返回的事件集合。
  • nfds表示fds数组的长度
  • timeout表示poll函数超时时间,单位是毫秒

注意:监听设置在events里面,返回的结果在revents里面查

events和revents的事件值:

事件描述是否可作为输入是否可作为输出
POLLIN数据(包括普通数据和优先数据)可读
POLLRDNORM普通数据可读
POLLRDBAND优先级带数据可读(Linux不支持)
POLLPRI高优先级数据可读,比如TCP带外数据
POLLOUT数据(包括普通数据和优先数据)可写
POLLWRNORM数据可写
POLLWRBAND优先级带数据可读
POLLRDHUPTCP连接被对方关闭,或者对方关闭了写操作,由GNU引入
POLLERR错误
POLLHUP挂起。比如管道的写端被关闭后,读端描述符上将收到POLLHUP事件
POLLNVAL文件描述符没有打开

返回结果:

  • 返回值小于0, 表示出错
  • 返回值等于0,表示poll函数等待超时
  • 返回值大于0, 表示poll由于监听的文件描述符就绪而返回。

poll优缺点

优点:
select需要使用三个指针参数,poll仅仅使用一个就可以了

  • pollfd结构体包含了要监视的event和要发生的event,不再使用值传递的方式。
  • poll没有最大数量的限制

缺点:
poll监听的文件描述符过多时:

  • 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
  • 每次调用pollfd都需要把大量的pollfd结构从用户态拷贝到内核中。
  • 同时连接的大量客户端在同一时刻可能只有很少的处于就绪状态,因此随着监视描述符的增长,其效率会线性下降。

demo

同select一样,只不过修改成了poll逻辑的代码。
源码

2.4 多路转接-epoll(重点)

由poll改进来的,兼顾多路转接的所有优点。

epoll系列的接口

//常见一个epoll的句柄
int epoll_create(int size);

参数说明:

  • size参数可忽略。
  • 使用完后,必须调用close()关闭。
//epoll事件注册函数。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

参数说明:

  • 不同于select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。
  • 第一个参数是epoll的句柄。
  • 第二个参数表示动作,三个宏来表示。
    三个宏:
    EPOLL_CTL_ADD:注册新的fd到epfd中;
    EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
    EPOLL_CTL_DEL:从epfd中删除一个fd;
  • 第三个参数是需要监听的fd。
  • 第四个参数是告诉内核需要监听什么事情

struct epoll_ecent结构体:
在这里插入图片描述events宏:

  • EPOLLIN:表示对应的文件描述符可以读。
  • EPOLLOUT:表示对应的文件描述符可以写。
  • EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外的数据到来)。
  • EPOLLERR:表示对应的文件描述符发生错误;
int epoll_wait(int epfd, struct epoll_event* event, int maxevents, int timeout);

参数解释:

  • 参数events是分配好的epoll_event结构体数组;
  • epoll会把发生的事件赋值到events数组中(event不能为空)。
  • maxevents告知内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size。
  • timeout是超时时间(毫秒),0会立即返回,-1是永久阻塞。
  • 如果调用成功,返回准备好的文件描述符数目,如果是0表示超时。小于0表示函数失败。

epoll原理

在这里插入图片描述

  1. 每一个epoll对象都有一个独立的eventpoll结构体,用于用于存放通过epoll_ctl方法向epoll对象添加进来的事件。
  2. 这些事件会挂载在红黑树中
  3. 所有添加的epoll中的事件都会与设备驱动程序建立回调关系(当事件就绪时,会调用这个回调方法
  4. 这个回调方法会将发生的事件添加到rdlist双链表(就绪列表)中
  5. 在epoll中,对于每一个事件,都会建立一个epitm结构体。
    在这里插入图片描述
  6. 当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。
  7. 如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户。(时间复杂度O(1))。

总结一下:三部曲

  • 调用epoll_create创建一个epoll句柄;
  • 调用epoll_ctl,将要监控的文件描述符进行注册;
  • 调用epoll_wait,等待文件描述符就绪;

demo

epoll源码

epoll工作方式

水平触发(LT)和边缘触发(ET)

LT模式:

  • 当epoll检测到socket上事件就绪的时候,可以不立刻进行处理或者只处理一部分。
  • 如,缓冲区有2k数据,读了1k,缓冲区还剩1k,第二次调用epoll_wait时,epoll_wait仍然会立刻返回并通知socket读事件就绪。
  • 直到缓冲区上所有的数据都被处理完,epoll_wait才不会立刻返回。
  • 支持阻塞读写和非阻塞读写

ET模式:
如果在第一步将socket添加到epoll描述符的时候使用了EPOLLET标志,epoll进入ET工作模式。

  • 当epoll检测到socket上事件就绪时,必须立刻处理。
  • 如,缓冲区有2k数据,读了1k,缓冲区还剩1k的数据,在第二次调用epoll_wait的时候,epoll_wait不会再返回了。
  • 也就是说,ET模式下,文件描述符上的事件就绪后,只有一次处理机会。
  • ET的性能比LT的性能更高(epoll_wait返回的次数少了很多)。Ngnix默认采用ET模式使用epoll。
  • 只支持非阻塞的读写。

注意:select和poll工作在LT模式,epoll二者都支持

ET和LT对比

LT是epoll的默认行为。**使用ET能够减少epoll触发的次数。但是代价就是强迫程序一次响应就绪过程中就把所有的数据都处理完。**相当于一个文件描述符就绪之后,不会反复被提示就绪,看起来比LT更高效一些。但是在LT情况下如果也能做到每次就绪的文件描述符都立刻处理,不让这个就绪被重复提示的话,其实性能也是一样的。
另外ET的代码复杂度高。

ET模式和非阻塞文件描述符的关系

使用ET模式的epoll,需要将文件描述符设置为非阻塞,这个不是接口上的要求,是工程实践的要求。

假设这样的场景:服务器收到2k的请求,会向客户端返回一个应答数据。如果客户端收不到应答,不会发送第二个2k请求。
在这里插入图片描述
如果服务端写的代码是阻塞式的read,并且一次只read 1k的话(read不能保证一次就把所有的数据都读出来,可能被信号打断),剩下的9k的数据就会呆在缓冲区中。
在这里插入图片描述
此时由于epoll是ET模式,并不会认为文件描述符就绪。epoll_wait 就不会再次返回。剩下的9k会一直在缓冲区中。直到下一次客户端再给服务器写数据。epoll_wait才能返回。

问题来了:

  • 服务器只读到1k数据,要10k读完才会给客户端返回响应数据。
  • 客户端要读到服务器的响应,才会发送下一个请求。
  • 客户端发送了下一个请求,epoll_wait 才会返回,才能去读缓冲区中剩余的数据。

所以,为了解决上述问题(阻塞read不一定能一下把完整的请求读完),于是就可以使用非阻塞轮询的方式来读缓冲区,保证一次能把完整的请求都读出来。
而如果是LT没这个问题,因为只要缓冲区中的数据没读完,就能够让epoll_wait返回文件描述符读就绪。

epoll的使用场景

epoll的高性能,是有一定的特定的场景的。如果场景选择的不适宜,epoll的性能可能会适得其反。

  • 对于多链接,且多链接中只用一部分连接比较活跃时,比较适合使用epoll。
    比如:一个需要处理上万个客户端的服务器,各种互联网APP的入口服务器,这样的服务器很适合epoll。但是如果只是系统内部,服务器和服务器间通信,只有少数的几个连接,这种情况下epoll就不合适。

epoll的惊群问题

该篇博客比较详细

ET模式的demo

源码地址

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

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

相关文章

为什么人一旦开窍了就变的特别厉害?

点击上方△腾阳 关注 《让子弹飞》这部电影非常经典&#xff0c;其中一个名场面就是“六子吃粉”。 电影里&#xff0c;胡万对着老六就是一顿狂轰滥炸&#xff1a;“吃了两碗粉&#xff0c;就给一碗的钱&#xff0c;你当咱这是慈善堂呢&#xff1f;” 老六一听&#xff0c;那…

SpringBoot+ELK 收集日志的两种方式

方式一、FileBeatlogstash 7.5.1(docker)ES(docker)springboot 日志文件 应用方式 我们采用ELFK 架构采集日志&#xff0c;直接读取日志生成的文件&#xff0c;不对Springboot的日志任何的修改。也就是FileBeat 通过读取日志文件位置获取日志内容&#xff0c;然后发送至logsta…

移动应用开发课设——原神小助手文档(1)

2023年末&#xff0c;做的移动应用开发课设&#xff0c;分还算高&#xff0c;项目地址&#xff1a;有帮助的话&#xff0c;点个赞和星呗~ GitHub - blhqwjs/-GenShin_imp: 2023年移动应用开发课设 本文按照毕业论文要求来写&#xff0c;希望对大家有所帮助。 xxxx大学课程设计报…

C++--partition库函数

介绍 在C中&#xff0c;partition函数通常是指STL&#xff08;Standard Template Library&#xff09;中的std::partition算法&#xff0c;它用于对一个序列进行分区操作。具体来说&#xff0c;std::partition接受一个范围和一个谓词&#xff08;predicate&#xff09;作为参数…

win10使用小技巧一

1. 查看电脑IP地址 步骤&#xff1a;按WinR打开运行框 → 输入cmd点确定 → 输入ipconfig回车 → 查看IP地址。 2. 解决网页文字不能复制 步骤&#xff1a;按F12 → 调试框里点击设置 → 向下滑找到 禁用 JavaScript → 勾选 → 复制文字。 3. 解决电脑不能上网 方法一&…

im即时通讯哪家好?WorkPlus im即时通讯集成底座为企业保驾护航

在当今数字化时代&#xff0c;即时通讯是企业内部沟通和协作的重要工具&#xff0c;提高工作效率和团队协作效果。在众多IM即时通讯提供商中&#xff0c;WorkPlus作为一家具有独特优势的企业IM即时通讯集成底座&#xff0c;为企业提供了全面的功能和安全保障&#xff0c;为企业…

Linux权限概述

一、权限概述 1.权限的基本概念 2.为什么要设置权限 3.linux用户的身份类别 4.user文件的拥有者 5.group文件所属组内用户 6.other其他用户 7.特殊用户root 二、普通权限管理 1.ls -l查看文件权限 2.文件类型以及权限解析 3.文件或文件夹的权限设置 4.通过数字给文件…

吴恩达深度学习笔记:机器学习策略(2)(ML Strategy (2)) 2.3-2.4

目录 第三门课 结构化机器学习项目&#xff08;Structuring Machine Learning Projects&#xff09;第二周&#xff1a;机器学习策略&#xff08;2&#xff09;(ML Strategy (2))2.3 快速搭建你的第一个系统&#xff0c;并进行迭代&#xff08;Build your first system quickly…

Python 学习中什么是元组,如何使用元组?

什么是元组 元组&#xff08;Tuple&#xff09;是Python内置的一种数据结构&#xff0c;用于存储多个数据项。与列表类似&#xff0c;元组也可以存储不同类型的数据&#xff0c;但它们之间存在一个重要区别&#xff1a;元组是不可变的&#xff0c;也就是说&#xff0c;一旦创建…

智慧校园综合解决方案PPT(41页)

1. 方案背景 智慧校园综合解决方案响应《教育信息化2.0行动计划》等政策&#xff0c;旨在加快智慧校园建设&#xff0c;推动信息化与学习生活的深度融合。目前教育信息化配套设施建设存在“孤岛架构”&#xff0c;学生安全问题频发&#xff0c;技术发展迅速&#xff0c;家长对…

专题三:Spring源码中新建module

前面我们构建好了Spring源码&#xff0c;接下来肯定迫不及待来调试啦&#xff0c;来一起看看大名鼎鼎ApplicationContext 新建模块 1、基础步骤 1.1 自定义模块名称如&#xff1a;spring-self 1.2 选择构建工具因为spring使用的是gradle&#xff0c;所以这边需要我们切换默认…

Android 如何通过代码实时设置EditTextView光标

背景&#xff1a;换肤框架下&#xff0c;QA进行深色浅色切换说输入框光标颜色没有改变&#xff0c;转UI结果UI说需要修改&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 本来有方法可以设置&#xff0c;但是 设置后未生效。重新进入该页面才生效&#xff01;&a…

Android 集成OpenCV

记录自己在学习使用OpenCV的过程 我使用的是4.10.0 版本 Android 集成OpenCV 步骤 下载OpenCV新建工程依赖OpenCV初始化及逻辑处理 1、下载OpenCV 并解压到自己的电脑 官网 地址&#xff1a;https://opencv.org/releases/ 个人地址&#xff1a;https://pan.baidu.com/s/19f…

这款新的 AI 语音助手击败了 OpenAI,成为 ChatGPT 最受期待的功能之一

OpenAI 推迟了 ChatGPT 令人印象深刻的语音模式&#xff0c;这让许多 AI 聊天机器人的粉丝感到不安&#xff0c;但他们现在可能已经被挖走了。法国人工智能开发商 Kyutai 推出了一款名为 Moshi 的实时语音 AI 助手。 Moshi 旨在通过语音&#xff08;如 Alexa 或 Google Assista…

三、数据库系统(考点篇)试题

聚簇索引&#xff0c;也叫簇类索引&#xff0c;原理是对磁盘上实际数据重新组织以按指定的一个或多个列的值排序于聚簇索引的索引页面指针指向数据页面&#xff0c;所以使用聚簇索引查找数据几乎总是比使用非聚簇索引快。每张表只能建一个聚簇索引&#xff0c;并且建聚簇索引需…

在VMware中安装Linux RHEL8操作系统

Linux操作系统安装 任务目标 了解虚拟机平台VMWARE的安装步骤。 了解RHEL8的安装步骤。 熟悉安装所必须的硬件环境。 任务要求 在VMWARE虚拟机平台上安装RHEL8&#xff0c;要求使用root用户成功登录&#xff0c;关闭虚拟机做好快照。将安装步骤记录在下方“操作步骤”&am…

51单片机嵌入式开发:3、STC89C52操作8八段式数码管原理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 STC89C52操作8八段式数码管原理 1 8位数码管介绍1.1 8位数码管概述1.2 8位数码管原理1.3 应用场景 2 原理图图解2.1 74HC573原理2.2 74HC138原理2.3 数码管原理 3 数码管程序…

跟《经济学人》学英文:2024年07月06日这期:Finishing schools for the age of TikTok

Finishing schools for the age of TikTok Unsure how to be polite at work? Ask a digital etiquette guru 不确定如何在工作中保持礼貌&#xff1f;请教一位数字礼仪大师 “Finishing schools” 是指专门为年轻女性提供礼仪、社交技巧、文化修养等教育的学校&#xff0c;…

【Kafka】记录一次Kafka消费者重复消费问题

文章目录 现象业务背景排查过程Push与Pull 现象 用户反馈消费者出现消息积压&#xff0c;并且通过日志看&#xff0c;一直重复消费&#xff0c;且没有报错日志。 业务背景 用户的消费者是一个将文件做Embedding的任务&#xff0c;&#xff08;由于AI技术的兴起&#xff0c;大…

关注推送---Feed流,推模式实现的个人分析及其思考。

本篇文章记录我们实际开发过程中&#xff0c;关注推送场景的个人思考&#xff0c;以及解析。 文章目录 前言一、关注推送是什么&#xff1f;是什么是Feed流&#xff1f;二、解决关注推送问题的技术方案1.理论模型的选取2.数据类型的选取 三、理论模型的选取三、数据类型的选取总…