当前所在位置: 首页 > 百度域名

一个正则表达式怎么会引起线上CPU狂飙?Nginx详细总结(建议收藏)

2021-10-11 本站作者 【 字体:

Nginx简介

Nginx是异步框架的网页服务器,十分轻量级的HTTP服务器,也可以用作反向代理、负载平衡器和HTTP缓存。目前国内知名的公司都在使用,比如新浪、腾讯、豆瓣、163等。该软件由俄罗斯人伊戈尔·赛索耶夫创建并于2004年首次公开发布。2011年成立同名公司以提供支持。2019年3月11日,Nginx公司被F5 Networks以6.7亿美元收购。

作者:陈树义

我们可以看到所有的堆栈都指向了一个名为 validateUrl 的方法,这样的报错信息在堆栈中一共超过 100 处。通过排查代码,我们知道这个方法的主要功能是校验 URL 是否合法。

一个正则表达式怎么会引起线上CPU狂飙?

很奇怪,一个正则表达式怎么会导致 CPU 利用率居高不下。为了弄清楚复现问题,我们将其中的关键代码摘抄出来,做了个简单的单元测试。

public static void main(String[] args) { String badRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\/])+$"; String bugUrl = "http://www.fapiao.com/dddp-web/pdf/download?request=6e7JGxxxxx4ILd-kExxxxxxxqJ4-CHLmqVnenXC692m74H38sdfdsazxcUmfcOH2fAfY1Vw__^DadIfJgiEf"; if (bugUrl.matches(badRegex)) { System.out.println("match!!"); } else { System.out.println("no match!!"); } }

当我们运行上面这个例子的时候,通过资源监视器可以看到有一个名为 java 的进程 CPU 利用率直接飙升到了 91.4% 。

一个正则表达式怎么会引起线上CPU狂飙?

看到这里,我们基本可以推断,这个正则表达式就是导致 CPU 利用率居高不下的凶手!

于是,我们将排错的重点放在了那个正则表达式上:

^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\/])+$

这个正则表达式看起来没什么问题,可以分为三个部分:

第一部分匹配 http 和 https 协议,第二部分匹配 www. 字符,第三部分匹配许多字符。我看着这个表达式发呆了许久,也没发现没有什么大的问题。

Nginx是免费的开源软件,根据类BSD许可证的条款发布。一大部分Web服务器使用Nginx,通常作为负载均衡器。Nginx有着非常好的性能(比Apache快将近67%),因为它是以事件驱动的方式编写的。Nginx采用C进行编写,不论是系统资源开销还是CPU使用效率都很多。

其实这里导致 CPU 使用率高的关键原因就是:Java 正则表达式使用的引擎实现是 NFA 自动机,这种正则表达式引擎在进行字符匹配时会发生回溯(backtracking)。而一旦发生回溯,那其消耗的时间就会变得很长,有可能是几分钟,也有可能是几个小时,时间长短取决于回溯的次数和复杂度。

看到这里,可能大家还不是很清楚什么是回溯,还有点懵。没关系,我们一点点从正则表达式的原理开始讲起。

Nginx详细总结(建议收藏)Nginx特点

Nginx使用异步事件驱动的方法来处理请求。Nginx的模块化事件驱动架构可以在高负载下提供更可预测的性能。是一个安装非常的简单、配置文件非常简洁、Bug非常少的服务。Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。还能够在不间断服务的情况下进行软件版本的升级。

高性能HTTP服务器

Nginx是一款面向性能设计的HTTP服务器,相较于Apache、lighttpd具有占有内存少,稳定性高等优势。与旧版本(≤ 2.2)的Apache不同,Nginx不采用每客户机一线程的设计模型,而是充分使用异步逻辑从而削减了上下文调度开销,所以并发服务能力更强。整体采用模块化设计,有丰富的模块库和第三方模块库,配置灵活。

# 正则表达式引擎

