当前位置: 首页 > article >正文

深度解析:Nginx模块架构与工作机制的奥秘

文章目录

  • 前言
    • Nginx是什么?
    • Ngnix特点:
  • 一、Nginx模块与工作原理
    • 1.Nginx的模块
      • 1.1 Nginx模块常规的HTTP请求和响应的流程图:
      • 1.2 Nginx的模块从结构上分为如下三类:
      • 1.3 Nginx的模块从功能上分为如下三类:
    • 2.Nginx的进程模型
      • 2.1 Nginx进程结构
      • 2.2 nginx进程管理
    • 3.多进程I/O模型
      • 3.1 nginx的多进程模型
      • 3.2 nginx支持的事件模型
  • 二、Nginx的适用场景
    • 2.1 HTTP服务器
    • 2.2 反向代理/负载均衡
    • 2.3 虚拟主机
    • 2.4 Nginx三大功能总结
  • 三、nginx和其他web服务的对比
    • 3.1 nginx对比httpd
    • 3.2 Nginx对比HProxy 、LVS

前言

Nginx是什么?

Nginx是由俄罗斯的程序设计师伊戈尔·西索夫(Igor Sysoev)所开发,一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。
官方测试nginx 能够支支撑 5 万并发链接,并且 cpu、内存等资源消耗却非常低,运行非常稳定其特点是占有内存少,并发能力强。
事实上nginx的并发能力在同类型的网页服务器中表现较好,国内使用Nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

Ngnix特点:

  1. 高并发:单机支持10万以上的并发连接;
  2. 高性能:低内存消耗:一般1万个非活跃的 HTTP Keep-Alive 连接在 Nginx 中仅消耗2.5MB内存;
  3. 高可靠性:可以在服务器上持续不间断运行数年;
  4. 高拓展性:主要体现在它的模块化设计,模块化设计非常的稳定使得nginx的第三方模块生态圈非常的丰富,丰富的生态圈为我们nginx丰富的功能提供了保证;
  5. 热部署:master 管理进程与 worker工作进程的分离设计,使得 Nginx 能够支持热部署;
  6. 开源协议:使用 BSD 许可协议,免费使用,且可修改源码。

一、Nginx模块与工作原理

1.Nginx的模块

1.1 Nginx模块常规的HTTP请求和响应的流程图:

在这里插入图片描述

1.2 Nginx的模块从结构上分为如下三类:

核心模块:HTTP模块、EVENT模块和MAIL模块
基础模块:HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块,
第三方模块:HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块。
用户可根据自己的需要开发的模块都属于第三方模块。

1.3 Nginx的模块从功能上分为如下三类:

Handlers(处理器模块) 此类模块直接处理请求,并进行输出内容和修改headers信息等操作。Handlers处理器模块一般只能有一个。
Filters (过滤器模块) 此类模块主要对其他处理器模块输出的内容进行修改操作,最后由Nginx输出。
Proxies (代理类模块) 此类模块是Nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务比如FastCGI等进行交互,实现服务代理和负载均衡等功能。

2.Nginx的进程模型

2.1 Nginx进程结构

在这里插入图片描述

2.2 nginx进程管理

在这里插入图片描述
2.2.1 Master进程
核心功能: 管理进程
master进程主要用来管理worker进程,具体包括如下4个主要功能:

  1. 接收来自外界的信号。
  2. 向各worker进程发送信号。
  3. 监控woker进程的运行状态。
  4. 当woker进程退出后(异常情况下),会自动重新启动新的woker进程。

用户交互接口:master进程充当整个进程组与用户的交互接口,同时对进程进行监护。它不需要处理网络事件,不负责业务的执行,只会通过管理worker进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能。

重启work进程:我们要控制nginx,只需要通过kill向master进程发送信号就行了。比如kill -HUP pid,则是告诉nginx,从容地重启nginx,我们一般用这个信号来重启nginx,或重新加载配置,因为是从容地重启,因此服务是不中断的。

