从零构建通讯器--7.4 服务器惊群、性能优化大局观

2024-02-11 10:40

本文主要是介绍从零构建通讯器--7.4 服务器惊群、性能优化大局观,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • (1)CPU占比与惊群
      • 1)看程序运行占用CPU百分比
      • 2)惊群:
    • (2)性能优化大局观
      • 1)概述
      • 2)两个层面看性能优化问题:
    • (3)性能优化的实施
      • (3.1)绑定CPU、提升优进程先级
      • (3.2)TCP/IP协议的配置选项
      • (3.3)TCP/IP协议额外注意的一些算法、概念等
    • (4)配置最大允许打开的文件句柄数
    • (5)内存池补充说明

(1)CPU占比与惊群

1)看程序运行占用CPU百分比

ps -elf看所有进程,找到相关进程号
用top -p 进程号 看程序占CPU的百分比

2)惊群:

(1)背景:1个master进程 4个worker进程
(2)介绍:一个连接进入,惊动了4个worker进程,但是只有一个worker进程accept();其他三个worker进程被惊动,这就叫惊群;但是,这三个被惊动的worker进程都做了无用功【操作系统本身的缺陷】,产生了很多无用的消耗;
(3)解决方法:官方nginx解决惊群的办法:锁,进程之间的锁;谁获得这个锁,谁就往监听端口增加EPOLLIN标记,有了这个标记,客户端连入就能够被服务器感知到;
资料:https://zhuanlan.zhihu.com/p/51251700
知乎介绍nginx互斥锁解决惊群

法一:使用一个worker进程进行分配给其他worker进程请求
法二:使用worker进程之间的各自线程通信,协商分配解决惊群

(4)3.9以上内核版本的linux,在内核中解决了惊群问题;而且性能比官方nginx解决办法效率高很多;
uname -r看内核版本
(5)注意:
a)很多 套接字配置项可以通过setsockopt()等等函数来配置;
b)还有一些tcp/ip协议的一些配置项我们可以通过修改配置文件来生效;
(6)课后作业:

(1)在worker进程中实现ngx_open_listening_sockets()函数;
(2)观察,是否能解决惊群问题;
(3)如果在master进程中调用ngx_open_listening_sockets()函数,那么建议master进程中把监听socket关闭;
(7)惊群处理方法
a)lighttpd的解决思路:无视惊群。采用Watcher/Workers模式,具体措施有优化fork()与epoll_create()的位置(让每个子进程自己去epoll_create()和epoll_wait()),捕获accept()抛出来的错误并忽视等。这样子一来,当有新accept时仍将有多个lighttpd子进程被唤醒。
b)nginx的解决思路:避免惊群。具体措施有使用全局互斥锁,每个子进程在epoll_wait()之前先去申请锁,申请到则继续处理,获取不到则等待,并设置了一个负载均衡的算法(当某一个子进程的任务量达到总设置量的7/8时,则不会再尝试去申请锁)来均衡各个进程的任务量。
c)一款国内的优秀商业MTA服务器程序(不便透露名称):采用Leader/Followers线程模式,各个线程地位平等,轮流做Leader来响应请求。
d)坊间也流传Linux 2.6.x之后的内核,就已经解决了accept的惊群问题,但其实不然,这篇论文里提到的改进并未能彻底解决实际生产环境中的惊群问题,因为大多数多进程服务器程序都是在fork()之后,再对epoll_wait(listen_fd,…)的事件,这样子当listen_fd有新的accept请求时,进程们还是会被唤醒。论文的改进主要是在内核级别让accept()成为原子操作,避免被多个进程都调用了
(8)采用方案
多方考量,最后选择参考lighttpd的Watcher/Workers模型,实现了我需要的那款多进程epoll程序,核心流程如下:
a)主进程先监听端口, listen_fd = socket(…); ,setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,…),setnonblocking(listen_fd),listen(listen_fd,…)。
b)开始fork(),到达子进程数上限(建议根据服务器实际的CPU核数来配置)后,主进程变成一个Watcher,只做子进程维护和信号处理等全局性工作。
c)每一个子进程(Worker)中,都创建属于自己的epoll,epoll_fd = epoll_create(…);,接着将listen_fd加入epoll_fd中,然后进入大循环,epoll_wait()等待并处理事件。千万注意,epoll_create()这一步一定要在fork()之后。epoll解决的是epoll_create 在 fork 之前创建,那样导致所有进程共享一个 epoll 红黑数,但epoll 并不是只处理 accept 事件,accept 后续的读写事件都需要处理,还有定时或者信号事件。
d)大胆设想(未实现):每个Worker进程采用多线程方式来提高大循环的socket fd处理速度,必要时考虑加入互斥锁来做同步,但也担心这样子得不偿失(进程+线程频繁切换带来的额外操作系统开销),这一步尚未实现和测试,但看到nginx源码中貌似有此逻辑