在Linux操作系统下,Nginx使用epoll事件模型,所以Nginx在Linux操作系统下效率相当高。

正则表达式是一个很方便的匹配符号,但要实现这么复杂,功能如此强大的匹配语法,就必须要有一套算法来实现,而实现这套算法的东西就叫做正则表达式引擎。简单地说,实现正则表达式引擎的有两种方式:DFA 自动机(Deterministic Final Automata 确定型有穷自动机)和 NFA 自动机(Non deterministic Finite Automaton 不确定型有穷自动机)。

对于这两种自动机,他们有各自的区别,这里并不打算深入将它们的原理。简单地说,DFA 自动机的时间复杂度是线性的,更加稳定,但是功能有限。而 NFA 的时间复杂度比较不稳定,有时候很好,有时候不怎么好,好不好取决于你写的正则表达式。但是胜在 NFA 的功能更加强大,所以包括 Java 、.NET、Perl、Python、Ruby、PHP 等语言都使用了 NFA 去实现其正则表达式。

那 NFA 自动加到底是怎么进行匹配的呢?我们以下面的字符和表达式来举例说明。

作用:处理静态文件,索引文件以及自动索引;打开文件描述符缓冲.无缓存的反向代理加速,简单的负载均衡和容错.FastCGI,简单的负载均衡和容错.支持 SSL 和 TLSSNI.

可大量并行处理

有报告表明能够支持五万个并行连接,而在实际运作中,可支持二~四万个并行连接。

text="Today is a nice day." regex="day"

要记住一个很重要的点,即:NFA 是以正则表达式为基准去匹配的。也就是说,NFA 自动机会读取正则表达式的一个一个字符,然后拿去和目标字符串匹配,匹配成功就换正则表达式的下一个字符,否则继续和目标字符串的下一个字符比较。或许你们听不太懂,没事,接下来我们以上面的例子一步步解析。

首先,拿到正则表达式的第一个匹配符:d。于是那去和字符串的字符进行比较,字符串的第一个字符是 T,不匹配,换下一个。第二个是 o,也不匹配,再换下一个。第三个是 d,匹配了,那么就读取正则表达式的第二个字符:a。读取到正则表达式的第二个匹配符:a。那着继续和字符串的第四个字符 a 比较,又匹配了。那么接着读取正则表达式的第三个字符:y。读取到正则表达式的第三个匹配符:y。那着继续和字符串的第五个字符 y 比较,又匹配了。尝试读取正则表达式的下一个字符,发现没有了,那么匹配结束。

上面这个匹配过程就是 NFA 自动机的匹配过程,但实际上的匹配过程会比这个复杂非常多,但其原理是不变的。

内存池

为了避免出现内存碎片,减少向操作系统申请内存的次数、降低各个模块的开发复杂度,Nginx 设计了简单的内存池,它的作用主要是把多次向系统申请内存的操作整合成一次,这大大减少了 CPU 资源的消耗,同时减少了内存碎片。

# NFA自动机的回溯

了解了 NFA 是如何进行字符串匹配的,接下来我们就可以讲讲这篇文章的重点了:回溯。为了更好地解释回溯,我们同样以下面的例子来讲解。

text="abbc" regex="ab{1,3}c"

上面的这个例子的目的比较简单,匹配以 a 开头,以 c 结尾,中间有 1-3 个 b 字符的字符串。NFA 对其解析的过程是这样子的.

代理服务器