master进程在接收到HUP信号后是怎么做的呢?

  1. 首先master进程在接到信号后,会先重新加载配置文件,然后再启动新的worker进程,并向所有老的worker进程发送信号,告诉他们可以光荣退休了。

  2. 新的worker在启动后,就开始接收新的请求,而老的worker在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出。

直接给master进程发送信号,这是比较传统的操作方式,nginx在0.8版本之后,引入了一系列命令行参数,来方便我们管理。比如,./nginx -s reload,就是来重启nginx,./nginx -s stop,就是来停止nginx的运行。如何做到的呢?我们还是拿reload来说,我们看到,执行命令时,我们是启动一个新的nginx进程,而新的nginx进程在解析到reload参数后,就知道我们的目的是控制nginx来重新加载配置文件了,它会向master进程发送信号,然后接下来的动作,就和我们直接向master进程发送信号一样了。

2.2.2 worker进程
核心功能:处理请求
基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的。

worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?

Nginx采用异步非阻塞的方式来处理网络事件,类似于Libevent,具体过程如下:

  1. 接收请求:首先,每个worker进程都是从master进程fork过来,在master进程建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。所有worker进程的listenfd会在新连接到来时变得可读,每个work进程都可以去accept这个socket(listenfd)。当一个client连接到来时,所有accept的work进程都会受到通知,但只有一个进程可以accept成功,其它的则会accept失败。为保证只有一个进程处理该连接,Nginx提供了一把共享锁accept_mutex来保证同一时刻只有一个work进程在accept连接。所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。
  2. 处理请求:当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。
    我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。worker进程之间是平等的,每个进程,处理请求的机会也是一样的。

3.多进程I/O模型

3.1 nginx的多进程模型

优势:
首先,对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。

其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快启动新的worker进程。当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低了风险。

虽然nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发数很有限啊,多少个worker就能处理多少个并发,何来高并发呢?非也,这就是nginx的高明之处,nginx采用了异步非阻塞的方式来处理请求,也就是说,nginx是可以同时处理成千上万个请求的。一个worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,因此,当Nginx上的进程数与CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),进程间切换的代价是最小的。

而apache的常用工作方式(apache也有异步非阻塞版本,但因其与自带某些模块冲突,所以不常用),每个进程在一个时刻只处理一个请求,因此,当并发数上到几千时,就同时有几千的进程在处理请求了。这对操作系统来说,是个不小的挑战,进程带来的内存占用非常大,进程的上下文切换带来的cpu开销很大,自然性能就上不去了,而这些开销完全是没有意义的。

在这里插入图片描述

3.2 nginx支持的事件模型

Nginx支持如下处理连接的方法(I/O复用方法),这些方法可以通过use指令指定。

select– 标准方法 如果当前平台没有更有效的方法,它是编译时默认的方法。你可以使用配置参数 –with-select_module 和 –without-select_module 来启用或禁用这个模块。

poll– 标准方法 如果当前平台没有更有效的方法,它是编译时默认的方法。你可以使用配置参数 –with-poll_module 和 –without-poll_module 来启用或禁用这个模块。
3.2.3 kqueue– 高效的方法,使用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X. 使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃。

epoll – 高效的方法,使用于Linux内核2.6版本及以后的系统。在某些发行版本中,如SuSE 8.2, 有让2.4版本的内核支持epoll的补丁。

rtsig – 可执行的实时信号,使用于Linux内核版本2.2.19以后的系统。默认情况下整个系统中不能出现大于1024个POSIX实时(排队)信号。这种情况 对于高负载的服务器来说是低效的;所以有必要通过调节内核参数 /proc/sys/kernel/rtsig-max 来增加队列的大小。可是从Linux内核版本2.6.6-mm2开始, 这个参数就不再使用了,并且对于每个进程有一个独立的信号队列,这个队列的大小可以用 RLIMIT_SIGPENDING 参数调节。当这个队列过于拥塞,nginx就放弃它并且开始使用 poll 方法来处理连接直到恢复正常。
/dev/poll – 高效的方法,使用于 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+.
3.2.6 eventport – 高效的方法,使用于 Solaris 10. 为了防止出现内核崩溃的问题, 有必要安装这个 安全补丁。

