Nginx性能优化

简介

nginx作为常用的web代理服务器,某些场景下对于性能要求还是蛮高的,所以本片文章会基于操作系统调度以及网络通信两个角度来讨论一下Nginx性能的优化思路。

基于操作系统调度进行Nginx优化

CPU工作方式

对于用户进程,CPU会按照下面的规则完成工作调度:

  1. 每个用户进程被加载到内存中,就会采用CFS调度算法,即对于vruntime少的优先运行,得到CPU的运行时间片就会运行,时间一到就会被挂起。
  2. 进程优先级越高得到时间片的时间就越长。
  3. 进程实际运行时间不一定和时间片相等,当进程遇到IO阻塞时也会被挂起。

如下图,我们的用户进程nginx就会被放到csf_rq中,操作系统会等deadline进程(dl_rq中的进程)和实时进程(rt_rq中的进程)拿到时间片运行完之后,从cfs_rq中取出最左节点运行。

优化的整体方向

基于CPU工作原理的优化,我们一般都从以下两个角度考虑:

  1. 尽可能让操作系统历用尽可能多的CPU资源
  2. 尽可能占用更多的CPU时间片、减少进程间切换。
策略1(提升CPU利用率)

在多核CPU的情况下,我们可以设置多个nginx进程使其尽可能利用CPU资源。

首先我们可以使用vmstat ,查看CPU整体资源使用情况。

# 查看系统资源使用情况,2秒输出一次,输出3次vmstat 2 3

如下所示,可以发现用户进程+系统进程所占用的时间比小于80%,系统资源充裕。


procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st1  0 265472 177356      0 317180   10   49   778    55   78   67  1  1 98  0  00  0 265472 177356      0 317180    0    0     0     0   81  115  0  0 100  0  00  0 265472 177356      0 317180    0    0     0     0   72  114  0  0 100  0  0

所以们可以使用top命令并键入1查看操作系统的CPU核心数。

top

如下所示,笔者的机器有6个CPU核心,所以我们可以设置6个nginx进程,使每个worker进程与CPU核心一一对应。

top - 14:20:33 up 18 min,  2 users,  load average: 0.20, 0.13, 0.23
Tasks: 255 total,   1 running, 254 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.3 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.3 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu4  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu5  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

查看我们的worker进程:

 ps -ef |grep nginx |grep -v  grep

此时我们的Linux中的nginx实际接收用户请求的worker进程数为1,很明显未能很好的利用CPU资源,所以我们需要调整一下

 

root       2891      1  0 14:06 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      2892   2891  0 14:06 ?        00:00:00 nginx: worker process
nginx      2893   2891  0 14:06 ?        00:00:00 nginx: cache manager process

打开nginx.conf,将worker_processes 设置为auto,这样

worker_processes  auto;

 完成后重新加载一下配置。

/usr/local/nginx/sbin/nginx -s reload

可以看到worker进程和CPU核心数一样,这样一来nginx就能更好的利用CPU资源了。


root       2891      1  0 14:06 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      3179   2891  0 14:29 ?        00:00:00 nginx: worker process
nginx      3180   2891  0 14:29 ?        00:00:00 nginx: worker process
nginx      3181   2891  0 14:29 ?        00:00:00 nginx: worker process
nginx      3182   2891  0 14:29 ?        00:00:00 nginx: worker process
nginx      3183   2891  0 14:29 ?        00:00:00 nginx: worker process
nginx      3184   2891  0 14:29 ?        00:00:00 nginx: worker process
nginx      3185   2891  0 14:29 ?        00:00:00 nginx: cache manager process
策略2(避免Nginx进程切换)

即使创建与CPU核心数一样,nginx也不一定能够按序分别到每一个CPU上。所以我们希望能够将worker进程与CPU进行一一绑定,尽可能的避免nginx进程在CPU之间切换导致的伪共享带来的性能问题。

我们可以使用sar命令去查看每个CPU的资源使用情况(可能不一定准确,因为系统中还有别的进程在使用CPU,假如你这台服务器完全给nginx使用,那么这条指令是极具参考作用的)