(2)性能优化大局观

1)概述

a)性能优化无止境无极限
b)没有一个放之四海皆准的优化方法,只能够一句具体情况而定
c)这里也不可能把性能优化方方面面都谈到,很多方面,大家都需要不断的探索和尝试;

2)两个层面看性能优化问题:

1.软件层面
a)充分利用cpu,比如刚才惊群问题;
b)深入了解tcp/ip协议,通过一些协议参数配置来进一步改善性能;
c)处理业务逻辑方面,算法方面有些内容,可以提前做好;
2.硬件层面
a)高速网卡,增加网络带宽;
b)专业服务器;数十个核心,马力极其强;
c)内存:容量大,访问速度快;
d)主板啊,总线不断升级的;

(3)性能优化的实施

(3.1)绑定CPU、提升优进程先级

1)一个worker进程运行在一个核上;为什么能够提高性能呢?

(1)cpu:内部有缓存;cpu缓存命中率问题;把进程固定到cpu核上,可以大大增加cpu缓存命中率,从而提高程序运行效率;
(2)worker_cpu_affinity【cpu亲和性】,就是为了把worker进程固定的绑到某个cpu核上;
(3)相关Nginx源码:ngx_set_cpu_affinity,ngx_setaffinity;

2)提升进程优先级,这样这个进程就有机会被分配到更多的cpu时间(时间片【上下文切换】),得到执行的机会就会增多;

(1)setpriority();设置进程优先级
(2)干活时进程 chuyuR状态,没有连接连入时,进程处于S
(3)pidstat - w - p 3660 1 看某个进程的上下文切换次数[切换频率越低越好]
cswch/s:主动切换/秒:你还有运行时间,但是因为你等东西,你把自己挂起来了,让出了自己时间片。
nvcswch/s:被动切换/秒:时间片耗尽了,你必须要切出去;

3)一个服务器程序,一般只放在一个计算机上跑,专用机;

(3.2)TCP/IP协议的配置选项

1)这些配置选项都有缺省值,通过修改,在某些场合下,对性能可能会有所提升;
2)若要修改这些配置项,要求做到以下几点:

a)对这个配置项有明确的理解;
b)对相关的配置项,记录他的缺省值,做出修改;
c)要反复不断的亲自测试,亲自验证;是否提升性能,是否有副作用;

3)细节:

a) TCP_DEFER_ACCEPT参数
用法范例:
setsockopt( listen_fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(int) )
作用:一般三路握手后我们就可以用accept()函数把这个连接从 已完成连接 队列 中就拿出来了,用了这个选项之后,只有客户端往这个连接上发送数据了,accept()才会返回【而不再是三次握手就返回】,那是否有可能有用户连着你不发数据【恶意攻击】,那我这个时候我用这个选项不会触发accept()返回,因为唤醒accept()肯定会有一些系统上下文切换的,这也是代价;若有客户端恶意攻击,只发请求不接受就爆炸了