在linux下面,只有epoll是高效的方法

二、Nginx的适用场景

2.1 HTTP服务器

Nginx作为HTTP服务器:是指在web项目开发时,总是将项目部署在tomcat jetty等应用服务器上,而服务端所需要的资源,文本数据和静态资源路径自然存放在数据库中,而静态资源实体(如图片、音视频等)既不能放在数据库中,又不能放在应用服务器的相关目录下,这个时候我们需要一种用来存放项目所需静态资源的服务器(只要在数据库的字段中存储好静态资源的路径即可),这就是http服务器——Nginx。
通常我们使用nginx处理静态资源请求,例如 图片、css、js、html等请求,动态请求交由后端服务(java程序,php程序,python程序等)去处理。这种方式也可称为动静分离。
静态请求和动态请求最直接的区别是是否连接数据库进行数据交互。

一个网页的js请求如下图所示:
在这里插入图片描述
配置Nginx——修改Nginx安装目录nginx.conf

server {
    listen       81; # 监听的端口
    server_name  localhost; # 域名或IP
    location / {      # 访问路径配置
        root   /var/www/html; # 根目录
        index  index.html index.htm; # 默认首页
    }
    error_page   500 502 503 504  /50x.html;      # 错误页面
    location = /50x.html {
        root   /var/www/errpage;
    }
} 

现在对这段代码解释,实际上,对于Nginx做服务器,和其他服务器一样,只要搞清“ ip:port、页面、后台目录”三个东西:
指定ip:port是localhost:81,我们直接在Linux计算机的浏览器上输入localhost:81,显示的是index.html/index.htm界面,对应后台目录是Nginx安装目录/index目录(如usr/local/nginx/index);我们直接在Linux计算机的浏览器上输入localhost:81/50x.html,对应后台目录是Nginx安装目录/html目录(如usr/local/nginx/html).
关于匹配关系,上面的配置中/表示可以匹配所有,/50x.html表示可以匹配50x.html,优先级关系是优先匹配长的,如localhost:81/50x.html同时满足/和/50x.html,由于优先匹配长的,所以要导向到html目录。如localhost:81/xxx.html仅满足于/,所以导向到index目录。
关于页面优先关系, index、index.html、index.htm;优先关系是从左到右,有index.html就显示index.html,没有就显示index.htm。

对于上面的理解如下图:
在这里插入图片描述

2.2 反向代理/负载均衡

Nginx反向代理:Nginx作为服务端代理,代表实际应用服务器与客户端交流,将网络请求分发给后台实际服务器。
Nginx负载均衡:Nginx作为服务端代理,根据weight权重将网络请求分发给后台实际服务器。
负载均衡和反向代理的关系:负载均衡是通过反向代理来实现的,负载均衡=反向代理+weight权重。

2.2.1 正向代理与反向代理
正向代理:是指客户端的代理,代表客户端向服务端发出网络请求,如图:
在这里插入图片描述
反向代理:是指服务端的代理,代表服务端向客户端发出响应结果,如图:
在这里插入图片描述
正向代理+反向代理,由客户端代理服务器代表Client客户机向服务端发出网络请求,由服务端代理服务器代表Server服务机向客户端发出响应结果。如图:
在这里插入图片描述
最简单的理解,正向代理和反向代理这个知识是计算机网络中的一个知识,由于当前使用的http网络请求时基于请求-响应模式,服务端开启后被动等待(websocket协议服务端也可以发送消息给客户端),由客户端主动发起网络请求(get请求、post请求),服务端提供结果响应,然后客户端再一次主动发起网络请求,服务端再一次提供结果响应