# 查看第一个CPU的资源使用情况,每个1秒输出一次,共输出5次
sar -P 0 1 5

 输出结果如下:


Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain)    07/24/2022      _x86_64_        (6 CPU)02:25:49 PM     CPU     %user     %nice   %system   %iowait    %steal     %idle
02:25:50 PM       0      0.00      0.00      0.00      0.00      0.00    100.00
02:25:51 PM       0      0.00      0.00      0.00      0.00      0.00    100.00
02:25:52 PM       0      0.00      0.00      0.00      0.00      0.00    100.00
02:25:53 PM       0      0.00      0.00      0.00      0.00      0.00    100.00
02:25:54 PM       0      0.00      0.00      0.00      0.00      0.00    100.00
Average:          0      0.00      0.00      0.00      0.00      0.00    100.00

所以我们可以在nginx.conf配置下面这条命令,使得worker进程一一与下面的CPU对应

worker_cpu_affinity 0001 0010 0011 0100 0101 0110;
策略3(提升进程优先级)

Linux实时进程priority处于0-99,用户进程priority处于100-139,这个值越小优先级越高。priority的值的计算如下所示。
root用户nice可以将nice-20~19,普通用户只能0~19(避免抢占系统资源进程优先级)

priority(new) = priority(old) + nice

在演示提高优先级前,我们先查看一下nginx的进程优先级,

ps -elf |grep nginx

如下所示worker进程priority都是80


5 S root       2891      1  0  80   0 - 19456 sigsus 14:06 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
5 S nginx      5108   2891  0  80   0 - 20085 ep_pol 17:33 ?        00:00:00 nginx: worker process
5 S nginx      5109   2891  0  80   0 - 20085 ep_pol 17:33 ?        00:00:00 nginx: worker process
5 S nginx      5110   2891  0  80   0 - 20085 ep_pol 17:33 ?        00:00:00 nginx: worker process
5 S nginx      5111   2891  0  80   0 - 20085 ep_pol 17:33 ?        00:00:00 nginx: worker process
5 S nginx      5112   2891  0  80   0 - 20085 ep_pol 17:33 ?        00:00:00 nginx: worker process
5 S nginx      5113   2891  0  80   0 - 20085 ep_pol 17:33 ?        00:00:00 nginx: worker process
5 S nginx      5114   2891  0  80   0 - 20032 ep_pol 17:33 ?        00:00:00 nginx: cache manager process
0 S root       5205   4963  0  80   0 - 28203 pipe_w 17:39 pts/0    00:00:00 grep --color=auto nginx

对于nginx提高优先级的配置也非常简单,只需在nginx.conf加下面一行即可,这条配置就会将nice改为-20。

worker_priority -20;

再次查看发现nice变为-20,优先级变为60.

 ps -elf |grep nginx

输出结果如下:

5 S root       2891      1  0  80   0 - 19456 sigsus 14:06 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
5 S nginx      5208   2891  0  60 -20 - 20089 ep_pol 17:40 ?        00:00:00 nginx: worker process
5 S nginx      5209   2891  0  60 -20 - 20089 ep_pol 17:40 ?        00:00:00 nginx: worker process
5 S nginx      5210   2891  0  60 -20 - 20089 ep_pol 17:40 ?        00:00:00 nginx: worker process
5 S nginx      5211   2891  0  60 -20 - 20089 ep_pol 17:40 ?        00:00:00 nginx: worker process
5 S nginx      5212   2891  0  60 -20 - 20089 ep_pol 17:40 ?        00:00:00 nginx: worker process
5 S nginx      5213   2891  0  60 -20 - 20089 ep_pol 17:40 ?        00:00:00 nginx: worker process
5 S nginx      5214   2891  0  80   0 - 20036 ep_pol 17:40 ?        00:00:00 nginx: cache manager process
0 S root       5222   4963  0  80   0 - 28203 pipe_w 17:40 pts/0    00:00:00 grep --color=auto nginx
策略4(延迟处理新连接)

我们可以在location模块的监听后面加一个deferred,加上这个配置后,当用户与nginx服务器建立连接时,只有用户有请求数据时才会将TCP连接状态改为ESTABLISHED,否则就直接丢弃这条连接。
通过减少服务器和客户端之间发生的三次握手建立连接的数量来帮助提高性能。

 listen       80 deferred;

提升nginx的网络性能

简介网络四层模型

我们的大学教程大部分讲述七层模型,实际上现代网络协议使用的都是四层模型,如下图,应用层报文经过四层的首部封装到对端。对端链路层拆开首部查看mac地址是自己在网上,拆开ip首部查看目的地址是不是自己,然后到达传输层应用层完成报文接收。

基于TCP连接实现nginx网络性能优化

对于网络问题,我们可以使用tcpdumppingsar等指令排查

