抽空本身写了个简易版的rpc框架,想了下怎么搞负载均衡, 最简单的方式就是搞个配置文件放置服务地址,直接读配置文件,转而想到配置文件能够放zk,至关于用zk来作配置中心或者服务发现。 优秀的dubbo项目就能够这么作,立刻参考了下谷歌的grpc,发现了一篇谷歌很棒的文章,拜读了下(也借用了谷歌这篇文章的图片),很不错,想写一些我本身的看法。nginx
rpc通讯自己并不复杂,只要定好协议怎么处理问题不大,可是负载均衡的策略是值得推敲的。算法
通常状况下,负载均衡的策略有如下两种后端
1. 代理服务
客户端并不知道服务端的存在,它全部的请求都打到代理服务,由代理服务去分发到服务端,而且实现公平的负载算法。 客户机可能不可信,这种状况经过用户面向用户的服务,相似于咱们的nginx将请求分发到后端机器。服务器
缺点: 客户端不知道后端的存在,且客户端不可信,延迟会更高且代理服务会影响服务自己的吞吐量cookie
优势: 在中间层作监控等拦截操做特别棒。负载均衡
如图: 框架
2. 客户端负载均衡
客户端知道有多个后端服务,由客户端去选择服务端,而且客户端能够从后端服务器中本身总结出一份负载的信息,实现负载均衡算法。 这种方式最简单的实现就是我上面说的直接搞个配置文件,调用的时候随机或者轮询服务端便可。ide
如图: 模块化
优势:
高性能,由于消除了第三方的交互微服务
缺点:
客户端会很复杂,由于客户端要跟踪服务器负载和健康情况,客户端实现负载均衡算法。多语言的实现和维护负担也很麻烦,且客户端须要被信任,得是靠谱的客户端。
以上是介绍了两种负载均衡的方案,下面要说的就是使用代理方式负载均衡的几种详细的方案
代理方式的负载均衡有不少种
代理负载平衡能够是 L3/L4(传输级别)
或 L7(应用程序级别)
。
在 L3/L4
中,服务器终止TCP链接并打开另外一个链接到所选的后端。
L7
只是在客户端链接到服务端端链接之间搞一个应用来作中间人。
L3/L4
级别的负载均衡按设计只作不多的处理,与L7级别的负载均衡相比的延迟会更少,并且更便宜,由于它消耗更少的资源。
在L7(应用程序级)负载平衡中,负载均衡服务终止并解析协议。负载均衡服务能够检查每一个请求并根据请求内容分配后端。这就意味监控拦截等操做能够很是方便快捷的作在这里。
L3/L4 vs L7
正确的打开方式有一下几种
- 这些链接之间的RPC负载变化很大: 建议使用L7.
- 存储或计算相关性很重要 :建议使用L7,并使用cookie或相似的路由请求来纠正服务端.
- 设备资源少(缺钱): 建议使用 L3/L4.
- 对延迟要求很严格(就是要快): L3/L4.
下面要说的就是客户端实现负载均衡方式的详细方案:
public class Test
{
public class InnerClass
{
public int getSum(int x,int y)
{
return x+y;
}
}
public static void main(String[] args)
{
Test.InnerClass testInner =new Test().new InnerClass();
int i = testInner.getSum(2/3);
System.out.println(i); //输出5
}
}
实例内部类
实例内部类是指没有用 static 修饰的内部类
public class Outer
{
class Inner
{
//实例内部类
}
}
在外部类的静态方法和外部类之外的其余类中,必须经过外部类的实例建立内部类的实例,若是有多层嵌套,则内部类能够访问全部外部类的成员
public class Outer
{
class Inner{}
Inner i=new Inner(); //类内部不须要建立外部类实例
public void method0()
{
Inner j=new Inner(); //类内部不须要建立外部类实例
}
public static void method1()
{
Inner r=new Outer().new inner(); //静态方法须要建立外部类实例
}
class Inner1
{
Inner k=new Inner(); //不须要建立外部类实例
}
}
class OtherClass
{
Outer.Inner i=new Outer(yongshi123.cn).new Inner(); //其余类使用时须要建立外部类实例
}
静态内部类
静态内部类是指使用 static 修饰的内部类
public class Outer
{
static class Inner
{
//静态内部类
}
}
在建立静态内部类的实例时,不须要建立外部类的实例
public class Outer
{
static class Inner{}
}
class OtherClass
{
Outer.Inner oi=new Outer.Inner();
}
局部内部类
局部内部类是指在一个方法中定义的内部类
public class Test
{
public void method()
{
class Inner
{
//局部内部类
}
}
}
局部内部类与局部变量同样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰,局部内部类只在当前方法中有效,局部内部类中能够访问外部类的全部成员
public class Test
{
Inner i=new Inner(www.hnxinhe.cn); //编译出错
Test.Inner ti=new Test.Inner(); //编译出错
Test.Inner ti2=new Test().new Inner(); //编译出错
public void method()
{
class Inner{}
Inner i=new Inner();
}
}
匿名类
匿名类是指没有类名的内部类,必须在建立时使用 new 语句来声明类
new<类或接口>()
{
//类的主体
};
这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。使用匿名类可以使代码更加简洁、紧凑,模块化程度更高
匿名类有两种实现方式:
继承一个类,重写其方法。
实现一个接口(能够是多个),实现其方法。
public class Out
{
void show()
{
System.out.println("调用 Out 类的 show() 方法");
}
}
public class TestAnonymousInterClass
{
//在这个方法中构造一个匿名内部类
private void show(www.xgjrfwsc.cn)
{
Out anonyInter=new Out()
{
//获取匿名内部类的实例
void show()
{
System.out.println("调用匿名类中的 show() 方法");
}
};
anonyInter.show();
}
public static void main(String[] args)
{
TestAnonymousInterClass test=new TestAnonymousInterClass();
test.show();
}
1. 笨重的客户端
这就意味着客户端中实现负载平衡策略,客户端负责跟踪可用的服务器以及用于选择服务器的算法。 客户端一般集成与其余基础设施(如服务发现、名称解析、配额管理等)通讯的库,这就很复杂庞大了。
2. Lookaside 负载均衡 (旁观?)
旁观式负载平衡也称为外部负载平衡,使用后备负载平衡,负载平衡的各类功能智能的在一个单独的特殊的负载均衡服务中实现。客户端只须要查询这个旁观式的负载均衡服务, 这个服务就能给你最佳服务器的信息,而后你拿这个数据去请求那个服务端。 就像我一开说的好比把服务端的信息注册到zk,由zk去作负载均衡的事情,客户端只须要去zk取服务端数据,拿到了服务端地址后,直接向服务端请求。
如图:
以上说了这么多,到底服务间的负载均衡应该用哪一个,总结如下几点:
-
客户端和服务器之间很是高的流量,且客户端是可信的,建议使用‘笨重’的客户端 或者 Lookaside 负载均衡
-
传统设置——许多客户端链接到代理背后的大量服务,须要服务端和客户端之间有一个桥梁,建议使用代理式的负载均衡
-
微服务- N个客户端,数据中心有M个服务端,很是高的性能要求(低延迟,高流量),客户端能够不受信任,建议使用 Lookaside 负载均衡