客户端局域网LAN1中的代理服务器代表客户端主机,我们称之为正向代理,正向代理隐藏了客户端,其存在的意义在于 客户端无法直接访问到服务端,但是 代理服务器可以访问到服务端,所以客户端通过代理服务器来访问到服务端。
2.2.2 Nginx实现反向代理
Nginx是如何实现反向代理的,我们一步步来分析。两个Tomcat服务通过Nginx反向代理,本例子使用三台虚拟机进行测试。
Nginx服务器:192.168.1.2
tomcat1服务器:192.168.1.100
tomcat2服务器:192.168.1.101

客户端访问流程如下:
在这里插入图片描述
这里的配置是基于域名实现的反向代理。
配置一个代理即tomcat1服务器

upstream tomcat_server1 {
        server 192.168.1.100:8080;
    }

配置一个代理即tomcat2服务器

upstream tomcat_server2 {
        server 192.168.1.101:8080;
    }

配置一个虚拟主机

 server {
    listen 80;
    server_name aaa.com;
    location / {
            #域名aaa.com的请求全部转发到tomcat_server1即tomcat1服务上
            proxy_pass http://tomcat_server1;
            #欢迎页面,按照从左到右的顺序查找页面
            index index.jsp index.html index.htm;
    }

}
server {
    listen 80;
    server_name bbb.com;

    location / {
             #域名bbb.com的请求全部转发到tomcat_server2即tomcat2服务上
              proxy_pass http://tomcat_server2;
              index index.jsp index.html index.htm;
    }
}

2.2.3 nginx的负载均衡算法
对于负载均衡,它的最重要的 upstream 参数,还有就是nginx的默认的负载均衡算法和常用的负载均衡算法。
wrr:英文全称weighted round-robin,就是权重(就是上面的weight)轮询,这是默认负载均衡方式.
ip_hash:IP的哈希结果固定选择一个真实服务器,每个请求只访问tomcat,解决跨节点session共享问题,分布式登录的时候用到。
leas_conn:该负载均衡方案同时考虑连接数和权重两个因素,连接数越小且权重越大,则优先,如果上一次刚刚分配,本次不分配。

2.2.4 同源策略
所谓同源,是否同源由URL决定,URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。
同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略禁止这种跨域请求。后端分离已经是web应用最常见的架构。但由于浏览器的同源策略导致web应用访问不同域的资源不得不面临跨域访问问题。
配置方法:
add_header Access-Control-Allow-Origin; //允许所有域名跨域访问代理地址,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求
add_header Access-Control-Allow-Headers XXX XXX XXX; 表明服务器允许请求中携带字段
add_header Access-Control-Allow-Methods; //跨域请求访问请求方式,
在这里插入图片描述

2.3 虚拟主机

2.3.1 虚机主机简介
Nginx虚拟主机:Nginx部署在一个物理服务器上,却通过IP、端口、域名对外实现多个访问入口,让客户端以为是多个服务器,这就是虚拟主机。
虚拟主机技术,使一个IP,通过port可以对应多个域名。
虚拟主机和负载均衡的区别又是什么?
Nginx做虚拟主机,将一个服务器当做多个服务器用,通过文件目录来虚拟服务器(主机),虚拟主机指的是Nginx自己作为服务器存储文件;
Nginx做负载均衡,Nginx作为服务端代理服务器,将网络请求分发到具体的应用服务器(Tomcat或Jetty),根据不同的应用服务器(Tomcat Jetty)的性能,设置weight权重,Nginx本身不作为服务器存储文件。

2.3.2 在nginx中的配置格式

 ......
events {
.......
}
http{
.......
server{
.......
}
server{
.......
}

} 

Nginx的/conf/nginx.conf配置中,每个server标签就是一个虚拟主机。 实际上,就是同一机器,用不同的目录虚拟成不同的访问入口。
其中,因IP不同形成的不同的访问入口称为“基于IP的虚拟主机”,因端口不同形成的不同的访问入口称为“基于端口的虚拟主机”,因域名不同形成的不同的访问入口称为“基于域名的虚拟主机”。

