Nginx基础知识点汇总

1. 技术背景
水平扩展的可用性都需要灵活的负载均衡解决方案才能得以保障,NGINX
提供了多种协议的负载均衡解决方案如:HTTP、TCP 和 UDP 负载均衡。

2. HTTP实例

  1. 问题:将用户请求分发到 2 台以上 HTTP 服务器。
    解决方案
    使用 NGINX 的 HTTP 模块,将请求分发到有 upstream 块级指令代理的 HTTP
    服务器集群,实现负载均衡:
upstream wlx{
	server 127.0.0.1:80 weight=1;
	server www.wlx.com:80 weight=2;
}
server {
	location / {
		proxy_pass http://wlx;
	}
}

3. HTTP 总结
HTTP 模块的 upstream 用于设置被代理的 HTTP 服务器实现负载均衡。模块
内定义一个目标服务器连接池,它可以是 UNIX 套接字、IP 地址、DNS 记录
或它们的混合使用配置
;此外 upstream 还可以通过 weight 参数配置,如何
分发请求到应用服务器。
所有 HTTP 服务器在 upstream 块级指令中由 server 指令配置完成。server
指令接收 UNIX 套接字、IP 地址或 FQDN(Fully Qualified Domain Name: 全限
定域名) 及一些可选参数。可选参数能够精细化控制请求分发。它们包括用于负
载均衡算法的 weight 参数;判断目标服务器是否可用,及如何判断服务器可用
性的 max_fails 指令和 fail_timeout 指令。NGINX Plus 版本提供了许多其他
方便的参数,比如服务器的连接限制、高级DNS解析控制,以及在服务器启动后
缓慢地连接到服务器的能力。
2. TCP实例
问题:将请求分发到 2 台以上 TCP 服务器
解决方案
在 NGINX 的 stream 模块内使用 upstream 块级指令实现多台 TCP 服务器负载
均衡:

stream {
	upstream mysql_read {
		server read1.example.com:3306 weight=5;
		server read2.example.com:3306;
		//backup 作为备用数据库服务器当负载请求分发失败时会被启用。
		server www.wlx.com:3306 backup;
	}
	server {
		listen 3306;
		proxy_pass mysql_read;
	}
}

3. TCP 总结
TCP 负载均衡在 stream 模块中配置实现。stream 模块类似于 http 模块。
配置时需要在 server 块中使用 listen 指令配置待监听端口或 IP 加端口。
接着,需要明确配置目标服务,目标服务可以使代理服务或 upstream 指令
所配置的连接池。 TCP 负载均衡实现中的 upstream 指令配置和 HTTP 负载
均衡实现中的 upstream 指令配置相似。TCP 服务器在 server 指令中配置,
格式同样为 UNIX 套接字、IP地址或 FQDN(Fully Qualified Domain Name:
全限定域名);用于精细化控制的 weight 权重参数、最大连接数、DNS 解析
器、判断服务是否可用和启用为备选服务的 backup 参数一样能在 TCP 负载
均衡中使用

负载均衡算法(Load-Balancing Methods)
对于负载压力不均匀的应用服务器或服务器连接池,**轮询(round-robin)**负载均衡算法
无法满足业务需求。使用 NGINX 提供的其它负载均衡算法,如:最少连接数(least connections)、最短响应时间(leaest time)、通用散列算法(generic hash)或 IP 散列算法(IP hash)

upstream backend {
	//最小连接数
	least_conn;
	server backend.example.com;
	server backend1.example.com;
}
upstream backend {
	//最短响应时间
	least_time;
	server backend.example.com;
	server backend1.example.com;
}
upstream backend {
	//通用散列算法
	has;
	server backend.example.com;
	server backend1.example.com;
}
upstream backend {
	/IP 散列
	ip_hash;
	server backend.example.com;
	server backend1.example.com;
}

实际落地
访问应用时,可能由于网络连接失败,Web 服务器宕机或应用程序异常等原因导致
应用程序无法访问。这时,代理或负载均衡器需要提供能够智能检测被代理或被负
载的 Web 服务是否无法访问的能力,来确保不会请求分发到这些失效的服务器。
同时,客户端会收到连接超时的响应,结束请求等待状态。
通过代理服务器向被代理服务器发送健康检测请求,来判断被代理服务器是否失效,是
一种减轻被代理服务器压力的有效方法。NGINX 服务器提供两种不同的健康检测案:
被动检测和主动检测,开源版的 NGINX 提供被动检测功能, NGINX PLUS 提供主动检
测功能。
主动检测的实现原理是:
NGINX 代理服务向被代理服务器定时的发送连接请求,如果被代理服务器正常响应,则说明被代理服务器正常运行。
被动检测的实现原理是:
NGINX 服务器通过检测客户端发送的请求及被代理(被负载均衡)服务器的响应结果进行
判断被代理服务器是否失效。
被动检测方案,可以有效降低被代理服务器的负载压力;
主动检测则能够在客户端发送请求之前,就能够剔除掉失效服务器。

