我现在在调用远程服务器上部署的EJB的时候,有时候因为网络或者其他原因,所以非常慢,很长时间也不能够返回结果,我不知道可不可以设置一个超时控制这样的东东,如果在一段时间内没有返回结果,我就直接返回,执行忙下边的程序。谢谢大家了,请大家多帮忙!
注:EJB2.0 中 sessinoBean

解决方案 »

  1.   

    客户端接入线程是指由于客户端接入服务器而导致服务器增加的线程。
    目前在网络开局现场发现每接入一个Client会导致30-40服务器线程的增加。按照50个Client计算,则可能增加2000个左右的线程。而这些线程可能会占用1M做的stack内存,而通常Java的堆内存分配的比较多,最后导致无法创建本地线程的问题。
    通过观察现场的线程,发现绝大多数是RMI的通讯线程
    4.2 问题分析   
    客户端到服务器的通信目前存在两种主要的通信方式:F口发起的调用和JMS的异步消息上班。其中F口的调用是RMI方式的EJB调用。而JMS的异步消息也是通过RMI的主动轮询来完成的。
    并且在进行F口调用的时候,会在应用逻辑中有可能产生新的线程。这些线程的数量也是需要关注的。
    4.3 实现原理
    客户端和服务器频繁的发起RMI调用,导致服务器上会有很多线程为这些通讯连接服务。由于RMI调用通常都是短时的,比如JMS的消息主题的轮询,是每2s进行一次,但是每次调用的时间是在毫秒级。控制调用的并发程度,对性能没有什么损失,就能降低服务器上的接入线程的数量。
    4.3.1 JMS并发控制
    并发控制的出发点是:一个RMI调用通常在非常短的时间完成。目前2秒钟轮询一次,理论上可以支持非常多的主题轮询。目前网管系统中出现很多JMS相关的线程,是由于并发度导致的,而非处理能力上问题。即很多请求是在同一个时刻发起导致了很多线程,如果将请求错开一点,也是完全能够满足要求,并不会带来性能上的损失。
    并发控制的原理是:控制并发的数量,将请求均匀分布。
    基本实现方法是在请求的时候进行排队。如原来会多线程并行的调用如下的方法,
    SpyMessage message = serverIL.receiveAndAck(connectionToken,
                                sub.subscriptionId, wait);
    每个方法很快会返回,每隔2s会调用一次,通过如下的方法就可以控制并发度,也就可以控制在服务器上的线程数量,
    concurrentSepephore.acquire();
    SpyMessage message = serverIL.receiveAndAck(connectionToken,
                                sub.subscriptionId, wait);
    concurrentSepephore.release();
    注意:网络不好的时候,会导致在获取资源锁的时候有较大的延时。但是这个延时即使在没有采取资源锁的情况下也是应该有的。导致问题的关键是网络不好,即使全并发延时也会相同的严重。
    4.3.2 F口调用并发控制
    F口的并发程度不高。为了控制异常冲高的情况,并且为了控制服务器上接入线程的数量,因此也进行相同的并发控制。主要是在F口的EJB调用上进行并发控制。
    4.3.3 端口合并
    UEP在deploy-default.properties中配置了很多的RMI端口,这些端口使用了不同RMIClientSocketFactory。使用不同的RMIClientSocketFactory,但是对超时值设置却是相同的。
    这里存在的问题:
    1、 使用不同的端口,导致建立的不同TCP连接,会导致服务器上存在不同的线程来服务。导致服务器端频繁的创建和销毁线程。
    2、 端口分开没有体现应有的作用。首先设置的超时值大部分是相同的。即使不同,实质差别也不大。
    3、 导致穿越防火墙的时候开了过多的端口。
    解决办法
    将常用的RMI端口进行合并。
    目前经常发起的RMI调用有:F口调用,F口的心跳,JNDI的lookup。
    jndi.rmiobjectport=21104
    jndi.rmiport=21102
    uep.finterface.heartbeart.Port=21108
    现状:
    JNDI的超时
    jndi.rmiConnTimeout=600000
    jndi.rmiSoTimeout=600000
    F口调用的超时
    ums.invoker.rmi.conntimeout=600000
    ums.invoker.rmi.sotimeout=600000
    F口心跳的超时
        long interval = SessionCenter.getHeartBeatInteval();
        int count = SessionCenter.getHeartBeatFailCount();
        int timeOut = (int)(interval * count / 4);
        FITimedRMIClientSocketFactory csf = new FITimedRMIClientSocketFactory();
    csf.setTimeout(timeOut, timeOut);
    其中缺省的设置是:
    uep.finterface.heartbeat_interval=30000
    uep.finterface.heartbeat_fail_times=6
    折合下来是连接的超时45000,读的超时是45000ms。
    可以将这三个端口的超时值设置为一致的。因为都是客户端到服务器发起的调用,面对相同的网络环境。其他端口,如果是RMI的通讯方式,也是可以按照类似方式合并的。目前合并这三个端口,主要是为了减少服务器端的线程考虑的。
    修改方法
    RMI要共享端口,需要使用相同的RMIClientSocketFactory实现或者都不使用。建议都不使用。
    修改步骤:
    1、 修改F口心跳
    修改FIInitManager中初始化HeartbeatReciever代码,
    hearbeatReciever = new HeartbeatReciever(port,csf);
    修改为
    hearbeatReciever = new HeartbeatReciever(port,null);
    2、 修改JNDI
    修改ums-svr\kernel\server\default\conf\all\jboss-service.xml.tmpl中的
    <mbean code="com.zte.ums.uep.psl.naming.server.GlobeNamingServerMain"
    name="zte:service=GlobeNamingServer">
       <attribute name="Port">@port@</attribute>
       <attribute name="RmiPort">@rmiport@</attribute>
       <attribute name="RmiConnTimeout">@rmiConnTimeout@</attribute>
       <attribute name="RmiSoTimeout">@rmiSoTimeout@</attribute>
       <attribute name="ClientSocketFactory">com.zte.ums.uep.psl.naming.interfaces.TimedRMIClientSocketFactory</attribute>
       <!--<attribute name="ServerSocketFactory">custom</attribute>-->
    </mbean>
    注释掉其中的ClientSocketFactory属性。
    3、 修改F口调用
    修改ums-svr\kernel\server\default\conf\all\jboss-service.xml.tmpl中的
    <mbean code="org.jboss.invocation.jrmp.server.JRMPInvoker"
             name="jboss:service=invoker,type=jrmp">
        <attribute name="RMIObjectPort">@rmiobjectport@</attribute>
        <attribute name="RMIClientSocketFactory">com.zte.ums.uep.psl.systemsupport.rmisocketfactory.JRMPRMIClientSocketFactory</attribute>
        <!--<attribute name="RMIServerSocketFactory">custom</attribute>
        <attribute name="RMIServerSocketAddr">custom</attribute>
        -->
    </mbean>
    注释掉其中的RMIClientSocketFactory属性。修改deploy-default.properties文件
    uep.finterface.heartbeart.Port=21108
    jndi.rmiport=21102
    jndi.rmiobjectport=21104
    都修改成21104即可。
    增加系统属性: 
    //客户端超时,可只在客户端设置
    sun.rmi.transport.connectionTimeout=300000//客户端idle timeout,5分钟
    sun.rmi.transport.tcp.responseTimeout=600000//客户端,保持和目前相同。
    //服务器超时,可只在服务器设置
    sun.rmi.transport.tcp.readTimeout= 600 * 1000//服务端,保持和目前相同