最新的项目用了dubbo框架,原来只有一台provider机器提供服务,但是现在需要扩展到多台provider机,并且由于业务逻辑涉及到了文件加密解密操作,而密钥又是由客户提供的,因此出现了第二次请求过来会由dubbo分发到文件所在位置以外的服务机上,就出现了找不到文件的情况。
ok,作为supportor,开始解决,方案1是直接增加文件服务器来进行,但是由于项目已经上线,改起来麻烦,于是果断pass;
这样就有了方案2,修改dubbo的负载均衡策略,使得每次的业务逻辑在一条流水线上进行。
本文会持续更新,来介绍负载均衡
1. consistenthash--一致性hash算法
使用方式,在服务端注册的时候提供配置
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="DemoService" ref="demoService" loadbalance="consistenthash" />
dubbo对于该算法默认比较的是第一个请求参数,即相同的请求参数会分发到同一台服务机上。
最开始看到这个解释的时候瞬间迷茫了(原谅我的理解力),度娘了一下发现也没有demo,官网也没有提供,好吧,只能让我这种懒人自己来写了。
相关代码已在上面提供下载,这里启动了两台服务机,server 1 和server 2
服务端
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "classpath:consumer.xml" });
context.start();
DemoService demoService = (DemoService) context
.getBean("demoService");
while(true){
String hello = demoService.sayHello("word", "1");
String hello1 = demoService.sayHello("word", "2");
System.out.println(hello);
System.out.println(hello1);
}
}
这里我们看到,demoSerivce.sayHello()方法的第一个参数相同。
直接启动,结果如下,可以看到,所有的服务都是由机器2来提供的(也有可能都是1,主要看第一次是由那台服务机提供服务)server 2 say: Hello word, today is 1
server 2 say: Hello word, today is 2
server 2 say: Hello word, today is 1
server 2 say: Hello word, today is 2
server 2 say: Hello word, today is 1
server 2 say: Hello word, today is 2
server 2 say: Hello word, today is 1
server 2 say: Hello word, today is 2
因此开始考虑,一致性是通过什么来比对呢?看了一致性算法,果然没看懂,那只能试一试了。。。
开始考虑普通pojo
创建一个Students类,只有两个属性,name和age
Students s1 = new Students();
s1.setName("dog");
s1.setAge(1);
Students s2 = new Students();
s2.setName("cat");
s2.setAge(2);
DemoService demoService = (DemoService) context.getBean("demoService");
while (true) {
String hello = demoService.sayHello(s1);
String hello1 = demoService.sayHello(s2);
System.out.println(hello);
System.out.println(hello1);
}
运行结果如下,server 1 处理所有的cat,server2处理所有的dog
server 1 say: Hello cat, age is 2
server 2 say: Hello dog, age is 1
server 1 say: Hello cat, age is 2
server 2 say: Hello dog, age is 1
server 1 say: Hello cat, age is 2
server 2 say: Hello dog, age is 1
server 1 say: Hello cat, age is 2
server 2 say: Hello dog, age is 1
修改代码位置,把students对象的创建移动到for循环内
测试结果,说明对比的不是元素属性是否一致,而是和对象地址有关
server 1 say: Hello dog, age is 1
server 2 say: Hello cat, age is 2
server 2 say: Hello dog, age is 1
server 2 say: Hello cat, age is 2
server 2 say: Hello dog, age is 1
修改Students类的序列化参数,发现结果还是与地址有关
因此,最后项目修改如下,
第一次请求-->随机生成一个token-->服务机创建临时文件-->返回文件位置及token
第二次请求,携带token和文件位置-->通过token找到对应服务机-->文件加密-->业务结束
PS,由于比对的是地址值,因此需要设置一个web容器级别的token池,以保证对象一致
不过也有缺点,当消费机也是集群模式的时候,该配置无效。。。因为不同消费机的token地址不一致...
因此,如果是nginx做的前端负载均衡, 需要通过sticky来实现负载均衡(基于cookie),基本上由同一消费机提供服务,这样就能保证token同一了
最后,还是用文件服务器比较好,一劳永逸。