问题
你想对服务器进行有效检测,但不止如何去检测服务器健康状况。
解决方案
使用一个简单粗暴的检测方案实现应用健康检测。如,负载均衡器通过获取被负载
服务器的响应状态码是否为 200 判断应用服务器进程是否正常。
结论
实际项目中,对被负载的提供核心功能的应用服务器进行健康检测非常重要。
仅仅通过一种健康检测方案,确保核心服务是否可用,通常并不完全可靠。
健康检测应该通过网络直接检测被负载的应用服务器和应用本身是否运行正常,
来确保服务可用,这比仅使用负载均衡器来检测服务是否可用要可靠。
一般,可以选择一个功能来进行健康检测,来确保整个服务是否可用。比如,
确认数据库连接是否正常或应用是否能够正常获取它的资源。任何一个服务失效,
都可能引发蝴蝶效应导致整个服务不可用。

问题
需要检测 TCP 服务器是否正常并从代理池中移除失效服务器。
解决方案
在 server 块级指令中 使用 health_check 简单指令,对被代理服务器进行
健康检测:

stream {
	server {
		listen 3306;
		proxy_pass read_backend;
		health_check interval=10 passes=2 fails=3;
	}
}

上面的配置会对代理池中的服务器进行主动监测。如果被代理服务器未能正常
响应 NGINX 服务器的 3 个以上 TCP 连接请求,则被认为是失效的服务。
之后,NGINX 服务器会每隔 10 秒进行一次健康检测。
结论
在 NGINX PLUS 版本中同时提供被动检测和主动检测功能。被动检测是通过加之于
客户端与被代理服务器的请求响应检测实现的。如果一个请求超时或者连接失败,
被动检测则认为该被代理服务器失效。主动检测则是通过明确的 NGINX 指令配置
来检测服务器是否失效。主动检测途径可以是一个测试的连接,也可以是一个预期
的响应。

问题
需要主动检测 HTTP 服务器健康状态
解决方案
在 location 块级指令中使用 health_check 指令检测:

http {
server {
...
location / {
	proxy_pass http://backend;
	health_check interval=2s
	fails=2
	passes=5
	uri=/
	match=welcome;
	}
}
// status is 200, content type is "text/html",
// and body contains "Welcome to nginx!"
match welcome {
	status 200;
	header Content-Type = text/html;
	body ~ "Welcome to nginx!";
	}
}

通过向被代理服务器每隔 2 秒,发送一个到 ‘/’ URI 的请求来检测
被代理服务器是否失效。被代理服务器连续接收 5 个请求,如果其中有 2 个
连续请求响应失败,将被视作服务器失效。被代理服务器的健康响应格式
在 match 块级指令中配置,规定响应状态码为 200, 响应 Content-Type类型为
‘text/html’,响应 body 为 “Welcome to nginx!” 字符串的响应为有效服务器。
结论
在 NGINX PLUS 版本中,除了通过响应状态码来判断被代理服务器是否有效。
还能够通过其它的一些响应指标来判断是否有效。如:主动检测的时间间隔
(频率),主动请求的 URI 地址,健康检测的请求次数及失败次数和预期响应
结果等。在 health_check 指令中的 match 参数指向 match 块级指令配置,
match 块级指令配置定义了标准的响应,包括 status、header 和 body 指令,
他们都有各自的检测标准。

介绍
通过对请求的响应结果进行缓存,能够为后续相同请求提供加速服务。对相同请求
响应内容进行内容缓存(Content Caching),相比每次请求都重新计算和查询被代理
服务器,能有效降低被代理服务器负载。内容缓存能提升服务性能,降低服务器负
载压力,同时意味着能够使用更少的资源提供更快的服务。可伸缩的缓存服务从架构
层面来讲,能够显著提升用户体验,因为响应内容经过更少的转发就能够发送给用户,
同时能提升服务器性能。

问题
需要定义响应内容的缓存路径及缓存操作
解决方案
使用 proxy_cache_path 指令为待缓存定义内容缓存区域的共享内存及缓存路径

proxy_cache_path /var/nginx/cache
		keys\_zone=CACHE:60m
		levels=1:2
		inactive=3h
		max\_size=20g;
proxy_cache CACHE;

上面的配置中在 proxy_cache_path 指令中为响应在文件系统中定义了缓存的存
储目录 /var/nginx/cache,并使用 keys_zone 参数创建名为 CACHE 的拥有
60 M 的缓存内存空间;同时通过 levels 参数定义目录解构级别,通过 inactive
参数指明如果相同请求的缓存在 3 小时内未被再次访问则被释放,并使用 max_size
定义了缓存最大可用存储空间为 20 G。
结论
要使用 NGINX 内容缓存,需要在配置中定义缓存目录及缓存区域(zone)。
通过 proxy_cache_path 指令创建 NGINX 内容缓存,定义用于缓存信息的路
径和用于存储缓存的元数据(metadata)和运行时键名(active keys)的共享内存。
其它的可选参数,还提供缓存如何维护和访问的控制,levels 参数定义如何
创建文件结构,定义子目录的文件名长度,语法是以冒号分隔的值,支持最大
3 级。
NGINX 的所有缓存依赖于最终被计算成散列的 cache key,接着将结果以
cache key 作为文件名,依据缓存级别创建缓存目录。
inactive 参数用于控制最后一次使用缓存选项的时间,超过这个时间的缓存
会被释放。缓存的大小则可以通过 max_size 参数进行配置。还有部分参数
作用于缓存加载进程中,功能是将 cache keys 从磁盘文件加载仅共享内存里。
Caching Hash Keys 配置缓存哈希键名
问题
自定义如何缓存和查找缓存内容
解决方案
通过一条单独的 proxy_cache_key 指令,以变量名的形式定义缓存命中和
丢弃的规则。

proxy_cache_key "$host$request_uri $cookie_user";

上例指令依据请求域名、请求 URI 和用户 cookie 作为缓存
键名,来构建 NGINX 的缓存页面。这样,就可以对动态页面进行缓存,而
无需对每个用户都进行缓存内容的生成处理。
结论
proxy_cache_key 默认设置是 “schemeschemeproxy_host $request_uri”。默认设置
适用于多数的使用场景。配置之中包括 scheme、HTTP 或 HTTPS、代理域名
(proxy_host)、请求的 URI 等变量。总之,它们能够正确处理 NGINX 代理请求。
您可能会发现,对于每个应用程序,有许多其他的因素可以定义一个惟一的请求,
比如请求参数、头文件、会话标识符等等,您需要创建自己的散列键。或许你
已经发现,对一个应用,还有其它的数据能够确定一个唯一的请求,比如请求参数、
请求头(headers)、会话标识(session identifiers) 等等,这些都可以用于
构建自己的散列键名。在构建时应基于应用程序的理解,创建选择一个好的散列
键名,这一点非常重要。比较简单的是为静态内容创建缓存键名,通常,可以直接
使用域名(hostname)和请求 URI 就可以了。而类似于仪表盘这类的,具有动态内
容的页面,则需要充分了解用户和应用之间的交互、以及用户体验之间的差异,来
构建缓存键名。如从安全的角度触发,你可能不希望缓存将一个用户的缓存数据展
示给另外的用户。proxy_cache_key 令配置了用于缓存生成哈希值字符,此条指令
可以在 HTTP、server、location 块级指令上下文中定义,实现对请求如何缓存的
灵活控制。
Cache Bypass 绕过缓存
问题
将一些内容不进行缓存
解决方案
将 proxy_cache_passby 指令,设置称非空值或非 0。一种途径是,在 location
块级指令中设置一个值等于 1 的 proxy_cache_passby 指令

proxy_cache_bypass $http_cache_bypass;

配置告知 NGINX 服务器,如果一个 HTTP cache_passby 请求头的值设置为非
0(或非空),则不对该请求进行缓存处理
结论
挺多应用场景下都不应对请求进行缓存处理,对此,NGINX 提供 proxy_cache_passby
指令来应对这些场景。通过将指令值设置为非空或非零,匹配的请求 URI 会直接发送给
被代理服务器,而不是从缓存中获取。如何使用该指令,需要结合客户端和应用的实际
使用。它既可以配制成如同一个请求变量一样简单,也可以配置成复杂的映射指令块。
但最终目的都是绕过缓存。其中,一个重要的应用场景就是排除故障和调试应用。如果
在研发过程中一直使用缓存,或对特定用户进行缓存,缓存会影响问题的复现。提供对指定
cookie、请求头(headers)或请求参数等的缓存绕过能力,则是一个必要的功能。此外,
NGINX 服务器还能够在 location 块指令中将 proxy_cache 指令设置为 off,完全禁用
缓存。

Cache Performance 缓存性能
问题
需要在客户端提升服务性能
解决方案
使用客户端缓存控制消息头

location ~* .(css|js)$ {
expires 1y;
add\_header Cache-Control "public";
}

该 location 块指令设置成功后,客户端可以对 CSS 和 JS 文件进行缓存。expires
指令将所有缓存的有效期设置为 1 年。add_header 指令将 HTTP 消息头 Cache-Control
设置成 public 并加入响应中,表示所有的缓存服务器都可以缓存资源。如果将它的值
设置为 private,则表示仅允许客户端对资源进行缓存。
结论
缓存的性能和许多因素有关,其中磁盘读写速度是影响缓存性能的重要原因之一。
在 NGINX 配置指令中,还有很多能够提升性能的指令。像上例中配置的,通过
设置 Cache-Control 响应消息头,客户端会直接从本地读取缓存,而不会将请求
发送给服务器来提升性能。

用户数据报协议(UDP) 在多种场景下运用,如 DNS、NTP 服务、IP语音(Voice
over IP)服务。NGINX 可以在 upstream 块级指令中使用所有的负载均衡算法
实现 UDP 的负载均衡,本章将学习 UDP 负载均衡相关配置。
未完待续·················

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章