作为邮件代理服务:Nginx 同时也是一个非常优秀的邮件代理服务(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm 描述了成功并且美妙地使用经验。

首先,读取正则表达式第一个匹配符 a 和 字符串第一个字符 a 比较,匹配了。于是读取正则表达式第二个字符。读取正则表达式第二个匹配符 b{1,3} 和字符串的第二个字符 b 比较,匹配了。但因为 b{1,3} 表示 1-3 个 b 字符串,以及 NFA 自动机的贪婪特性(也就是说要尽可能多地匹配),所以此时并不会再去读取下一个正则表达式的匹配符,而是依旧使用 b{1,3} 和字符串的第三个字符 b 比较,发现还是匹配。于是继续使用 b{1,3} 和字符串的第四个字符 c 比较,发现不匹配了。此时就会发生回溯。发生回溯是怎么操作呢?发生回溯后,我们已经读取的字符串第四个字符 c 将被吐出去,指针回到第三个字符串的位置。之后,程序读取正则表达式的下一个操作符 c,读取当前指针的下一个字符 c 进行对比,发现匹配。于是读取下一个操作符,但这里已经结束了。

下面我们回过头来看看前面的那个校验 URL 的正则表达式:

模块化设计结构

整体采用模块化设计是Nginx的一个重大特点,甚至http服务器核心功能也是一个模块。

^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\/])+$

出现问题的 URL 是:

Nginx详细总结(建议收藏)

和Apache相比

Nginx 的编写有一个明确目标就是超越 Apache Web 服务器的性能。Nginx 提供开箱即用的静态文件,使用的内存比 Apache 少得多,每秒可以处理大约四倍于 Apache 的请求。 在低并发下性能与 Apache 相当(有时候还低于),但是在高并发下 Nginx 能保持低资源低消耗高性能。Nginx 的优点还包括:高度模块化的设计,模块编写简单,以及配置文件简洁。

Nginx架构

Nginx的架构大致流程如下:

http://www.fapiao.com/dzfp-web/pdf/download?request=6e7JGm38jfjghVrv4ILd-kEn64HcUX4qL4a4qJ4-CHLmqVnenXC692m74H5oxkjgdsYazxcUmfcOH2fAfY1Vw__^DadIfJgiEf

我们把这个正则表达式分为三个部分:

Nginx启动后会产生一个主进程,主进程执行一系列的工作后会产生一个或者多个工作进程;在客户端请求动态站点的过程中,Nginx服务器还涉及和后端服务器的通信。Nginx将接收到的Web请求通过代理转发到后端服务器,由后端服务器进行数据处理和组织;Nginx之所以降低网络压力,采用缓存机制,是为了提高对请求的响应效率,将历史应答数据缓存到本地。保障对缓存文件的快速访问;Nginx详细总结(建议收藏)

Nginx 里有一个 master 进程和多个 worker 进程。master 进程并不处理网络请求,主要负责调度工作进程:加载配置、启动工作进程及非停升级。worker 进程负责处理网络请求与响应。

第一部分:校验协议。^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)。第二部分:校验域名。(([A-Za-z0-9-~]+).)+。第三部分:校验参数。([A-Za-z0-9-~/])+$。

我们可以发现正则表达式校验协议 http:// 这部分是没有问题的,但是在校验 www.fapiao.com 的时候,其使用了 xxxx. 这种方式去校验。那么其实匹配过程是这样的:

匹配到 www.匹配到 fapiao.匹配到 com/dzfp-web/pdf/download?request=6e7JGm38jf…..,你会发现因为贪婪匹配的原因,所以程序会一直读后面的字符串进行匹配,最后发现没有点号,于是就一个个字符回溯回去了。

这是这个正则表达式存在的第一个问题。

master进程主要用来管理worker进程,具体包括如下4个主要功能:

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

woker进程主要用来处理基本的网络事件:

多个worker进程之间是对等且相互独立的,他们同等竞争来自客户端的请求。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致。同时,nginx为了更好地利用多核特性,具有cpu绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。Nginx能用来做什么?

下面咱们从配置中来一一解释

另外一个问题是在正则表达式的第三部分,我们发现出现问题的 URL 是有下划线(_)和百分号(%)的,但是对应第三部分的正则表达式里面却没有。这样就会导致前面匹配了一长串的字符之后,发现不匹配,最后回溯回去。

一、静态HTTP服务器

这是这个正则表达式存在的第二个问题。

# 解决方案