2.3.3 Nginx三种虚拟主机方式——基于IP的虚拟主机配置
客户端访问流程如下:
在这里插入图片描述
一台Nginx服务器绑定三个IP:192.168.1.2、192.168.1.3、192.168.1.4,访问不同的IP请求不同的html目录,即:访问http://192.168.1.2将访问“html2”目录下的html网页,访问http://192.168.1.3将访问“html3”目录下的html网页,访问http://192.168.1.4将访问“html4”目录下的html网页,如图:

#配置虚拟主机192.168.1.2
server {
    listen       80;
    server_name  192.168.1.2;

    location / {
        root   /usr/local/nginx/html2;
        index  index.html index.htm;
    }

}

} 
#配置虚拟主机192.168.1.3
server {
    listen       80;
    server_name  192.168.1.3;

    location / {
        root   /usr/local/nginx/html3;
        index  index.html index.htm;
    }

}

} 
#配置虚拟主机192.168.1.4
server {
    listen       80;
    server_name  192.168.1.4;

    location / {
        root   /usr/local/nginx/html4;
        index  index.html index.htm;
    }

}

} 

2.3.4 Nginx三种虚拟主机方式——基于端口的虚拟主机配置
客户端访流程问如下:
在这里插入图片描述
一个物理服务器,提供一个IP地址三个端口,分别是192.168.1.2:81、192.168.1.2:82、192.168.1.2:83,在外界客户端开来,好像有三个服务器,都可以独立网络请求,因为它们后台是不同的文件目录,分别是/usr/local/nginx/html2、/usr/local/nginx/html3和/usr/local/nginx/html4,不会产生任何数据文件干扰。

#配置虚拟主机端口81
server {
    listen       81;
    server_name  192.168.1.2;

    location / {
        root   /usr/local/nginx/html2;
        index  index.html index.htm;
    }

}
#配置虚拟主机端口82
server {
    listen       82;
    server_name  192.168.1.2;

    location / {
        root   /usr/local/nginx/html3;
        index  index.html index.htm;
    }

}

#配置虚拟主机端口83
server {
    listen       83;
    server_name  192.168.1.2;

    location / {
        root   /usr/local/nginx/html3;
        index  index.html index.htm;
    }

}

2.3.5 Nginx三种虚拟主机方式——基于域名的虚拟主机配置
客户端访流程问如下:
在这里插入图片描述
一个物理服务器,提供三个域名地址,分别是aaa.com、bbb.com和ccc.com,在外界客户端开来,好像有三个服务器,都可以独立网络请求,因为它们后台是不同的文件目录,/usr/local/nginx/html2、/usr/local/nginx/html3和/usr/local/nginx/html4,不会产生任何数据文件干扰。
客户端测试访问时候需要绑定本地hosts文件解析域名指向nginx服务器IP地址。

2.3.6 小结

  1. 对于基于IP的虚拟主机:由于IP地址本来就稀缺,一个物理服务器配两个IP是不合实际的(毕竟,一个IP比一个服务器贵),所以,基于IP的虚拟主机不常用到,了解即可;

  2. 对于基于端口的虚拟主机:端口倒是不稀缺0-65535(一共65536个,默认是80端口),但是想让用户在浏览器上输入端口是非常不切实际的,所以,基于IP的虚拟主机也不常用到,了解即可;

  3. 对于基于域名的虚拟主机:一个物理服务器/服务器群(一个IP)配置多个域名,是可行的,因为:
    (1) 成本低,域名平均价格比IP便宜的多;
    (2) 客户端可以容易的记得域名,然后在浏览器中输入域名。

2.4 Nginx三大功能总结

http服务器+虚拟主机+负载均衡
在这里插入图片描述

三、nginx和其他web服务的对比

3.1 nginx对比httpd

服务进程模型配置文件性能对比部署方面社区情况
Nginx异步、非阻塞事件驱动配置简洁轻量级支持高并发安装启动简单,支持热启动活跃
httpd进程模型稍复杂重量级不支持高并发安装启动简单,不支持热启动活跃