如下我们使用ping查看网络连通性

ping -c 3 192.168.12.128

 们ping的服务器是上游服务器0% packet loss说明连通性没问题。


PING 192.168.12.128 (192.168.12.128) 56(84) bytes of data.
64 bytes from 192.168.12.128: icmp_seq=1 ttl=64 time=0.446 ms
64 bytes from 192.168.12.128: icmp_seq=2 ttl=64 time=4.33 ms
64 bytes from 192.168.12.128: icmp_seq=3 ttl=64 time=2.44 ms--- 192.168.12.128 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.446/2.409/4.336/1.588 ms

同样我们也可以使用sar来查看网络数据包的收发情况

sar -n DEV 1 3

输出结果如下:

Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain)    07/24/2022      _x86_64_        (6 CPU)06:11:22 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
06:11:23 PM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
06:11:23 PM virbr0-nic      0.00      0.00      0.00      0.00      0.00      0.00      0.00
06:11:23 PM    virbr0      0.00      0.00      0.00      0.00      0.00      0.00      0.00
06:11:23 PM     ens33      0.00      0.00      0.00      0.00      0.00      0.00      0.00# 略

对应参数含义:

#IFACE 本地网卡接口的名称
#rxpck/s 每秒钟接受的数据包
#txpck/s 每秒钟发送的数据库
#rxKB/S 每秒钟接受的数据包大小,单位为KB
#txKB/S 每秒钟发送的数据包大小,单位为KB
#rxcmp/s 每秒钟接受的压缩数据包
#txcmp/s 每秒钟发送的压缩包
#rxmcst/s 每秒钟接收的多播数据包

如下所示通过netstat 这条指令可以看到网口的收发情况

 netstat -I

RX-ERR/TX-ERR基本为0,说明网络质量良好

 

Kernel Interface table
Iface             MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
ens33            1500     3393      0      0 0          2101      0      0      0 BMRU
lo              65536     1600      0      0 0          1600      0      0      0 LRU
virbr0           1500        0      0      0 0             0      0      0      0 BMU

TCP内核参数详解
net.ipv4.tcp_syn_retries

表示应用程序进行 connect() 系统调用时,在对方不返回 SYN + ACK 的情况下 (也就是超时的情况下),第一次发送之后,内核最多重试几次发送 SYN 包,并且决定了等待时间。
Linux 上的默认值是 net.ipv4.tcp_syn_retries = 6 ,也就是说如果是本机主动发起连接(即主动开启 TCP 三次握手中的第一个 SYN 包),如果一直收不到对方返回 SYN + ACK ,那么应用程序最大的超时时间就是 127 秒。

我们可以通过以下指令看到,他的默认值为6

 cat /proc/sys/net/ipv4/tcp_syn_retries
6

 对此我们可以实验以下印证这个问题,128服务器将127的包drop掉,看看127这台服务器的请求会不会重试6次

首先我们开启一个终端抓一次127服务器的发送给128的HTTP包

tcpdump -i ens33 -nn 'dst 192.168.12.128 and  tcp port 80'

 然后设置128的服务器将127服务器的包丢弃

iptables -I INPUT -s 192.168.12.127 -j DROP

这时候127使用curl尝试连通

curl http://192.168.12.128

然后基于tcpdump进行监控:

 tcpdump -i ens33 -nn 'dst 192.168.12.128 and  tcp port 80'

实验结果最终为发现,确实超市重试了6次,每次超时等待时间都是上一次的2倍

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:35:02.372499 IP 192.168.12.127.41216 > 192.168.12.128.80: Flags [S], seq 3711897357, win 29200, options [mss 1460,sackOK,TS val 19661434 ecr 0,nop,wscale 7], length 0# 超时重试6次
19:35:03.375342 IP 192.168.12.127.41216 > 192.168.12.128.80: Flags [S], seq 3711897357, win 29200, options [mss 1460,sackOK,TS val 19662436 ecr 0,nop,wscale 7], length 0
19:35:05.378852 IP 192.168.12.127.41216 > 192.168.12.128.80: Flags [S], seq 3711897357, win 29200, options [mss 1460,sackOK,TS val 19664440 ecr 0,nop,wscale 7], length 0
19:35:09.386363 IP 192.168.12.127.41216 > 192.168.12.128.80: Flags [S], seq 3711897357, win 29200, options [mss 1460,sackOK,TS val 19668448 ecr 0,nop,wscale 7], length 0
19:35:17.402651 IP 192.168.12.127.41216 > 192.168.12.128.80: Flags [S], seq 3711897357, win 29200, options [mss 1460,sackOK,TS val 19676464 ecr 0,nop,wscale 7], length 0
19:35:33.418587 IP 192.168.12.127.41216 > 192.168.12.128.80: Flags [S], seq 3711897357, win 29200, options [mss 1460,sackOK,TS val 19692480 ecr 0,nop,wscale 7], length 0
19:36:05.482794 IP 192.168.12.127.41216 > 192.168.12.128.80: Flags [S], seq 3711897357, win 29200, options [mss 1460,sackOK,TS val 19724544 ecr 0,nop,wscale 7], length 0