b)tcp参数

在/etc/sysctl.conf文件中有一些配置项,可能有的影响客户端,有的影响服务器端;
1)net.ipv4.tcp_syn_retries【客户端】:主动建立连接时,发送syn的重试次数;

2)net.ipv4.ip_local_port_range【客户端】:主动建立时,本地端口范围,大家都知道,客户端端口一般系统分配;

3)net.ipv4.tcp_max_syn_backlog【服务器】:处于SYN_RCVD状态,未获得对方确认的连接请求数;就是那个未完成连接队列的大小。第五章第四节有讲过listen队列;,有人攻击就可以减小点

4)net.core.somaxconn【服务器】:已完成连接队列【需要用 accept()取走】的大小受到该值的限制,此值是系统级别的最大的队列长度限制值;

5)net.ipv4.tcp_synack_retries【服务器】:回应 SYN 包时会尝试多少次重新发送初始 SYN,ACK 封包后才决定放弃,服务器给客户端发信息,没收到确认,超过多少次就认为断开了
6)net.core.netdev_max_backlog:在网卡接收数据包的速率比内核处理这些包的速率快时,允许送到待处理报文队列的数据包的最大数目。缺省值1000,应对拼命发包攻击时可能有效;
net.ipv4.tcp_abort_on_overflow:超出处理能力时,对新来的syn连接请求直接回rst包;缺省是关闭的;

7)net.ipv4.tcp_syncookies:这个项也是防止一些syn攻击 用的,syn队列满的时候,新的syn将不再进入未完成连接队列,而是用一种syncookie技术进行三路握手,也就是说服务会计算出cookie然后把这个cookie通过syn/ack标记的包返回给客户端,客户端发送数据时,服务根据数据包中带的cookie信息来 恢复连接。这个选项可能有些副作用,因为syn/ack包会返回一个序列号信息,现在返回的信息变成了cookie,可能会使一些tcp协议的功能失效,大家用的时候要完全研究清楚这种参数;而且程序代码上是不是要做一些调整和配合都要搞清楚;因为老师没详细研究过这个参数,感觉这种方式似乎不需要accept()就能把 用户接入进来,所以感觉代码上有可能要调整

8)net.ipv4.tcp_fastopen【客户端/服务器】:用于优化三次握手,默认不启用;
通过前面的学习,大家都知道了TCP的三次握手,其中的第三次握手是个ack包,大家抓一下包就会发现,这个包里一般是不携带额外数据的,但是这个包里是可以携带额外的数据的,怎么能携带上额外数据,提供一篇参照文章,“TCP连接建立的三次握手过程可以携带数据吗?”,因为这个涉及到tcp协议内的细节内容,:参考:http://0xffffff.org/2015/04/15/36-The-TCP-three-way-handshake-with-data/
三次握手大家都熟悉,syn,syn/ack,ack,下次重新连接还要进行三次握手,这很耗费性能,那如果syn/ack的时候给客户端回一个cookie,那么下次客户端重新连接到服务器的时候不用进行三次握手,而是 可以直接发送syn包,里边夹带cookie并夹带要发送的数据即可,那这样是不是省了好几步数据传输;不过要求c/s都要支持这种特性才能做到,因为客户端要发送一个带fast open cookie request请求的包给服务器的,而且你这种fastopen特性如果开启的话,可能还涉及到fastopen队列,这个队列的最大长度你可以也要考虑设置一下,这种探索或者说是代码怎么书写,
9)net.ipv4.tcp_rmem:收数据缓存的最小值,默认值,最大值(单位:字节)
10)net.ipv4.tcp_wmem:发数据缓存的最小值,默认值,最大值(单位:字节)
11)tcp_adv_win_scale:这东西会把上边这个缓存拿出来一部分作为额外开销,这个数字用于确定拿出来多少作为额外开销;

(3.3)TCP/IP协议额外注意的一些算法、概念等

