> Author:songxiankun2008@126.com
RJ45:橙白 橙 白绿 蓝 蓝白 绿 棕白 棕
### Nginx
##### 1. 负载均衡高可用
---
###### 1. 单机Tomcat
- 优点:开发简单 部署简单
- 缺点:单点故障 出错不可访问
- 容量:一般200-300;经过优化后可能达到 500/s
- 巨容易出错,且没救
###### 2. 多个Tomcat:
- 优点:轮训算法 能够排除单点故障 并且容量提升
- 缺点:应用服务器 全部暴露在外网 入口不集中 不安全 并且ip地址是由域名服务商提供的,总会有一半的用户会请求到坏的那个ip地址里面的服务器里面去
- 容易出错,部分用户有救
###### 3. 请求分发/负载均衡 (多个Tomcat之上)
- 优点:
- 一个ip地址进来后再进行分配到不同的服务器(对外网只暴露了接口,没有暴露应用服务器,由内网来分配)
- 负载均衡典型算法 轮询 随机
- 同样的大容量
- 缺点:
- "请求分发/负载均衡"这个设备或者服务器出问题,那么就是单点故障;不会分配到任何一个服务器
- 还不如上面第2点还有救
- 不容易出错,但是出错就没救
###### 4. IP回传、多个请求分发的服务器(==双机热备==)要经过“存活检测”(基于多Tomcat)
双机热备:特指基于高可用系统中的两台服务器的热备。双机高可用按工作中的切换方式分为:主-备方式(Active-Standby方式)和双主机方式(Active-Active方式);
主-备方式即指的是一台服务器处于某种业务的激活状态(即Active状态),另一台服务器处于该业务的备用状态(即Standby状态)。
而双主机方式即指两种不同业务分别在两台服务器上互为主备状态(即Active-Standby和Standby-Active状态)。
- 优点:同一时刻 只有一个在服务,可能每一个几秒(自定义时间间隔)都会存活检测去检测服务器是否正常运行,如果服务器挂点,存活检测就会修改ip地址让用户请求到另外一个正常的服务器上
- 缺点:
- 利用率低;只利用了50%,另外一个正常服务器处于空闲状态没有被利用即50%空闲且不能关闭这个空闲的服务器
- 请求分发设备 也有流量并发上限 eg:100W 瓶颈
###### 5. 双机热备 + DNS轮训 (基于多Tomcat)
在域名服务商有多个IP地址,用户通过不同的IP地址进来后会分配到不同的“请求分发/负载均衡 心跳检测”服务区中(即分配到不同的“双机热备”上),每一套不同的" 请求分发/负载均衡 存活检测"又进行轮训或者随机算法到不同的Tomcat服务器上
保守估计 一天几万,一个月几百万的访问量;具体看服务看实际架构
##### 2. 常见负载均衡设备优缺点 - Tomcat压力测试
---
负载均衡:
- 硬件实现:
- 常用设备 F5 会分发到这个F5的ip上面
- 1. 优点:非常快 可靠性高 并发量大
- 2. 缺点:太贵 成本高 不方便
- 软件实现:
- 常用①:Linux中的LVS 基于Linux系统IP层面的负载均衡
- 1. 优点:可靠性非常高 简单易用 并发量大
- 2. 缺点:将动态和静态文件都负载在Tomcat上不能实现动静分离
- 常用②:Nginx
- 1. 优点:是个软件,不是硬件,也不是像LVS这样基于Linux的小系统;Nginx是个软件,==可以将静态资源和动态资源放在Nginx里面不同的目录里面;如果访问中有静态资源,那么静态资源不会经常Tomcat就直接返回到浏览器,而动态资源等需要请求数据库的才通过Tomcat服务器进入到数据库里面再把值带出来==;这样相当于前几者都大大降低了服务器的压力且提高了静态资源的访问速度
- 常用③: Apache Http-Server
- 1. 优点:跟Nginx差不多
- 2. 缺点:效率比Nginx低很多
正向代理: 用户将自己的ip隐藏;
反向代理: 服务器将自己的ip给隐藏了
常用压力测试软件: jmeter
##### 3. Nginx负载均衡实战-常见负载均衡算法解析
---
配置: nginx-1.12.2\conf\nginx.conf
#upstream关键字表示上游服务器真正的应用服务器配置
#test-service 表示这个配置的名称
upstream test-service { #服务器集群名字,此处叫做test-service
server localhost:8090; #服务器配置
server localhost:8080;
}
//上面这三行是需要添加的
server {
#表示监听本机端口80
listen 80;
#服务器名称
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
#此处的"/" 表示localhost下的所有请求
location / {
root html;
index index.html index.htm;
#请求转发,此处的路径就是上面配置的名称
proxy_pass http://test-service;
//上面这一行是需要添加的
}
#error_page 404 /404.html;
启动:
- nginx.exe -> localhost:80
- 启动localhost:8080 和 localhost:8090 两个Tocmat
- [x] 此时打开localhost:80;就会经过默认的“轮询”算法轮到这两个Tocmat启动的项目中去,可能上一秒是8080的项目下秒就是8090的项目
###### 算法解析:
public class IpMap {
/**
* 待路由的Ip列表,Key代表Ip,Value代表该Ip的权重
*/
public static HashMap<String,Integer> serverWeigetMap = new HashMap<String, Integer>();
static {
serverWeigetMap.put("192.168.1.100", 2);
serverWeigetMap.put("192.168.1.101", 3);
serverWeigetMap.put("192.168.1.102", 1);
serverWeigetMap.put("192.168.1.103", 2);
serverWeigetMap.put("192.168.1.104", 1);
}
}
轮询算法 RoundRobin
public class RoundRobin {
/**
* 轮询算法
*/
private static Integer pos = 0;
public static String getServer() {
//重建一个Map,避免服务器的上下限导致的并发问题
Map<String, Integer> serverMap = new HashMap<String, Integer>();
serverMap.putAll(IpMap.serverWeigetMap);
//取得Ip地址List
Set keySet = serverMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();
keyList.addAll(keySet);
String server = null;
synchronized (pos) {
if (pos > keySet.size()) {
pos = 0;
}
server = keyList.get(pos);
pos++;
}
return null;
}
}
随机算法 RandomArithmetic
public class RandomArithmetic {
public static String getServer() {
//重建一个Map,避免服务器的上下限导致的并发问题
Map<String, Integer> serverMap = new HashMap<String, Integer>();
serverMap.putAll(IpMap.serverWeigetMap);
//取得Ip地址List
Set keySet = serverMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();
keyList.addAll(keySet);
Random random = new Random();
int randomPos = random.nextInt(keyList.size());
return keyList.get(randomPos);
}
}
源地址哈希 Hash
- 最后的那几行代码很重要;
- 不同于上面的“随机”和“轮询”;
- 这种算法 每次都会着陆于同一台Tomcat上
public class Hash {
public static String getServer() {
//重建一个Map,避免服务器的上下限导致的并发问题
Map<String, Integer> serverMap = new HashMap<String, Integer>();
serverMap.putAll(IpMap.serverWeigetMap);
//取得Ip地址List
Set keySet = serverMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();
keyList.addAll(keySet);
// 在web应用中可通过HttpServer的getRemoteIp方法获取
String remoteIp = "127.0.0.1";
int HashCode = remoteIp.hashCode();
int severListSize = keyList.size();
int serverPos = HashCode % severListSize;
return keyList.get(serverPos);
}
}
加权轮询
- 增加权利,同时增加责任;加大被分配上的几率
- 应用场景:比如一个内存4G,一个内存16G;那么就需要加权到16G的机器上
public class WeightRoundRobin {
private static Integer pos;
public static String getServer() {
//重建一个Map,避免服务器的上下限导致的并发问题
Map<String, Integer> serverMap = new HashMap<String, Integer>();
serverMap.putAll(IpMap.serverWeigetMap);
//取得Ip地址List
Set<String> keySet = serverMap.keySet();
Iterator<String> iterator = keySet.iterator();
List<String> serverList = new ArrayList<String>();
while (iterator.hasNext()) {
String server = iterator.next();
int weight = serverMap.get(server);
for (int i = 0; i < weight; i++) {
//此处 重复添加;被轮询到的概率增大
serverList.add(server);
}
}
String server = null;
synchronized (pos) {
if (pos > keySet.size()) {
pos = 0;
server = serverList.get(pos);
pos++;
}
}
return server;
}
}
###### 权重轮询的配置:
#upstream关键字表示上游服务器真正的应用服务器配置
#test-service 表示这个配置的名称
upstream test-service { #服务器集群名字,此处叫做test-service
server localhost:8090; weight 10 #表示轮询为10
server localhost:8080;
}
- 加权随机(Weight Random)法
- 最小连接数(Least Connections)法——据后端服务器当前的连接情况,动态的选取其中当前积压连接数最少的一台服务器来处理当前请求
##### 4. 负载均衡带来的问题以及解决方法
---
###### 1.
- 问题: 轮询到不同的Tomcat上,两个Tomcat上的session不同步,即操作的数据也可能不同步;
- 解决: 应用服务器session同步
- 具体操作:在两个(或多个Tomcat中 添加 以下配置(集群配置))
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
然后再修改系统PATH,把这两个放在同一个文件夹中.....各种巨麻烦
来源: http://blog.csdn.net/wlwlwlwl015/article/details/48160433
- 缺点:应用服务器本身能力有限 再加上session同步 带来的网络开销越来越大
- 所以基本都不用这种方法
###### 2.
- 问题:与1. 同样的问题
- 解决:上面的算法中有个“源地址哈希”算法;
- 操作:每次都会请求分发到同一台的服务器上,所以session根本不会变;(是将用户进行随机或者轮询到不同的服务器上,那么这个用户下次来的时候就会一直在这台服务器上不会再改变所以,session不会产生新的也不会变)
- 缺点:这样的方式,集群容灾的特性就体现不出来了
- 配置:
#upstream关键字表示上游服务器真正的应用服务器配置
#test-service 表示这个配置的名称
upstream test-service { #服务器集群名字,此处叫做test-service
server localhost:8090; #服务器配置
server localhost:8080;
ip_hash; #仅添加了这个,表示使用"源地址哈希"算法才分配用户
}
- 备注:为了解决并发问题不解决容灾或者故障的话可以考虑用这个
###### 3.
- 问题:与上同样问题
- 解决: 把session外置(到redis);Nginx可以用随机轮询等
- 能够彻底解决问题,类似于一种单点登录
##### 5. Nginx动静分离-双机热备原理
---
###### 动静分离配置:
#upstream关键字表示上游服务器真正的应用服务器配置
#test-service 表示这个配置的名称
upstream test-service { #服务器集群名字,此处叫做test-service
server localhost:8090; #服务器配置
server localhost:8080;
ip_hash; #仅添加了这个,表示使用"源地址哈希"算法才分配用户
}
server {
#表示监听本机端口80
listen 80;
#服务器名称
server_name localhost;
#charset koi8-r;
#所有静态请求都由nginx处理,存放目录为html
location ~ \.(gif|jpg|jpeg|png|bmp|swf)$ {
#请求匹配的正则表达式,所有以 上面 这些后缀结尾的文件
root html;
# 全部到Nginx本地根目录下的 html 文件夹里面去找
# expires 5d; #图片在本地缓存5天,就不用往后台请求了
}
#access_log logs/host.access.log main;
#此处的"/" 表示localhost下的所有请求
location / {
root html;
index index.html index.htm;
#除了上面的静态资源之外的动态请求数据的资源
#全部都请求转发到后台服务器上去
proxy_pass http://test-service;
}
###### 双机热备:
- 双机热备中用到的软件是<code>Keepalived</code>;
- 仅支持<code>Linux</code>系统并且要在两台电脑或者虚拟机下才能完成
- 有一个Master的Nginx01,有个Backup的Nginx02;有一个KeepAlived的VirtualIP;
- 当Master的Nginx01挂了后,KeepAlived会立即通过虚拟IP转到备用的Nginx02上;
##### 6. Ngnix...总结
---
- [x] Nginx后面主要跟的是应用型服务器比如Tomcat(Http请求这类的),当然也可以跟Mysql,只是Mysql有它单独的一套;
- [x] Nginx算法:
- 1. 轮询(默认)
- 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除
- 2. Weight
- 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况
- 3. IP Hash
- 每个请求按访问ip的Hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题
- 4. Fair (第三方)
- 按后端服务器的响应时间来分配请求,响应时间的优先分配
- 5. url_hash (第三方)
- 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效
---
###### OSI层级协议
- [ ] 所谓四层就是基于 IP + 端口 的负载均衡
- [ ] 七层就是基于URL等应用层信息的负载均衡
- [ ] 同理,还有基于MAC地址的二层负载均衡和基于IP地址的三层负载均衡
- [x] 换句话说,**二层负载均衡**会通过一个虚拟MAC地址接收请求,单后再分配到真实的MAC地址;**三层负载均衡**会通过一个虚拟IP地址接收请求,然后再分配到真实的IP地址;**四层**通过虚拟 IP+端口 接收请求,然后再分配到真实的服务器;**七层**通过虚拟的URL或主机名接收请求,然后再分配到真实的服务器;
###### 优缺点:
- [x] 七层负载均衡也称为“内容交换”,也就是主要通过报文中的真正有意义的应用层内容,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。
- [x] 以常见的TCP为例,负载均衡设备如果要根据真正的应用层内容再选择服务器,只能先代理最终的服务器和客户端建立连接(三次握手)后,才可能接受到客户端发送的真正应用层内容的报文,然后再根据该报文中的特定字段,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。负载均衡设备在这种情况下,更类似于一个代理服务器。负载均衡和前端的客户端以及后端的服务器会分别建立TCP连接。所以从这个技术原理上来看,七层负载均衡明显的对负载均衡设备要求更高,处理七层的能力也必然会低于四层模式的部署方式。
- 更智能
![image](https://s3.didiyunapi.com/sxk/pic/nginx/1.jpg)
![image](https://s3.didiyunapi.com/sxk/pic/nginx/2.jpg)
![image](https://s3.didiyunapi.com/sxk/pic/nginx/3.jpg)
![image](https://s3.didiyunapi.com/sxk/pic/nginx/tcp-ip.gif)
评论区