nginx 简介
nginx 是一个高性能的 http 服务器,代码完全用C语言编写,能够支持高达50,000个并发连接数的响应。与其它 http 服务器相比,nginx 具有以下几个特性:
- nginx 可以在大部分 Linux OS 上编译运行,并且可以比较简单地在 Windows 上移植。
- nginx 可以提供很方便的反向代理功能。
- nginx 可以轻松完成负载均衡服务
由于业务需求,我学习 nginx 主要是希望将 nginx 作为反向代理服务器进行使用, 并希望它能提供负载均衡功能
nginx 在 Windows 中运行
为了方便尝试,目前准备简单地在 Windows 上配置使用即可,下载地址为 http://nginx.org/en/docs/windows.html 下载后解压,运行 nginx.exe 或者运行命令行,在解压目录中输入 start nginx 即可运行。
检查 nginx 进程可以使用 tasklist 指令:
tasklist /fi "imagename eq nginx.exe"
映像名称 PID 会话名 会话# 内存使用
========================= ======== ================ =========== ============
nginx.exe 6516 Console 1 444 K
nginx.exe 33104 Console 1 820 K
其中一个进程是 master 进程,另外一个是 worker 进程。
另外一些简单命令有:
nginx -s stop 快速停止nginx
nginx -s quit 优雅退出
nginx -s reload 如果改变配置文件,开启新的worker进程以运行新的配置
nginx -s reopen 重新打开log文件
nginx 使用
nginx 常用功能
- 代理服务器
- 负载均衡
- web 缓存
nginx 配置文件结构
./conf/nginx.conf
worker_processes 1; #全局块
events{ #events块
worker_connections 1024;
}
http #http块
{
include mime.types; #http全局块
default_type application/octet-stream;
keepalive_timeout 65;
server {
listen 80; #server全局块
server_name localhost;
location / { #location块
root html;
index index.html index.htm;
}
location [PATTERN]
{
...
}
}
server
{
...
}
}
配置文件参数的详解可以查看 http://tengine.taobao.org/book/chapter_02.html#id6
在 http://www.nginx.cn/doc/ 中也列出了几个配置文件的例子可以参考:
- 两个虚拟主机(纯静态-html 支持) - Two Virtual Hosts, Serving Static Files
http {
server {
listen 80;
server_name www.domain1.com;
access_log logs/domain1.access.log main;
location / {
index index.html;
root /var/www/domain1.com/htdocs;
}
}
server {
listen 80;
server_name www.domain2.com;
access_log logs/domain2.access.log main;
location / {
index index.html;
root /var/www/domain2.com/htdocs;
}
}
}
反向代理
原理+实践
反向代理概念
反向代理(Reverse Proxy)方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。当一个代理服务器能够代理外部网络上的主机,访问内部网络时,这种代理服务的方式称为反向代理服务。
可以看出,使用反向代理服务器的好处有:
- 代理服务器可以在安全数据库和可能共计的恶意节点中提供一道屏障,提高系统安全性
- 可以将用户请求的 http 服务重定向为 https , 提高用户安全性
- 使得负载均衡功能可以方便应用
反向代理服务器配置
较为基本的反向代理服务器配置相对简单,主要是运用 HttpProxy 模块,下面给出一份基础模板可以参考:
#设定负载均衡的服务器列表
#weigth参数表示权值,权值越高被分配到的几率越大
upstream test{
server ip0:8080 weight=1;
server ip1:8080 weight=1;
}
server {
#侦听的80端口
listen 80;
server_name localhost;
location / {
index index.html;
proxy_pass http://test; #设置代理
#以下是一些反向代理的配置可删除
proxy_redirect off;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 150;
proxy_read_timeout 150;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}
反向代理动态服务发现:
了解了反向代理配置后,仍然是无法成功运用在目标系统中,因为目标系统要求服务具有伸缩性,即可以动态增加服务内容,或者增加服务器。因此需要代理服务器也能动态发现服务。
使用etcd+confd管理nginx配置 则是一个可行的尝试, 利用etcd动态发现服务,然后用confd监听etcd的变化,从而改变配置文件。
生成配置的方式为:
通过API将配置写入etcd,confd注册监控etcd的key为/nginx/,只要发生变化就通知 confd 根据模板生成配置。confd 默认的配置路径为 /etc/confd/,创建 conf.d 和 template 两个目录,分别存放配置资源和配置模板。
confd 的安装地址为 https://github.com/kelseyhightower/confd, 看了一下也包含了对 Windows 系统的支持, 但是做的比较粗糙,在 Windows系统中查找配置文件仍然是从 /etc/confd 中寻找:WARNING Cannot load template resources: confdir '/etc/confd' does not exist
, 因此还是建议在 Linux 系统下运行。
nginx 的配置模板需要动态写入,因此需要修改(这里只讨论增减服务器):
upstream www_{{getv "/nginx/https/www/server/server_name"}} {
{{range getvs "/nginx/https/www/upstream/*"}}server {{.}};{{end}}
}
server {
server_name {{getv "/nginx/https/www/server/server_name"}}:443;
location / {
proxy_pass http://www_{{getv "/nginx/https/www/server/server_name"}};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}
}
但是目前仍然有问题,就是配置文件生成之后,如何能够动态加载,加载方式有如下几种:
- dns动态解析:改变dns配置
- 动态模板解析: 使用jinja2、mako的模板引擎,动态的根据你提供变量渲染配置
- 服务发现模式:
- 前面2个都有比较大的限制,并且需要reload的话,nginx新老配置交替的时候会掉15%左右的qps, 因此频繁reload方式并不建议,服务发现模式有些时候可以不按照reload方式进行:
在github中的不少nginx服务发现的实现,他们不会新开进程,而是在在master进程中注册一个定时器,该事件会触发watch,当发现version的版本号发生变更时,就知道主机列表发生了变化,进而重载配置. 那么如何让worker进程也使用新的配置? 这时候可能不会使用共享变量,因为读写都要加锁,及其影响速度. 所以每个worker都会缓存一份location upstream的配置,每个worker也会有个定时器,他的事件共享内存的upstream有无变化…
-
可以基于 Redis 动态路由: 第一次请求时,从 Redis 获取路由地址,放入本地缓存中,并设置有效时间,后续请求直接从本地缓存中获取,如果本地缓存失效,则从 Redis 中请求。
但没有考虑 redis 数据与本地缓存数据不一致问题。
而且不管如何动态更新,一个关键问题是,nginx 的最小单位是 IP 地址 + 端口, 而目标系统的最小单位是服务。因此相对难以应用。但本次探索不失为一个有价值的尝试。