明白了回溯是导致问题的原因之后,其实就是减少这种回溯,你会发现如果我在第三部分加上下划线和百分号之后,程序就正常了。

Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML、图片)通过HTTP协议展现给客户端。

二、反向代理服务器

public static void main(String[] args) { String badRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~_%\\/])+$"; String bugUrl = "http://www.fapiao.com/dddp-web/pdf/download?request=6e7JGxxxxx4ILd-kExxxxxxxqJ4-CHLmqVnenXC692m74H38sdfdsazxcUmfcOH2fAfY1Vw__^DadIfJgiEf"; if (bugUrl.matches(badRegex)) { System.out.println("match!!"); } else { System.out.println("no match!!"); } }

运行上面的程序,立刻就会打印出match!!。

客户端本来可以直接通过HTTP协议访问某网站应用服务器,网站管理员可以在中间加上一个Nginx,客户端请求Nginx,Nginx请求应用服务器,然后将结果返回给客户端,此时Nginx就是反向代理服务器。

三、负载均衡

当网站访问量非常大。因为网站越来越慢,一台服务器已经不够用了。于是将同一个应用部署在多台服务器上,将大量用户的请求分配给多台机器处理。同时带来的好处是,其中一台服务器万一挂了,只要还有其他服务器正常运行,就不会影响用户使用。

但这是不够的,如果以后还有其他 URL 包含了乱七八糟的字符呢,我们难不成还再修改一遍。肯定不现实嘛!

Nginx可以通过反向代理来实现负载均衡。