总结:
Nginx除了可以作为HTTP服务器使用,其强大的反向代理功能还被广泛地用作负载均衡前端服务器,逐渐取代了基于硬件的负载均衡器。在Nginx中可以配置若干个后端服务器,Nginx在收到HTTP请求之后按照一定规则(轮询,IP哈希,优先随机)等将请求转发给后端服务器,实现负载在多台服务器上的平均或加权分配。
同时作为负载均衡的前端还能缓存后端返回的数据,缓解后端服务器的压力。前端采用Nginx做负载均衡限制每个服务器的连接数,后端服务器运行Apache的模式也并不少见。

3.2 Nginx对比HProxy 、LVS

从Nginx、LVS和HProxy 3种负载均衡软件的优缺点、适用性和量级等角度进行详细的对比

项目NginxHAProxyLVS
简介高可用、负载均衡基于TCP和HTTP应用的代理,支持高并发,多集群反向代理高性能http和反向代理服务器、支持高并发、经量级Web,低系统资源消耗Linux虚拟机、VS/DR VS/TUN,VS/NAT,三种模式负载均衡
优点1、正则规则更为强大和灵活
2、Nginx对网络稳定性的依赖非常小
3、可以承担高负载且稳定
4、Nginx可以通过端口检测到服务器内部的故障
1、抗负载能力强、负载均衡速度快
2、支持Session的保持,Cookie的引导,同时支持通过获取指定的url来检测后端服务器的状态
3、HAProxy支持TCP协议的负载均衡转发
1、抗负载能力强、工作在四层,只负责分发作用,
2、配置简单
3、无流量产生,只负责分发请求
4、适应范围广
缺点1、Nginx仅能支持http、https和Email协议
2、对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测
1、不支持POP/SMTP、SPDY、协议,不支持HTTP cache功能
2、重载配置的功能需要重启进程
3、多进程模式支持不够好
1、不支持正规表达式,不能做动静分离
2、如果是网站应用比较庞大,LVS/DR+Keepalived相比前两者实施较为复杂
四层支持支持支持
七层支持支持不支持
支持算法支持轮循
带权轮循
IP哈希算法
支持轮循
带权轮循
原地址保持
RI请求URL rdp-cookie
支持轮循
带权轮循
最小连接数
权重最小连接

http://www.kler.cn/a/410260.html

相关文章:

  • Centos 7 安装 Docker 最新版本
  • Unity清除所有的PlayerPrefs
  • 【C++】C++11新特性详解:可变参数模板与emplace系列的应用
  • SAP开发语言ABAP常见面试问题及答案
  • 学习threejs,使用设置normalMap法向量贴图创建更加细致的凹凸和褶皱
  • C语言练习.if.else语句.strstr
  • FPGA经验谈系列文章——9、块储存器的高效使用
  • Enhancing K8s Gateway API with Easegress Without Changing a Single Line of Code
  • 【数据结构】通过对比二叉查找树、平衡二叉树和B树,对MySQL中的B+树讲解
  • 企业OA管理系统:Spring Boot技术架构与应用
  • Spring Boot英语知识网站:开发与优化
  • AI服务器核心部件产业链升级分析
  • mac终端配置-支持 git branch
  • 数字图像处理(4):FPGA中的定点数、浮点数
  • wsl2的Ubuntu18.04安装ros和anaconda
  • 后端开发详细学习框架与路线
  • 基于python的机器学习(三)—— 关联规则与推荐算法
  • 3D可视化产品定制,打造“所见即所得”的购物体验!
  • FPGA实现串口升级及MultiBoot(九)BPI FLASH相关实例演示
  • sql工具!好用!爱用!
  • Css—实现3D导航栏
  • conda下载与pip下载的区别
  • 丹摩征文活动|实现Llama3.1大模型的本地部署
  • 第三十八章 IOT 通信协议MQTT协议实现的中间件EMQXDocker安装与验证指南
  • 系统使用杂记
  • 一文理解 Python 编程语言中的 .strip() 方法