首页 文章 精选 留言 我的

精选列表

搜索[实时etl],共10000篇文章
优秀的个人博客,低调大师

RT-DETR:可以满足实时性要求的DETR模型

本文分享自华为云社区《高性能网络设计秘笈:深入剖析Linux网络IO与epoll》,作者: Lion Long 。 一、epoll简介 epoll是Linux内核中一种可扩展的IO事件处理机制,可替代select和poll的系统调用。处理百万级并发访问性能更佳。 二、select的局限性 (1)文件描述符越多,性能越差。单个进程中能够监视的文件描述符存在最大的数量,默认是1024(在linux内核头文件中定义有 #define _FD_SETSIZE 1024),当然也可以修改,但是文件描述符数量越多,性能越差。 (2)开销巨大,select需要复制大量的句柄数据结构,产生了巨大的开销(内核/用户空间内存拷贝问题)。 (3)select需要遍历整个句柄数组才能知道哪些句柄有事件。 (4)如果没有完成对一个已经就绪的文件描述符的IO操作,那么每次调用select还是会将这些文件描述符通知进程,即水平触发。 (5)poll使用链表保存监视的文件描述符,虽然没有了监视文件数量的限制,但是其他缺点依旧存在。 由于以上缺点,基于select模型的服务器程序,要达到十万以上的并发访问,是很难完成的。因此,epoll出场了。 三、epoll的优点 (1)不需要轮询所有的文件描述符 (2)每次取就绪集合,都在固定位置 (3)事件的就绪和IO触发可以异步解耦 四、epoll函数原型 4.1、epoll_create(int size) #include <sys/epoll.h> int epoll_create(int size); 功能:创建epoll的文件描述符。 参数说明:size表示内核需要监控的最大数量,但是这个参数内核已经不会用到,只要传入一个大于0的值即可。当size<=0时,会直接返回不可用,这是历史原因保留下来的,最早的epoll_create是需要定义一次性就绪的最大数量;后来使用了链表以便便维护和扩展,就不再需要使用传入的参数。 返回:返回该对象的描述符,注意要使用 close 关闭该描述符。 4.2、epoll_ctl #include <sys/epoll.h> int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); // epoll_ctl对应系统调用sys_epoll_ctl 功能:操作epoll的文件描述符,主要是对epoll的红黑树节点进行操作,比如节点的增删改查。 参数说明: 4.2.1、event参数说明 struct epoll_event结构体原型 typedef union epoll_data{ void* ptr; int fd; uint32_t u32; uint64_t u64 }; struct epoll_event{ uint32_t events; epoll_data_t data; } events成员代表要监听的epoll事件类型 events成员: data成员: data 成员时一个联合体类型,可以在调用 epoll_ctl 给 fd 添加/修改描述符监听的事件时携带一些数据,方便后面的epoll_wait可以取出信息使用。 4.2.2、扩展说明:SYSCALL_DEFINE数字 的宏定义 跟着的数字代表函数需要的参数数量,比如SYSCALL_DEFINE1代表函数需要一个参数、SYSCALL_DEFINE4代表函数需要4个参数。 4.2.3、注意 epoll_ctl是非阻塞的,不会被挂起。 4.3、epoll_wait 函数原型 #include <sys/epoll.h> int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); 功能:阻塞一段时间,等待事件发生 返回:返回事件数量,事件集添加到events数组中。也就是遍历红黑树中的双向链表,把双向链表中的节点数据拷贝出来,拷贝完毕后把节点从双向链表中移除。 五、epoll使用步骤 step 1:创建epoll文件描述符 int epfd = epoll_create(1); step 2:创建struct epoll_event结构体 struct epoll_event ev; ev.data.fd=listenfd;//保存监听的fd,以便epoll_wait的后续操作 ev.events=EPOLLIN;//设置监听fd的可读事件 step 3:添加事件监听 epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev); step 4:等待事件 struct epoll_event events[EVENTS_LENGTH]; char rbuffer[MAX_BUFF]={ 0 }; char wbuffer[MAX_BUFF]={ 0 }; while(1) { int nready = epoll_wait(epfd,events,EVENTS_LENGTH,-1);//-1表示阻塞等待 int i=0; for(i=0;i<nready;i++) { int clientfd=events[i].data.fd; if(clientfd==listenfd) { struct sockaddr_in client; int len=sizeof(client); int confd=accept(listenfd,(struct sockaddr*)&client,&len); //step 2:创建struct epoll_event结构体 struct epoll_event evt; evt.data.fd=confd;//保存监听的fd,以便epoll_wait的后续操作 evt.events=EPOLLIN;//设置监听fd的可读事件 // step 3:添加事件监听 epoll_ctl(epfd,EPOLL_CTL_ADD,confd,&evt); } else if(events[i].events &EPOLLIN) { int ret = recv(clientfd,rbuffer,MAX_BUFF,0); if(ret>0) { rbuffer[ret]='\0';//剔除干扰数据 printf("recv: %s\n",rbuffer); memcpy(wbuffer,rbuffer,MAX_BUFF);//拷贝数据,做回传示例 //step 2:创建struct epoll_event结构体 struct epoll_event evt; evt.data.fd=clientfd;//保存监听的fd,以便epoll_wait的后续操作 evt.events=EPOLLOUT;//设置监听fd的可写事件 // step 3:修改事件监听 epoll_ctl(epfd,EPOLL_CTL_MOD,clientfd,&evt); } } else if(events[i].events &EPOLLOUT) { int ret = send(clientfd,wbuffer,MAX_BUFF,0); printf("send: %s\n",wbuffer); //step 2:创建struct epoll_event结构体 struct epoll_event evt; evt.data.fd=clientfd;//保存监听的fd,以便epoll_wait的后续操作 evt.events=EPOLLIN;//设置监听fd的可读事件 // step 3:修改事件监听 epoll_ctl(epfd,EPOLL_CTL_MOD,clientfd,&evt); } } } 六、完整示例代码 #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <fcntl.h> #include <unistd.h> #include <pthread.h> #include <sys/epoll.h> #include <string.h> #define BUFFER_LENGTH 128 #define EVENTS_LENGTH 128 char rbuff[BUFFER_LENGTH] = { 0 }; char wbuff[BUFFER_LENGTH] = { 0 }; int main() { // block int listenfd = socket(AF_INET, SOCK_STREAM, 0); // if (listenfd == -1) return -1; // listenfd struct sockaddr_in servaddr; servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(9999); if (-1 == bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) { return -2; } #if 0 // nonblock int flag = fcntl(listenfd, F_GETFL, 0); flag |= O_NONBLOCK; fcntl(listenfd, F_SETFL, flag); #endif listen(listenfd, 10); int epfd = epoll_create(1); struct epoll_event ev, events[EVENTS_LENGTH]; ev.events = EPOLLIN; ev.data.fd = listenfd; epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); printf("epfd : %d\n", epfd); while (1) { int nready = epoll_wait(epfd, events, EVENTS_LENGTH, -1); printf("nready --> %d\n",nready); int i; for (i = 0; i < nready;i++) { int clientfd = events[i].data.fd; if (listenfd == clientfd) { // accept struct sockaddr_in client; int len = sizeof(client); int conffd = accept(clientfd, (struct sockaddr*)&client,&len); printf("conffd --> %d\n",conffd); ev.events = EPOLLIN; ev.data.fd = conffd; epoll_ctl(epfd, EPOLL_CTL_ADD, conffd, &ev); } else if(events[i].events & EPOLLIN)//client { int ret=recv(clientfd, rbuff, BUFFER_LENGTH, 0); if (ret > 0) { rbuff[ret] = '\0'; printf("recv buffer: %s\n", rbuff); /* int j; for (j = 0; j < BUFFER_LENGTH;j++) { buff[j] = 'a' + (j % 26); } send(clientfd, buff, BUFFER_LENGTH, 0); */ memcpy(wbuff, rbuff, BUFFER_LENGTH); ev.events = EPOLLOUT; ev.data.fd = clientfd; epoll_ctl(epfd, EPOLL_CTL_MOD, clientfd, &ev); } } else if (events[i].events & EPOLLOUT) { send(clientfd, wbuff, BUFFER_LENGTH, 0); printf("send --> %s\n",wbuff); ev.events = EPOLLIN; ev.data.fd = clientfd; epoll_ctl(epfd, EPOLL_CTL_MOD, clientfd, &ev); } } } return 0; } 七、epoll的缺点 读写使用相同的缓冲区。比如上述的示例中,wbuffer和rbuffer是使用同一个缓冲区的,所以需要rbuff[ret] = ‘\0’;去除杂数据。 八、水平触发(LT)与边沿触发(ET) 8.1、两者差异 1、水平触发可以一次recv,边沿触发需要用循环来recv; 2、水平触发可以使用阻塞模式,边沿模式不能 3、两者性能差异非常小,一般小数据使用水平触发LT,大数据使用边沿触发ET 4、listen fd最好使用水平触发,尽量不要边沿触发 5、当当recv的buffer小于接受的数据时: (1)水平触发是只要有数据就一直触发,直到数据读完; (2)边沿触发是来一次连接触发一次,如果接受数据的buffer不够大,则数据会保留在缓冲区,下次触发继续从缓冲区读出来; 6、一般,水平触发只需要一个recv,边沿触发需要搭配while从缓冲区读完数据 8.2、设置触发模式 默认是水平触发模式,在事件中设置中 | EPOLLET 就可以设置边沿触发,不设置则默认是水平触发。 例如: ev.events=EPOLL_IN | EPOLLET 九、常见疑惑问题 9.1、为什么提前先定义一个事件? 我们需要注册,内核才会有事件来的时候通知进程。比如生活中要退一个快递,那么我们需要注册一个快递公司的账户,然后发送一个退快递请求时快递公司才能找到你并取快递。 9.2、epoll events超出EVENTS_LENGTH? epoll会循环拷贝红黑树结构体中的双向链表节点,读取节点数据,直到没有事件。 9.3、缓冲区有多大空间时才返回可读/可写? 只要缓冲区有空间就返回可读、可写,不管空间多少。比如缓冲区是1024,但是有1023有数据了,这种极端条件也会返回可读、可写。 9.4、recv和send放在一起时,有什么问题? 发送给客户端数据很大的时候(大于内核缓冲区),就可能出现send不全,客户端recv不全,最好用EPOLLOUT单独处理发送数据事件。 总结 本文介绍了网络IO模型,引入了epoll作为Linux系统中高性能网络编程的核心工具。通过分析epoll的特点与优势,并给出使用epoll的注意事项和实践技巧,该文章为读者提供了宝贵的指导。通过掌握这些知识,读者能够构建高效、可扩展和稳定的网络应用,提供出色的用户体验。 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

开源实时监控系统 HertzBeat 赫兹跳动 v1.2.1 发布

官网:hertzbeat.com|tancloud.cn 大家早上好,监控告警系统 HertzBeat v1.2.0 发布啦!新增IoTDB作为时序数据存储,更多测试用例和bug修复提升整体稳定性等。欢迎了解使用。 只需要一条 docker 命令即可安装体验 heartbeat : docker run -d -p 1157:1157 --name hertzbeat tancloud/hertzbeat 花一分钟快来试试吧。 感谢 hertzbeat 贡献者们的贡献!👍👍 我们急需对测试用例,新增应用监控,文档等各方面的贡献者,非常欢迎您的加入。快来吧,HertzBeat 上手非常简单! 特性: [workflow] 在translate-action里支持机器人自动翻译修改issue标题 #336@hertzbeat [web-app] 应用默认语言设置的英文#337 [alerter] 代码注射翻译整理#346@TJxiaobao [manger] 新增mockito单元测试用例(#363) #368@gcdd1993 支持iotdb作为时序数据库存储 #372@星辰 新增单元测试用例 #370@TJxiaobao [webapp,warehouse] 历史图表支持最大值最小值平均值统计展示#373 [manager] I18nControllerTest and MonitorControllerTest 单元测试用例实现 #376@TJxiaobao MonitorsControllerTest 单元测试用例实现#378@TJxiaobao 支持配置iotdb数据存储时间 #379@星辰 NoticeConfigController Test class writing completed #380@TJxiaobao [warehouse] 启动时对iotdb链接可用性检测#384 [web-app] notice monitors.detail.time-series.unavailable #390 [home] 新增iotdb数据库安装初始化配置文档#392 Feature/app service test #393@TJxiaobao [docs] 更新hertzbeat架构图#394 [docs] 新增hertzbeat路线图#397 BUG 修复. [collector] fix doubleAndUnit 空指针异常,更新 cpu_load_average 计算表达式 #332@星辰 fix(sec): 升级 org.postgresql:postgresql to 42.4.1 #340@zhoumengyks fix(sec): 升级 org.yaml:snakeyaml to 1.32 #342@hdfjfg [collector] 修复redis监控采集failed to create a child event loop 问题 #344 fix(sec): 升级 mysql:mysql-connector-java to 8.0.28 #343@bitmasks [web-app] 修复历史图表tooltip多点只展示一个实例的问题 #365 [workflow] 升级 issues-translator version 2.7 #367 [manager] 升级 sureness v1.0.8 to 修复权限绕过安全问题 #382issue by @2xiaodi [collector] 修改snmp协议监控造成大量无用线程假死问题 #383issue by @fiendhous bugfix: Fixed expression:(A | B), A and B are null, print the error log #387@星辰 [home] 注释 jvm code_cache 只支持 jdk8#391 Typo repair #398@TJxiaobao [warehouse] 修复 400: statement is a query statement 异常 #401 [home] 更新告警 webhook 接口文档 #402 更新 constants.js 的 sa-token#396@孔明 更新 constants.js 的 jpom#388@不忘初心 更新 constants.js 的 northstar #395@Huangwl 在线环境 https://console.tancloud.cn. 升级请注意⚠️ 需要变更配置文件application.yml,将原来的 sureness: auths: - digest - basic - jwt 修改为. sureness: auths: - digest - basic - jwt jwt: secret: 'CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R LnfKefTjsIfJLBa2YkhEqEGtcHDTNe4CU6+9 8tVt4bisXQ13rbN0oxhUZR73M6EByXIO+SV5 dKhaX0csgOCTlCxq20yhmUea6H6JIpSE2Rwp' Have Fun! HertzBeat 赫兹跳动 是由Dromara孵化,TanCloud开源的一个支持网站,API,PING,端口,数据库,操作系统等监控类型,拥有易用友好的可视化操作界面的开源监控告警项目。 我们也提供了对应的SAAS 版本监控云,中小团队和个人无需再为了监控自己的网站资源,而去部署一套繁琐的监控系统,登录即可免费开始。 HertzBeat 支持自定义监控, 只用通过配置 YML 文件我们就可以自定义需要的监控类型和指标,来满足常见的个性化需求。 HertzBeat 模块化,manager, collector, warehouse, alerter各个模块解耦合,方便理解与定制开发。 HertzBeat 支持更自由化的告警配置 (计算表达式),支持告警通知,告警模版,邮件钉钉微信飞书等及时通知送达 欢迎登录 HertzBeat 的云环境 TanCloud试用发现更多。 我们正在快速迭代中,欢迎参与加入一起共建项目开源生态。 HertzBeat的多类型支持,易扩展,低耦合,希望能帮助开发者和中小团队快速搭建自有监控系统。 我们急需对测试用例,新增应用监控,文档等各方面的贡献者,非常欢迎您的加入。快来吧,HertzBeat 上手非常简单! 仓库地址 Gitee https://gitee.com/dromara/hertzbea Github https://github.com/dromara/hertzbeat 看到这里不妨 Star 支持下哦,灰常感谢! 一条命令即可开启监控之旅: docker run -d -p 1157:1157 --name hertzbeat tancloud/hertzbeat

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册