upstream minio-server { ip_hash; # 根据客户端IP地址Hash值将请求分配给固定的一个服务器处理 server 10.95.130.144:9000 weight=25 max_fails=2 fail_timeout=30s; # 应用服务器1 server 10.95.130.145:9000 weight=25 max_fails=2 fail_timeout=30s; # 应用服务器2 server 10.95.130.146:9000 weight=25 max_fails=2 fail_timeout=30s; # 应用服务器3 server 10.95.130.147:9000 weight=25 max_fails=2 fail_timeout=30s; # 应用服务器4 } # weight默认为1,该服务器处理1/4请求 server { listen 80; server_name localhost; charset utf-8; default_type text/html; location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $remote_addr; client_body_buffer_size 10M; client_max_body_size 10G; proxy_buffers 1024 4k; proxy_read_timeout 300; proxy_next_upstream error timeout http_404; root /usr/share/nginx/html; # 静态文件路径 proxy_pass http://minio-server; # 负载均衡 # proxy_pass http://192.168.20.1:8080; # 应用服务器地址,反向代理 } }Nginx详细总结(建议收藏)

四、虚拟主机

有的网站访问量大,需要负载均衡。然而并不是所有网站都如此出色,有的网站,由于访问量太小,需要节省成本,将多个网站部署在同一台服务器上。

例如将www.abc.com和www.def.com两个网站部署在同一台服务器上,两个域名解析到同一个IP地址,但是用户通过两个域名却可以打开两个完全不同的网站,互相不影响,就像访问两个服务器一样,所以叫两个虚拟主机。

其实在正则表达式中有这么三种模式:贪婪模式、懒惰模式、独占模式。

在关于数量的匹配中,有 + ? * {min,max} 四种两次,如果只是单独使用,那么它们就是贪婪模式。

在服务器8080和8081分别开了一个应用,客户端通过不同的域名访问,根据server_name可以反向代理到对应的应用服务器。虚拟主机的原理是通过HTTP请求头中的Host是否匹配server_name来实现的。另外,server_name配置还可以过滤有人恶意将某些域名指向你的主机服务器。

如果在他们之后加多一个 ? 符号,那么原先的贪婪模式就会变成懒惰模式,即尽可能少地匹配。但是懒惰模式还是会发生回溯现象的。TODO例如下面这个例子:

text="abbc" regex="ab{1,3}?c"

正则表达式的第一个操作符 a 与 字符串第一个字符 a 匹配,匹配成。于是正则表达式的第二个操作符 b{1,3}? 和 字符串第二个字符 b 匹配,匹配成功。因为最小匹配原则,所以拿正则表达式第三个操作符 c 与字符串第三个字符 b 匹配,发现不匹配。于是回溯回去,拿正则表达式第二个操作符 b{1,3}? 和字符串第三个字符 b 匹配,匹配成功。于是再拿正则表达式第三个操作符 c 与字符串第四个字符 c 匹配,匹配成功。于是结束。

如果在他们之后加多一个 + 符号,那么原先的贪婪模式就会变成独占模式,即尽可能多地匹配,但是不回溯。

server { listen 80 default_server; server_name _; return444; # 过滤其他域名的请求,返回444状态码 } server { listen 80; server_name www.abc.com; # www.abc.com域名 location / { proxy_pass http://localhost:8080; # 对应端口号8080 } } server { listen 80; server_name www.def.com; # www.def.com域名 location / { proxy_pass http://localhost:8081; # 对应端口号8081 } }

nginx+uwsgi+django是我们常用的django部署方式。nginx作为最前端的服务器,他负责接收所有的客户端请求,对于请求的静态文件,由nginx服务器自己完成,因为它具有很好处理静态文件的能力,性能进行过优化,支持高并发量;uWSGI服务器作为支持服务器,是用来服务nginx的,nginx将请求的动态文件交给uWSGI进行处理。uWSGI实现了uwsgi、wsgi和http协议,uwsgi协议是uWSGI自定义的协议,定义的是框架(django)和服务器对接的接口。

于是乎,如果要彻底解决问题,就要在保证功能的同时确保不发生回溯。我将上面校验 URL 的正则表达式的第二部分后面加多了个 + 号,即变成这样:

^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://) (([A-Za-z0-9-~]+).)++ --->>> (这里加了个+号) ([A-Za-z0-9-~\/])+$

这样之后,运行原有的程序就没有问题了。

例如我本文中存在问题的那个 URL 使用该网站检查后会提示:catastrophic backgracking(灾难性回溯)。

一个正则表达式怎么会引起线上CPU狂飙?

当你点击左下角的「regex debugger」时,它会告诉你一共经过多少步检查完毕,并且会将所有步骤都列出来,并标明发生回溯的位置。

nginx.conf 配置结构main全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。server块:配置虚拟主机的相关参数,一个http中可以有多个server。location块:配置请求的路由,以及各种页面的处理情况。

不同模块指令关系:server继承main;location继承server;upstream既不会继承指令也不会被继承,它有自己的特殊指令,不需要在其他地方的应用。

一个正则表达式怎么会引起线上CPU狂飙?

本文中的这个正则表达式在进行了 11 万步尝试之后,自动停止了。这说明这个正则表达式确实存在问题,需要改进。

但是当我用我们修改过的正则表达式进行测试,即下面这个正则表达式。

#全局块 events { #events块 } http #http块 { #http全局块 server #server块 { #server全局块 location [PATTERN] #location块 { } location [PATTERN] { } } server { } #http全局块 }Nginx.conf详细配置

上面nginx的配置初入门的可能还不太明白什么意思,下面提供给大家详细的配置信息。

#配置用户或者组,默认为nobody nobody。 #user administrator administrators; #允许生成的进程数,默认为1 #worker_processes 2; #指定nginx进程运行文件存放地址 #pid /nginx/pid/nginx.pid; #制定错误日志路径,级别。这个设置可以放入全局块,http块,server块,级别依次为:debug|info|notice|warn|error|crit|alert|emerg error_log log/error.log debug; #工作模式及连接数上限 events { #设置网路连接序列化,防止惊群现象发生,默认为on accept_mutex on; #设置一个进程是否同时接受多个网络连接,默认为off multi_accept on; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport #use epoll; #单个work进程允许的最大连接数,默认为512 worker_connections 1024; } #http服务器 http { #文件扩展名与文件类型映射表。设定mime类型(邮件支持类型),类型由mime.types文件定义 #include /usr/local/etc/nginx/conf/mime.types; include mime.types; #默认文件类型,默认为text/plain default_type application/octet-stream; #取消服务访问日志 #access_log off; #自定义日志格式 log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #设置访问日志路径和格式。"log/"该路径为nginx日志的相对路径,mac下是/usr/local/var/log/。combined为日志格式的默认值 access_log log/access.log myFormat; rewrite_log on; #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。(sendfile系统调用不需要将数据拷贝或者映射到应用程序地址空间中去) sendfile on; #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。 sendfile_max_chunk 100k; #连接超时时间,默认为75s,可以在http,server,location块。 keepalive_timeout 65; #gzip压缩开关 #gzip on; tcp_nodelay on; #设定实际的服务器列表 upstream mysvr1 { server 127.0.0.1:7878; server 192.168.10.121:3333 backup; #热备(其它所有的非backup机器down或者忙的时候,请求backup机器)) } upstream mysvr2 #weigth参数表示权值,权值越高被分配到的几率越大 server 192.168.1.11:80 weight=5; server 192.168.1.12:80 weight=1; server 192.168.1.13:80 weight=6; } upstream https-svr { #每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题 ip_hash; server 192.168.1.11:90; server 192.168.1.12:90; } #error_page 404 https://www.baidu.com; #错误页 #HTTP服务器 # 静态资源一般放在nginx所在主机 server { listen 80; #监听HTTP端口 server_name 127.0.0.1; #监听地址 keepalive_requests 120; #单连接请求上限次数 set $doc_root_dir "/Users/doing/IdeaProjects/edu-front-2.0"; #设置server里全局变量 #index index.html; #定义首页索引文件的名称 location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。 root $doc_root_dir; #静态资源根目录 proxy_pass http://mysvr1; #请求转向“mysvr1”定义的服务器列表 #deny 127.0.0.1; #拒绝的ip #allow 172.18.5.54; #允许的ip } } #http server { listen 80; server_name www.helloworld.com; #监听基于域名的虚拟主机。可有多个,可以使用正则表达式和通配符 charset utf-8; #编码格式 set $static_root_dir "/Users/doing/static"; location /app1 { #反向代理的路径(和upstream绑定),location后面设置映射的路径 proxy_pass http://zp_server1; } location /app2 { proxy_pass http://zp_server2; } location ~ ^/(images|javascript|js|css|flash|media|static)/ { #静态文件,nginx自己处理 root $static_root_dir; expires 30d; #静态资源过时间30天 } location ~ /\.ht { #禁止访问 .htxxx 文件 deny all; } location = /do_not_delete.html { #直接简单粗暴的返回状态码及内容文本 return 200 "hello."; } # 指定某些路径使用https访问(使用正则表达式匹配路径+重写uri路径) location ~* /http* { #路径匹配规则:如localhost/http、localhost/httpsss等等 #rewrite只能对域名后边的除去传递的参数外的字符串起作用,例如www.c.com/proxy/html/api/msg?method=1¶=2只能对/proxy/html/api/msg重写。 #rewrite 规则 定向路径 重写类型; #rewrite后面的参数是一个简单的正则。$1代表正则中的第一个()。 #$host是nginx内置全局变量,代表请求的主机名 #重写规则permanent表示返回301永久重定向 rewrite ^/(.*)$ https://$host/$1 permanent; } #错误处理页面(可选择性配置) #error_page 404 /404.html; #error_page 500 502 503 504 /50x.html; #以下是一些反向代理的配置(可选择性配置) #proxy_redirect off; #proxy_set_header Host $host; #proxy_set_header用于设置发送到后端服务器的request的请求头 #proxy_set_header X-Real-IP $remote_addr; #proxy_set_header X-Forwarded-For $remote_addr; #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP #proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时) #proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时) #proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时) #proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小 #proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32

^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)++([A-Za-z0-9-~\/])+$ 工具提示只用了 58 步就完成了检查。 一个正则表达式怎么会引起线上CPU狂飙?

一个字符的差别,性能就差距了好几万倍。

# 树义有话说

一个小小的正则表达式竟然能够把 CPU 拖垮,也是很神奇了。这也给平时写程序的我们一个警醒,遇到正则表达式的时候要注意贪婪模式和回溯问题,否则我们每写的一个表达式都是一个雷。

虽然把这篇文章写完了,但是关于 NFA 自动机的原理方面,特别是关于懒惰模式、独占模式的解释方面还是没有解释得足够深入。因为 NFA 自动机确实不是那么容易理解,所以在这方面还需要不断学习加强。欢迎有懂行的朋友来学习交流,互相促进

阅读全文
id_1广告位-300*300
相关推荐

写出域名解析的过程和具体步骤申请域名的流程?

写出域名解析的过程和具体步骤申请域名的流程?
域名分为国际域名和国内域名。国内域名需要实名制审核,具体流程如下:1、国际域名:...

这些免费DNS域名解析服务你们知道吗?稳定、可靠从DoH到ODoH,运营商再也不能搞DNS劫持了

这些免费DNS域名解析服务你们知道吗?稳定、可靠从DoH到ODoH,运营商再也不能搞DNS劫持了
DNS,即Domain Name System,中文为域名解析系统,平时我们可能...

域名解析中的cname和url转发有什么区别二级域名和URL转发的区别

域名解析中的cname和url转发有什么区别二级域名和URL转发的区别
a (address) 记录是用来指定主机名(或域名)对应的ip地址记录。用户可...

让我来帮你轻松搞定那些又臭又长的网页地址短网址系统(又名短链接系统)

让我来帮你轻松搞定那些又臭又长的网页地址短网址系统(又名短链接系统)
上网的时候我们总要与各种各样形式的网页链接打交道。那些很难记住的链接,特别是非常...

短链接/短网址缩短服务通常运用在哪些场景?又有什么样的作用?利用AdFly网址缩短服务跳转率分享赚美元方法分析操作

短链接/短网址缩短服务通常运用在哪些场景?又有什么样的作用?利用AdFly网址缩短服务跳转率分享赚美元方法分析操作
短链接特点简短、易记、易推广同时可以统计跟踪用户分析,让你的推广变得简单有效。在...

尼康以6800美金高价购买“尼康.世界”中文域名(转载)浅解姓氏域名的重要性,中小企业必看!

尼康以6800美金高价购买“尼康.世界”中文域名(转载)浅解姓氏域名的重要性,中小企业必看!
Sedo上周出售域名价值100万美元,其中包括了一些值得注意的新顶级域名。  新...

怎么缩短一个网址的链接?如何把这个网址简缩一下!不要二级域名的!急需!!!

怎么缩短一个网址的链接?如何把这个网址简缩一下!不要二级域名的!急需!!!
http://store.taobao.com淘宝首页http://store....

com.cn / .cn / .net的同名域名哪个主推比较好?快捷指令高级用法?

com.cn / .cn / .net的同名域名哪个主推比较好?快捷指令高级用法?
网站原本的网址是ip地址,例如www.wikipedia.org是一个域名,他的...

如何使用ScrapeBox查找过期域名几种域名whois查询的方法及平台介绍

如何使用ScrapeBox查找过期域名几种域名whois查询的方法及平台介绍
过期域名是SEO 项目中的一个宝贵资源,很多在做SEO项目的人都在挖掘它。域名注...

域名要过期多久之后才开放注册[网络天地]方便快捷查询网站域名Alexa和whios信息的捷径

域名要过期多久之后才开放注册[网络天地]方便快捷查询网站域名Alexa和whios信息的捷径
 所有的域名都会有一定的注册时间,最长的一半是10年,最短也要1年起注册。所以只...