因为涉及到从单机->集群的架构改进case, 所以需要借用nginx的大腿抱一下。
upstream定义负载均衡子服务地址列表
nginx支持负载均衡的关键语法是在nginx.conf中加入:
upstream xxx.某域名.com { ip_hash; # 这里业务中采用ip哈希的方式 server 192.168.xxx.xxx:8081 weight=10; server 192.168.xxx.xxx:8081 weight=10; server 192.168.xxx.xxx:8081 weight=10; server 192.168.xxx.xxx:7907 weight:20; server 192.168.xxx.xxx:7908 weight:20; server 192.168.xxx.xxx:7909 weight:20; server 192.168.xxx.xxx:9001 down; # 配置更多子服务 }
本案例是以权重+ip哈希的方式来做的。权重值越高, 受到的访问压力越大。
其中server段, 你可以预留一些已经down掉的server做预留, 例如
server xxx.xxx.xxx.xxx:xx down;
以上代码是告诉nginx, 当前节点确实有,但先暂时别跳过去, 给哥留着。
好了,加入完上述语法还是远远不够的。除非你的项目是异地多活的大号项目, 一般server后面跟着的都是内网地址, 你需要先ping一下这些内网服务器, 确认它们能不能搞得通。
另外,在本案例中,还需要加入一些虚拟网站配置文件。我们在nginx的conf目录下方新建一个vhosts文件夹, 在文件夹内又创建了一个xxx.某域名.com.conf, 为了能够完美使这个配置文件生效, 我们在nginx的http { }配置块的尾部加入了一句代码来引入所有该目录下的.conf文件:
http { # 一堆代码... include vhosts/*.conf; }
接下来编写xxx.某域名.com.conf
反向代理配置
代码中加入了一些SSL证书的引入和安全有关的配置, 顺便也加进去, 供您参考:
server { listen 80; listen 443 ssl; server_name www.某域名.com; # limit_conn one 10; # 防止一个ip暴力连接本实例用 # 如果你启用了这个语句, 你需要定义变量one, 可以在nginx.conf当中, 通过limit_conn_zone语法用这个语句来定义 # limit_conn_zone $binary_remote_addr zone=one:10m; client_max_body_size 8m; # 防止无聊的大post包 ssl_certificate ssl/www.某域名.pem; #将domain name.pem替换成您证书的文件名。 ssl_certificate_key ssl/www.某域名.com.key; #将domain name.key替换成您证书的密钥文件名。 ssl_session_timeout 5m; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; #使用此加密套件。 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #使用该协议进行配置。 ssl_prefer_server_ciphers on; location / { root html; index index.html; proxy_pass http://$host; proxy_http_version 1.1; proxy_set_header HOST $http_host; proxy_set_header X-FORWARDED-FOR $proxy_add_x_forwarded_for; proxy_connect_timeout 1s; } }
实际就是利用location / { ... }当中的proxy_pass语句来做反向代理。
这里SSL证书被放到了nginx/conf/ssl/下边。
接下来会有关于SSL证书的疑问了, 内网的子服务器是否需要绑定SSL证书呢? 如果你有瘾,想让内网彼此通信更安全, 或者你项目的节点涉及到了公网, 那么你可以去搞搞, 笔者的项目直接在负载均衡服务器顶层绑定了SSL证书, 其内部都是随便找个自定义端口+http协议直接互联的。如果你要问nginx的虚拟子网站(vhost)如何配置自定义端口? 答案是listen这个语句, 例如:
listen 8081;
就可以了。
负载均衡场景下的客户端IP透传
新接触nginx多层代理的业务场景, 如果获取客户端真实IP的问题没有解决, 会影响您项目的正常运转。代理中间件被正确配置前, 只会获取到中间件父节点的内网网卡ip。这里就要用到的上文当中的语句:
proxy_set_header X-FORWARDED-FOR $proxy_add_x_forwarded_for;
子服务器的虚拟主机(vhost)配置里也要使用同样的语句来以参数的形式逐层传递这个代理ip地址。
这个参数最后落到哪里了呢?就笔者比较熟悉的nginx+php架构来说, 此时因nginx内置的fastcgi配置所影响, php全局环境变量:
$_SERVER['HTTP_X_FORWARD_FOR']
会接住多层中间件一步一步地传播过来的参数。
其他架构请自行通过打印环境变量来判断。接下来说说服务器。
子服务器/服务配置
和创建一个普通的网站一样。像笔者这样的案例,除了负载均衡本身需要对外监听请求,其余都是内网通讯,你可以在子服务器把公网访问直接关了。这个case中, 没必要在子服务器中重复配置ssl证书和gzip, 内网通讯限制就没那么多,节省一些计算方面的资源开销。让提供服务支持的nginx/tengine/tomcat监听负载均衡服务列表中指定的端口即可,避免监听一些不必要的端口。
后话: 什么时候要用到负载均衡?
这一段说的都是废话, 和技术无关,您完全可以不看。
1 假如你的瓷器活人人都能干, 那你的职场生意将朝不保夕。
如果这件事情是你自己发起的,你一定是来学习的,想想未来君若要因学会此技术年薪百万,那岂不是妙哉?
若很“不幸地”遇到了一个很狗的上司或者滥用技术的老板, 未必是一件坏事, 也不要恶意揣摩人家。负载均衡技术, 并不是废技术, 相反, 它在各种应用场合下都有奇效。人家也是为了让妻儿老小过得开心一点, 如果这个活派给你,是给你历练的机会,善哉善哉。一个复杂的系统背后,有那么一点可能是一些职场方面的原因,随着厂子越来越大,系统的复杂性,也侧面保护了许多程序员/架构师的饭碗。俗话说的好:有人的地方,就有江湖。人越多的地方,划水的王八也越多。
2 当初用了一台傻大的单机服务器顶住了所有的压力, 想让项目灵动起来, 化整为零
只要你能忍受它所带来的后期维护的复杂程度,一般来说它也是正确解决思路,你做到真正为你老板负责了(如果你就是老板,恭喜你,你是个nb的老板)。
一台高配服务器,投入的成本可能很高,不妨用多台小宝贝服务器和一台lvs/nginx ingress/本案例的nginx SLB承压。而简单配置一台nginx SLB,可以极低的计算成本解决计算模型与分发路由模型绑架在一起的所产生的不稳定痛点。
——自从上了SLB, 贵公司实现了农村包围城市的战略构想。
3 仇家找上门, DDOS等安全问题
遭受了各种奇形怪状的DDOS攻击后, 痛下决心要做个负载均衡, 想用前置专有路由的方式结合WAP防护特性来清洗流量。
4 被各路推送新技术的大佬道德绑架, 强行上车
如果人人都学了葵花宝典和辟邪剑谱, 你偏不学。万一公司哪天不行了/你站错队了, 你拿什么过冬?
5 发现php/node.js也可以借助nginx发力, 像某java一样玩灵活套路
nginx开发团队已经针对可能的市场需求,对各路产品挂载了这样的能力。例如应付kubernetes出的nginx ingress controller, 这些年已经发育的很好,可以投入生产级别。许多程序员大佬, 为了公司的钱景, 闷头写代码写了许多年,真没太想往运维方向瞧一瞧。
6 加入区块链大军
区块链的天生体质良好, 自带相当强大的耐受性。本文的玩法是面向请求web/app应用压力分解和提高稳定性的需求场景,不适用于区块链场景。然而,区块链技术是否需要负载均衡呢?答案是肯定的。
或许因为某些人急着要申请个人发明专利,所以一定要“发明”一套如何让区块链实现负载均衡的理论。香蕉可以装进篮子里, 这回换成了白菜, 他说他发明了白菜可以装进篮子里的技术。近期的区块链“名企海龟”纷纷涌入国内,和一些海外的洋老板打着技术的旗号想发行虚拟货币,再到国人钱包里大肆洗劫。若干行开源免费的github代码到了这些人手里, 复制粘贴改一改算法,成了欺诈捣鬼、个人技术包装的利器。