在网络情况良好的情况下,TCP连接完全不需要这么多次的重试,对此我们可以调小可以参数值

为了将这个值永久生效,我们需要编辑如下文件

vim /etc/sysctl.conf

添加一行

net.ipv4.tcp_syn_retries = 2

使用sysctl -p使之生效

[root@localhost run]# sysctl -p# 可以看到这条命令会输出刚刚修改的内容
net.ipv4.tcp_syn_retries = 2

再次实验,可以看到127的抓包,仅仅重试了两次而已

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
20:33:43.041369 IP 192.168.12.127.41218 > 192.168.12.128.80: Flags [S], seq 2527903951, win 29200, options [mss 1460,sackOK,TS val 23182103 ecr 0,nop,wscale 7], length 0# 重试了两次
20:33:44.043910 IP 192.168.12.127.41218 > 192.168.12.128.80: Flags [S], seq 2527903951, win 29200, options [mss 1460,sackOK,TS val 23183104 ecr 0,nop,wscale 7], length 0
20:33:46.046469 IP 192.168.12.127.41218 > 192.168.12.128.80: Flags [S], seq 2527903951, win 29200, options [mss 1460,sackOK,TS val 23185108 ecr 0,nop,wscale 7], length 0
net.ipv4.tcp_synack_retries

