1、RPC远程过程调用
consumer将要在远端的提供方上调用的接口名称、方法名称和参数类型,参数对象先利用反射得到再通过序列化方式,并通过socket(tcp)传给提供方,提供方再反序列化得到这些值,再通过反射调用方法,得到结果在序列化,通过socket,返给consumer
2、模拟HTTP协议(简单的实现原理)
Request:encode,commandlength,command
Response:encode,responselength,response
这两个也是类,给request赋值之后,通过序列化的方式,通过socket传给提供方,提供方接收到之后,再反序列化,注意在反序列化时,根据encode、commandlength的类型来构造byte,得到结果在构造response,序列化,通过socket返给调用者,调用者在解析response;
例如:
private byte encode;
private String command;
private int commandLength;
读取编码:
byte[] encodeByte = new byte[1];
input.read(encodeByte);
byte encode=encodeByte[0];
读取命令长度:
byte[] commandLengthBytes = new byte[4];
input.read(commandLengthBytes);
int commandLength = ByteUtil.bytes2Int(commandLengthBytes);(byte到int要转换一下int是32位而byte8位)
读取命令
byte[] commandBytes= new byte[commandLength];
input.read(commandBytes);
String command="";
if(Encode.GBK.getValue==encode){
command = new String(commandBytes,"GBK");
}else{
command = new String(commandBytes,"UTF8");
}
3、HttpClient发送HTTP请求
调用HttpClient方法即可,不用自己写socket方法
4、RESTful和RPC
RPC风格的URL,直接在HTTP请求的参数中标明需要远程调用的服务接口名称、服务需要的参数;
而REST,资源是网络上的一个实体,可以使用url对其来进行访问,然而客户端怎么样对资源进行操作呢,所以有了get、post。。。这些操作方式完成CRUD操作;
结合两者,使用REST风格post、get方法,参数传RPC的方法、参数,来实现远程方法调用
5、负载均衡
服务量小的时候可以使用nginx连接多个server,保证负载均衡,但是当服务量大时候,就需要一个能够动态注册和获取服务信息的地方,来统一管理服务名称和其对应的服务器列表信息,称之为服务配置中心(zookeeper(也是由许多个zookeeper组成的))):
服务提供者在启动时,将其提供的服务名称、服务器地址注册到服务配置中心,服务消费者通过服务配置中心来获得需要调用的服务的机器列表,通过相应的负载均衡算法,选取其中一台服务器进行调用。当服务器宕机或者下线时,相应的机器需要能够动态的从服务配置中心里面移除,并通知相应的服务消费者,在这个过程中,服务消费者只有在第一次调用服务时需要查询服务配置中心,然后将查询到的信息缓存到本地,后面的调用直接使用本地缓存的服务地址列表信息,而不需要重新发起请求到服务配置中心去获取相应的服务地址列表,直到服务的地址列表有变更。
负载均衡算法:
- 轮询法:将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端每一台服务器,而不关心服务器实际的连接数和当前的系统负载
- 随机法:通过系统随机函数,根据后端服务器列表的大小值来随机选取其中一台进行访问,有概率统计理论可以得知,随着调用量的增大,其实际效果越来越接近于平均分配流量到每一台后端服务器,也就是轮询的效果。(而且轮询要锁住一个变量还影响性能)
- 源地址Hash法:获取客户端访问的IP地址值,通过hash函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是要访问的服务器的序号,这种方法,同一IP地址的客户端,当后端服务器列表不变时,每次都会被映射到同一台后端服务器进行访问,根据此特性可以在消费者与提供者之间建立有状态的session会话
- 加权轮询法:不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不尽相同,给配置高、负载低的机器配置更高的权重,让其处理更多的请求,而低配置、负载高的机器,给其分配较低的权重(加入权重为3,则在serverList里面添加3次这个server,让它使用3次)
- 加权随机法:根据权重将server添加到serverlist之后,在随机选一个
最小连接数法:根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前请求 - 动态配置:
//利用动态配置来在不同时候选用不同的负载均衡方法,达到不重启应用配置即可生效(改相应配置文件就行了)
GroovyClassLoader groovyClassLoad=new GroovyClassLoader(Thread.currentThread().getContextClassLoader());
Class<?> groovyClass = groovyClassLoad.parseClass(sourceCode);
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
String server = (String)groovyObject.invokeMethod("execute",serverWeigthtMap); //execute就是上述的负载均衡算法,
6、consistent Hash算法
主机根据ip地址和虚拟机的编号 host_ip#id生成hash值,排列成环。
需要缓存的对象也用同样的hash算法生成hash值,排列成环。
然后对象存储在顺时针离它最近的主机上。
单调性体现在:
无论是新增主机还是删除主机,需要改变位置的都是离那台主机最近的那些节点,其他节点不需要改变位置。