关于开发中负载均衡(代理)的一些笔记
- 负载这一块的知识有些乱, 听人家常说软负载、硬负载,四层负载,七层负载、客户端负载,服务端负载之类的,所以梳理一下。
- 负载均衡在系统架构中是一个非常重要,通过负载均衡可以提高系统的高可用,缓解网络、硬件资源的限制。
- 博文主要涉及一些项目中常用的负载方式,很浅,不涉及负载算法啥的,做负载离不来代理,所以文中提到代理服务器即负载服务器。
-
这里梳理的方式从 Dev和Ops的概念出发。这里简单分类一下:
-
软负载
-
客户端负载
- Spring Cloud Ribbon
-
服务端负载
- Ngixn (4-7)层负载
- Hyproxy (4-7)层负载
- LVS (4)层负载
- kube-proxy (4-7)层负载
-
-
硬负载
- F5
-
关于 LVS和kube-proxy、F5我们这里之后在和小伙伴分享,F5没有接触过,LVS的demo容器的方式一直没有成功,kube-proxy这一块我还没学到,只是简单的了解.
如果能深刻理解苦难,苦难就会给人带来崇高感 。 ——路遥
一、软负载
处理传输层到应用层的数据,为了能通一个URL将前端的访问分发到后台的多个服务器上
1、客户端负载
Dev 即开发角度的负载均衡。开发中的负载均衡一般是在微服务中涉及。服务提供方一般以多实例的形式提供服务,负载均衡功能能够让服务调用方连接到合适的服务节点。 并且,服务节点选择的过程对服务调用方来说是透明的。
所以这里理解为是客户端的负载均衡,是相对服务端负载均衡而言。
客户端负载均衡来讲,就是调用的客户端本身是知道所有服务信息,当需要调用服务上的接口的时候,客户端从自身所维护的服务列表中,根据提前配置好的负载均衡策略,自己挑选一个服务来调用,此时,客户端知道它所调用的是哪一个服务.
在 Spring Cloud 中使用在RestTemplate进行服务调用,要想使用负载均衡功能,需要使用Spring Cloud Ribbon。
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Nettlix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模板请求自动转换成客户端负载均衡的服务调用。
使用时需要给RestTemplate实例上添加一个@LoadBalanced注解即可,此时, RestTemplate就会自动具备负载均衡功能,这个负载均衡就是客户端负载均衡。
package com.liruilong.consulcon; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient public class ConsulConApplication { public static void main(String[] args) {
SpringApplication.run(ConsulConApplication.class, args);
} @Bean @LoadBalanced RestTemplate restTemplate(){ return new RestTemplate();
}
}
二、服务端负载
Ops 即运维角度的负载均衡,这里的负载我们也称为服务端负载
所谓服务端负载均衡,比如传统的Nginx的方式,调用的客户端并不知道具体是哪个服务提供的服务,它也不关心,反正请求发送给Nginx, 或者hyproxy作为代理的服务器,然后 Ngixn 在请求负载任意服务,客户端只需要记着Nginx的地址即可。
1、Nginx负载
七层(应用层)负载
Nginx 7层负载是最常见的一种负载,所谓7层负载,即应用层负载,即基于应用层协议(TELNET,SSH,HTTP,SMTP,POP...)做的代理,7层负载需要解析数据包的具体内容,需要消耗额外的cpu,然后根据具体内容(url, 参数, cookie, 请求头)匹配相应的路径,然后转发到相应的服务器。转发的过程是:建立和目标机器的连接,然后转发请求,收到响应数据在转发给请求客户端。
使用docker构建一个内部网络
┌──[root@liruilongs.github.io]-[~] └─$ docker network create --subnet 10.1.1.1/24 load_balancing 0e0cdf9c70b038f9bcd44fd282ddc3e5bff77403ca28ce5b9006c20793ae2f8d
内网里运行两个httpd服务
10.1.1.22
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker run -itd --name=web1 --net=load_balancing -p 80 -h web1 --ip 10.1.1.22 httpd
ccaa091f295d40c61e50f103e9d84b86caddf9f98d6e5075de3690d93ab48f70
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ echo 10.1.1.22 >index.html;cat index.html
10.1.1.22
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker cp ./index.html web1:/usr/local/apache2/htdocs/
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ccaa091f295d httpd "httpd-foreground" 29 seconds ago Up 28 seconds 0.0.0.0:49153->80/tcp, :::49153->80/tcp web1
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ curl 127.0.0.1:49153
10.1.1.22
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$
10.1.1.33
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker run -itd --name=web2 --net=load_balancing -p 80 -h web2 --ip 10.1.1.33 httpd
5b08d54cf4983f6f6ce69cc0cee4b2eab2684cfde8deee89796196760924e434
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ echo 10.1.1.33 >index.html;cat index.html
10.1.1.33
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker cp ./index.html web2:/usr/local/apache2/htdocs/
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5b08d54cf498 httpd "httpd-foreground" 40 seconds ago Up 38 seconds 0.0.0.0:49154->80/tcp, :::49154->80/tcp web2
ccaa091f295d httpd "httpd-foreground" 6 minutes ago Up 6 minutes 0.0.0.0:49153->80/tcp, :::49153->80/tcp web1
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ curl 127.0.0.1:49154
10.1.1.33
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$
Ngixn实现到上面两个httpd服务的负载
ng配置文件 |
---|
![]() |
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ cat nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid; #daemon off; events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$upstream_addr - $remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ';
access_log /var/log/nginx/nginx_access.log main;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
server {
listen 8099;
server_name localhost;
root /var/www/html/;
index index.html index.htm;
access_log /var/log/nginx/default_access.log main;
error_log /var/log/nginx/default_error.log;
location / {
proxy_pass http://backend;
}
location ~ .* {
proxy_pass http://backend;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream backend {
server web2:80;
server web1:80;
}
}
运行Nginx容器
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker run -itd -p 8099:8099 --name=nginx --network=load_balancing -v $PWD/nginx.conf:/etc/nginx/nginx.conf nginx
0af20ed5c390e81398037a498fc7d385cac96cd2f403a8b08f6f4e09d7a20ee0
测试一下
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0af20ed5c390 nginx "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 80/tcp, 0.0.0.0:8099->8099/tcp, :::8099->8099/tcp nginx
b16bcb89e0a8 httpd "httpd-foreground" 32 minutes ago Up 32 minutes 0.0.0.0:49155->80/tcp, :::49155->80/tcp web1
5b08d54cf498 httpd "httpd-foreground" 39 minutes ago Up 39 minutes 0.0.0.0:49154->80/tcp, :::49154->80/tcp web2
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ curl 127.0.0.1:8099
10.1.1.33
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ curl 127.0.0.1:8099
10.1.1.22
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$
四层(传输层)负载
所谓四层负载,即在传输层协议的基础上来做负载,基于TCP,UDP等协议,传输层的作用是确保数据被可靠的传输送到目标地址,能够让应用程序之间实现通信,所以彼此传递的是数据包,标识的只有IP+端口。不涉及具体的url其他结构解析。路径匹配等,不会涉及具体的应用层协议,所以理论上四层负载要比七成负载快。
nginx 四层代理是nginx1.9.0开始新增的功能,需要开启--with-stream模块,可以实现四层协议的转发、代理、负载等功能。
这里的话,我们还是用容器的方式。配置方式和七层主要是配置文件的区别
ng配置文件 |
---|
![]() |
└─$ cat nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
daemon off;
events {
worker_connections 1024;
} # 四层代理的方式 stream{
server {
listen 8088;
proxy_pass backend;
}
upstream backend {
server web1:80;
server web2:80;
}
}
http { # 这个是协议级别 include mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
gzip on;
server { #这个是服务器级别 listen 80;
server_name localhost;
location / { #这个是请求级别 root html;
index index.html index.htm;
}
}
}
启动4层负载的Nginx
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker run -itd -p 8088:8088 --name=nginx4 --network=load_balancing -v $PWD/nginx.conf:/etc/nginx/nginx.conf nginx nginx
7c342f86752c5fe494b5a142983503d82dd11ea54e2968da7172f2201d1c45ea
┌──[root@liruilongs.github.io]-[~/load_balancing]
└─$ docker logs nginx4
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: