博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RMI结合HAProxy的实际应用及问题解决的思路
阅读量:6609 次
发布时间:2019-06-24

本文共 3967 字,大约阅读时间需要 13 分钟。

hot3.png

假设客户端机器IP为IP1,HAProxyIP为IP2,后台的RMI服务器有2台,分别为IP3和IP4

IP1--->IP2------>IP3

               |_____>IP4

正常情况下,IP1的客户端代码指向IP2,IP2做分流到IP3(负载均衡),IP3返回的真实服务地址为IP3.

则响应通过IP2回到IP1后,IP1直接连接了IP3.这就是要解决的问题。

解决方案:

修改上一篇的软件代码如下:

client端代码:

import java.rmi.RemoteException;import java.util.Enumeration; import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NameClassPair;import javax.naming.NamingException; public class WarehouseClient { public static void main(String[] args) throws NamingException,RemoteException {Context namingContext = new InitialContext();/*Enumeration
 e = namingContext.list("rmi://192.168.243.109:8080/");while (e.hasMoreElements()) {System.out.println(e.nextElement().getName());}*///String url = "rmi://IP2:8080/central_warehouse";Warehouse centralWarehouse = (Warehouse) namingContext.lookup(url);if(null==centralWarehouse){System.out.println("fail to find remote RMI server...");return;}String descr = "Blackwell Toaster";double price = centralWarehouse.getPrice(descr);System.out.println(descr + ": " + price); }}

 

服务器端代码为:

import java.rmi.registry.LocateRegistry;import java.rmi.server.RMISocketFactory;import javax.naming.Context;import javax.naming.InitialContext;public class WarehouseServer { public static void main(String[] args) {  //在服务器端的容器内注册此对象  //注意:当服务器有多个IP时,client连接时会有问题。典型的服务器有多个 ip 引起的 rmi 连接问题。  //参考:http://blog.csdn.net/model_cz/article/details/6525029  //  try {   //指定服务器的设置   System.setProperty("java.rmi.server.hostname" , "IP2" );   //System.setProperty("java.rmi.server.hostname" , "1.2.3.4" );   LocateRegistry.createRegistry(8080);       //指定数据连接端口   RMISocketFactory.setSocketFactory(new WareFactory());       WarehoseImpl centralWarehouse = new WarehoseImpl();   Context namingContext = new InitialContext();   namingContext.bind("rmi://IP3:8080/central_warehouse", centralWarehouse);  } catch (Exception e) {   System.out.println(e.toString());   return;  }  System.out.println("waiting for the client to connect..."); }}

       解决思路:

 参考了

to("---------------------------------");下面的代码可以获取这个远程引用的IP和端口,不够目前我们用不上这些代码  /*  RemoteObjectInvocationHandler roih = (RemoteObjectInvocationHandler)Proxy.getInvocationHandler(centralWarehouse);    o(roih.getRef().remoteToString());    sun.rmi.server.UnicastRef ref = (sun.rmi.server.UnicastRef)roih.getRef();    LiveRef liveRef = ref.getLiveRef();    Channel c = liveRef.getChannel();  if(c instanceof TCPChannel ){   o("big congratulations...");   TCPChannel tc =(TCPChannel)c;     }else{   o(c.toString());  }  //o("endpoint "+(liveRef.getChannel().getEndpoint());    o("port "+liveRef.getPort());  */  o("---------------------------------");

 这样就获取了[IP:Port],其实我们要的就是Port.

由于控制链已经基于负载均衡,

所以数据链通过HAProxy直连这个[IP:Port],的话,

也是某种程度的负载均衡,不是吗?

-----------

背景知识:

控制链是短连接。

数据链是长连接。

PS:看过HADOO的RPC框架源码再理解RMI毫无压力。

==================================

然后,问题就转化为HAProxy的源码修改了。

需要增加的功能:

client--->HAProxy--->RMI SERVER

本质上就是在HAProxy源码中添加对RMI协议的分析。

所以,第一个问题是去找到RMI的RFC文档学习RMI协议。

发现找了半天没找到JRMP协议的RFC文档,于是我放弃了解析协议。

转而考虑依靠IP和端口提供线索。

经过抓包分析RMI的工作流后,我最终给出的思路如下:

一个HAProxy代理后面配置若干RMI服务器,大致的配置就是如下:

 ========================================

IP1--->IP2------>IP3

               |_____>IP4

IP1是RMI_client.   IP2是HAProxy,  IP3&IP4都是RMI_Server.

(所以需要保证ip3的控制端口80,数据端口为81,服务器代码返回的RMI对象的ip:port为  IP2 : 81)

(所以需要保证ip4的控制端口80,数据端口为82,服务器代码返回的RMI对象的ip:port为  IP2 : 82)

那么配置就是:

HAProxy:

 listen 0.0.0.0:80

server ip3 ip3:80

server ip4 ip4:80

这样的话,控制端仍然保持负载均衡。

 

剩下的关键在于数据端口

Haproxy:

listen 0.0.0.0:81

 server ip3 ip3:81

listen 0.0.0.0:82

  server ip4 ip4:82

这样就解决问题了。

不过haproxy的IP就暴露给了rmi server.

个人认为这是性价比最高的一种方案。

----------------------------------------

方案2是为技术狂准备的。

每个RMI服务器的数据端口都一样,

控制连的数据为RMI协议,修改haproxy源码做RMI协议(JRMP?)应用层协议分析。

提取(有用的信息比如objectid等 , ip)映射。

这个映射表可根据需要长期存在或者动态删除。

然后数据端建立连接时解析RMI协议的objectid,查找哈希表映射的IP,连接。

这个理论上很完美,但是因为要

1RMI应用层协议分析

2 修改haproxy源码。

所以性价比略低于方案1,而且在多台haproxy时无法共享哈希表映射关系(提取出来放在公共的缓存服务器?)。

------

从维护和劳动工作量的角度,个人偏向方案1,需改配置和服务器的数据端口即可。

转载于:https://my.oschina.net/qiangzigege/blog/382570

你可能感兴趣的文章
【Visual Studio 扩展工具】使用 ComponentOne迷你图控件,进行可视化数据趋势分析...
查看>>
通过更快,更一致的决策提高生产力和盈利能力
查看>>
Qt5开发及实例学习之按钮组QToolButton
查看>>
windows上类似dnsmasq的软件Dual DHCP DNS Server
查看>>
精选Spring Boot三十五道必知必会知识点!
查看>>
大数据的技术生态?Hadoop、Hive、Spark之间是什么关系?
查看>>
给你一份Spring Boot核心知识清单
查看>>
记一次神奇的Mysql死锁排查
查看>>
(转载)Python 模块 cachetools
查看>>
视图集ViewSet
查看>>
error: RPC failed; result=22, HTTP code = 405
查看>>
React性能优化
查看>>
Java Object详解
查看>>
Handler+Looper+MessageQueue深入详解(根据源码)
查看>>
ubuntu12.04--需要运行“apt-get -f install”来纠正下列错误
查看>>
Awk 20 分钟入门介绍
查看>>
OSChina 周日乱弹 ——病毒,你对程序员的原力一无所知!
查看>>
Apache+PHP+Mysql开发环境搭建
查看>>
一,JavaWeb系列博客的结构
查看>>
swift3.0 Timer 定时器
查看>>