当服务器接收到客户端发送的SYN连接请求报文后,回应SYNC+ACK报文,并等待客户端的ACK确认,如果超时会进行重传,重传次数由下列参数设置,默认为5

 
[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_synack_retries
5

 

为了印证这一点,我们将将上文128的drop还原accept,将127收到的128的包drop掉

iptables -I INPUT -s 192.168.12.128 -j DROP

此时我们使用curl命令

[root@localhost run]# curl http://192.168.12.128
curl: (7) Failed connect to 192.168.12.128:80; Connection timed out

抓到128服务器的包发现果然重试了5次

# 在128服务器抓回给127服务器的包
[root@localhost ~]# tcpdump -i ens33 -nn 'dst 192.168.12.127 '
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
20:47:42.062075 IP 192.168.12.1.61588 > 192.168.12.127.22: Flags [P.], seq 3290041520:3290041568, ack 2422181631, win 4106, length 48
20:47:42.114303 IP 192.168.12.1.61588 > 192.168.12.127.22: Flags [.], ack 49, win 4106, length 0
20:47:42.587274 IP 192.168.12.1.61588 > 192.168.12.127.22: Flags [P.], seq 48:96, ack 49, win 4106, length 48
# 第一次
20:47:42.593961 IP 192.168.12.128.80 > 192.168.12.127.41224: Flags [S.], seq 806829342, ack 2654770401, win 28960, options [mss 1460,sackOK,TS val 23416004 ecr 24020034,nop,wscale 7], length 0
20:47:42.631701 IP 192.168.12.1.61588 > 192.168.12.127.22: Flags [.], ack 97, win 4105, length 0
# 超时重试第1次
20:47:43.595729 IP 192.168.12.128.80 > 192.168.12.127.41224: Flags [S.], seq 806829342, ack 2654770401, win 28960, options [mss 1460,sackOK,TS val 23417006 ecr 24020034,nop,wscale 7], length 0
# 超时重试第2次
20:47:43.595941 IP 192.168.12.128.80 > 192.168.12.127.41224: Flags [S.], seq 806829342, ack 2654770401, win 28960, options [mss 1460,sackOK,TS val 23417006 ecr 24020034,nop,wscale 7], length 0
# 超时重试第3次
20:47:45.596646 IP 192.168.12.128.80 > 192.168.12.127.41224: Flags [S.], seq 806829342, ack 2654770401, win 28960, options [mss 1460,sackOK,TS val 23419007 ecr 24020034,nop,wscale 7], length 0
# 超时重试第4次
20:47:45.599521 IP 192.168.12.128.80 > 192.168.12.127.41224: Flags [S.], seq 806829342, ack 2654770401, win 28960, options [mss 1460,sackOK,TS val 23419010 ecr 24020034,nop,wscale 7], length 0
20:47:46.907779 ARP, Request who-has 192.168.12.127 (00:0c:29:bd:2b:9e) tell 192.168.12.1, length 46
20:47:47.597905 ARP, Request who-has 192.168.12.127 tell 192.168.12.128, length 28
20:47:49.655826 IP 192.168.12.1.61588 > 192.168.12.127.22: Flags [.], ack 161, win 4105, length 0
# 超时重试第5次
20:47:49.998252 IP 192.168.12.128.80 > 192.168.12.127.41224: Flags [S.], seq 806829342, ack 2654770401, win 28960, options [mss 1460,sackOK,TS val 23423408 ecr 24020034,nop,wscale 7], length 0

127作为nginx服务器,为了避免没必要的开销,无论与上游服务器还是和客户之前synack重试次数实际上也不要这么大,完完全全可以调小些例如2

net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syncookies

该参数在Centos6、7已经默认为1,这个参数开启后不会将还为建立的tcp连接存到SYN队列中,而是响应一个ACK+算好的cookie值,只要对方发送SYN+ACK+cookie包后才会将其存到队列中,这样的设置可以避免syn洪泛攻击

[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_syncookies
1
net.core.netdev_max_backlog

net.core.netdev_max_backlog参数表示网卡接受数据包的队列最大长度,在阿里云服务器上,默认值是1000,可以适当调整。

net.ipv4.tcp_max_syn_backlog

net.ipv4.tcp_max_syn_backlog参数决定已经收到syn包,但是还没有来得及确认的连接队列,这是传输层的队列,在高并发的情况下,必须调整该值,提高承载能力。

net.core.somaxconn

net.core.somaxconn参数决定了端口监听队列的最大长度,存放的是已经处于ESTABLISHED而没有被用户程序(例如nginx)接管的TCP连接,默认是128,对于高并发的,或者瞬发大量连接,必须调高该值,否则会直接丢弃连接。

上述三个队列位置图解

可以看到在高并发的情况下这些参数都必须调大。我们建议的配置如下,可以看到net.core.somaxconn设置为65535因为操作系统内核允许完全建立的连接大小不能超过65535,而另外两个参数可以24800是因为这些连接是尚未建立连接的数据包,所以数量可以多一些


net.core.netdev_max_backlog = 24800
net.ipv4.tcp_max_syn_backlog = 24800
net.core.somaxconn = 65535

这时候我们就可以调整nginx的backlog,可以看到笔者设置为24800,虽然这个值已经大于操作系统的somaxconn 大小,但这并不会报错,相反这样的设置可以使得nginx尽可能的榨取队列资源。

listen 80 deferred backlog=24800 ;

TCP的Fast Open

该参数是用来加速TCP连接数据交互的TCP扩展协议,是Google在2011年论文提出的。
原有tcp协议三次握手以及数据交互如下图,必须完全建立连接后才能发送数据

 

而经过RFC优化之后的的TCP交互如下图,可以看到在最后一次确认的时候可以直接将请求数据携带过去

 

而TCP Fast Open在此基础上,新增一个特性,在建立TCP连接期间,服务端会发给用户一个cookie,当本次TCP连接断开后,用户可以使用这个cookie快速与服务端建立连接。这个机制很适合用于nginx服务器与上游服务器的交互。

使用sysctl -a |grep tcp_fast即可看到这个值的默认值为0代表不开启TFO,1代表作为客户端时拥有TFO机制,2代表作为服务端才拥有TFO机制,3代表该服务器完全支持TFO机制。

[root@localhost ~]# sysctl -a |grep tcp_fast
net.ipv4.tcp_fastopen = 0
net.ipv4.tcp_fastopen_key = 00000000-00000000-00000000-00000000

 

所以我们建议nginx作为服务器的情况下可以开启TFO,参数可以设置为

net.ipv4.tcp_fastopen = 2

总结

文章是基于原有个人知识基础上,对旧知识进行巩固,以及新知识实践学习。对于基于操作系统的优化亦或者其他知识,我们在学习过程中势必会遇到很多陌生的概念,我们切不可急躁,善于使用搜索引擎以及原有积累的知识去理解每一个概念,将参考文献补充完善,以便于后续回顾以及后续遇到相同场景我们可以快速完成问题的解决。这就是学习的技巧——突破学习材料瓶颈,打破学习材料的局限性,完成技术栈的学习。

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

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

相关文章

MacOS安装homebrew

文章目录 官网脚本无法正常下载安装使用HomebrewCN国内安装脚本进行安装找到一份合适的安装脚步执行安装脚本 Homebrew自己的安装位置使用Homebrew安装tree指令验证安装是否成功Homebrew把软件程序都安装到哪里了 Homebrew安装需要依赖Git,请先确保Git已安装成功 Ho…

阿里云短信服务接口返回: 只能向已回复授权信息的手机号发送

1、问题描述 在阿里云短信服务控制台,调用发送短信接口,报错:只能向已回复授权信息的手机号发送 2、问题分析 所使用的签名 是 测试or个人学习的 ,所以会导致 有的手机号发送不出去验证码 3、解决 如果在测试阶段,非要…

YOLOv5:修改backbone为MobileOne

YOLOv5:修改backbone为MobileOne 前言前提条件相关介绍MobileOneYOLOv5修改backbone为MobileOne修改common.py修改yolo.py修改yolov5.yaml配置 参考 前言 记录在YOLOv5修改backbone操作,方便自己查阅。由于本人水平有限,难免出现错漏&#xf…

手动仿射变换

开发环境: Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码目的:学习与总结 demo解决问题:通过仿射控件vtkAffineWidget对目标actor进行手动的拖拽的仿射变换 关键类:vtkAffineWi…

C语言_自定义类型详解

文章目录 前言一.结构体的声明1.1结构体的基础知识1.2结构的声明1.3特殊声明1.4结构体的自引用在结构中包含一个类型为该结构本身的成员是否可以?正确的自引用方式匿名结构体类型和typedef的结合形式 1.5 结构体变量的定义和初始化结构体定义与初始化结构体里嵌套结…

探求flutter全栈开发

显示一种网络图片 import package:flutter/material.dart; main(){runApp(MaterialApp(theme: ThemeData.dark(),home:Home(),));}class Home extends StatelessWidget{overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar:AppBar(t…

图像二值化阈值调整——OTSU算法(大津法/最大类间方差法)

大津算法(OTSU算法)是一种常用的图像二值化方法,用于将灰度图像转化为二值图像。该算法由日本学者大津展之于1979年提出,因此得名。 大津算法的核心思想是通过寻找一个阈值,将图像的像素分为两个类别:前景…

LangChain介绍及代码实践

一、简介 LangChian 作为一个大语言模型开发框架,是 LLM 应用架构的重要一环。那什么是 LLM 应用架构呢?其实就是指基于语言模型的应用程序设计和开发的架构。 LangChian 可以将 LLM 模型、向量数据库、交互层 Prompt、外部知识、外部工具整合到一起&a…

与云栖的浪漫邂逅:记一段寻找云端之美的旅程

云端之旅 2023 年的云栖大会如约而至,这次云栖大会也是阿里新任掌门蔡老板当任阿里巴巴董事局主席以来的第一次。大会与以往有很多不一样的地方,其中 AIGC 更是本届大会的重点议题!你会感叹,阿里还是猛啊! 我逛了下展…

高校教务系统登录页面JS分析——天津大学

高校教务系统密码加密逻辑及JS逆向 本文将介绍天津大学教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的过程。通过本文,你将了解到密码加密的基本概念、常用加密算法以及如何通过逆向分析来破解密码。 本文仅供交流学习,勿用于非法用途。 一、密…

优先队列----数据结构

概念 不知道你玩过英雄联盟吗?英雄联盟里面的防御塔会攻击离自己最近的小兵,但是如果有炮车兵在塔内,防御塔会优先攻击炮车(因为炮车的威胁性更大),只有没有兵线在塔内时,防御塔才会攻击英雄。…

Azure机器学习 - 在 Azure 机器学习中上传、访问和浏览数据

目录 一、环境准备二、设置内核三、下载使用的数据四、创建工作区的句柄五、将数据上传到云存储空间六、访问笔记本中的数据七、创建新版本的数据资产八、清理资源 机器学习项目的开始阶段通常涉及到探索性数据分析 (EDA)、数据预处理(清理、特征工程)以…