a)滑动窗口的概念:
tcp协议引入滑动窗口主要是为了解决高速传输和流量控制问题【限速问题】;这个概念和实现一般都会在操作系统内核里边干,

b)Nagle算法的概念:
这个算法是避免发送很小的报文,大家都知道,报文再小他也要有包头,那么我们把几个小报文组合成一个大一点的报文再发送,那至少我们能够少发好几个包头,节省了流量和网络带宽;

c)Cork算法:
比Nagle更硬气,完全禁止发送小报文,除非累积到一定数量的数据或者是超过某一个时间才 会发送这种报文;

d) Keep-Alive机制:
用于关闭已经断开的tcp连接,这个咱们以往也提及过,那作为TCP/IP协议中的一个概念,这里也再次把他提及一下;
net.ipv4.tcp_keepalive_time:探测包发送周期单位是秒,默认是7200秒(2小时):如果2小时内没有任何报文在这个连接上发送,那么开始启动keep-alive机制,发送keepalive包。
net.ipv4.tcp_keepalive_intvl:缺省值75(单位秒)如果发送keepalive包没应答,则过75秒再次发送keepalive包;
net.ipv4.tcp_keepalive_probes:缺省值9,如果发送keepalive包对方一直不应答,发送9次后,如果仍然没有回应,则这个连接就被关闭掉;

e) SO_LINGER选项:
延迟关闭选项, 一般调用setsockopt(SO_LINGER),这个选项设置 在连接关闭的时候,是否进行正常的四次挥手有关;因为缺省的tcp/ip协议可能会导致某一通讯方给对方发送rst包以结束连接从而导致对方收到rst包而丢弃收到的数据,那么这个延迟选项可以避免给对方发送rst包导致对方丢弃收到的数据
说的再白一点:这个选项用来设置延迟关闭的时间,等待套接字发送缓冲区中的数据发送完成;延迟关闭并不是一个好事,所以大家要研究明白才能决定是否用它,咱们这个项目中,感觉没必要用;

(4)配置最大允许打开的文件句柄数

1)cat /proc/sys/fs/file-max :查看操作系统可以使用的最大句柄数
2)cat /proc/sys/fs/file-nr :查看当前已经分配的,分配了没使用的,文件句柄最大数目
在这里插入图片描述
3)限制用户使用的最大句柄数
修改/etc/security/limit.conf文件才能永久有效
root soft nofile 60000 :setrlimit(RLIMIT_NOFILE) //软限制,在程序中可修改
root hard nofile 60000 //硬限制改不了
4)暂时有效
ulimit -n :查看系统允许的当前用户进程打开的文件数限制
ulimit -HSn 5000 :临时设置,只对当前session(当前窗口)有效;
H表示硬限制
n:表示我们设置的是文件描述符
推荐文章:https://blog.csdn.net/xyang81/article/details/52779229

(5)内存池补充说明

1)为什么没有用内存池技术:感觉必要性不大,咱们分配和回收都比较快,不适合使用
2)内存池:分配小块内存节省内存,一般考虑动ngx_c_memory.cxx文件
3)TCMalloc,取代malloc(); //谷歌发明的第三方库,多线程分配内存,更快
效率提升:库地址:https://github.com/gperftools/gperftools


这篇关于从零构建通讯器--7.4 服务器惊群、性能优化大局观的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/699579

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

黑神话,XSKY 星飞全闪单卷性能突破310万

当下,云计算仍然是企业主要的基础架构,随着关键业务的逐步虚拟化和云化,对于块存储的性能要求也日益提高。企业对于低延迟、高稳定性的存储解决方案的需求日益迫切。为了满足这些日益增长的 IO 密集型应用场景,众多云服务提供商正在不断推陈出新,推出具有更低时延和更高 IOPS 性能的云硬盘产品。 8 月 22 日 2024 DTCC 大会上(第十五届中国数据库技术大会),XSKY星辰天合正式公布了基于星