RMI java.rmi.NoSuchObjectException and Port reuse in heavy concurrency - rmi

I am working on an application which has following structure
APPLICATION DESIGN:
One machine say MACHINE1 has running 6 different JVMs. Each JVM is running APP1 in it. So collectively MACHINE1 has 6 parallel executions of java application APP1
Another machine MACHINE2 runs Single JVM which has application APP2 running.
APP2 has different kind of JAVA Service Libraries like Service1, Service2 and service3 etc. If Any APP1 Of MACHINE1 wants to Perform Service1 then it will invoke Same instance of APP2 and pass Request Object. APP2 reads the Request object and on the basis of that it invokes the requested service and returns the result to APP1.
Services of APP2 are using input data in form of xml files of APP1. So we are transferring data of APP1 to APP2 in form of file InputStream
APP1 and APP2 are using RMI for communication. Services of APP2 perform operation on APP1 xml files to generate results. To send data from APP1 to APP2 we pick a port of MACHINE1 and export the remote Object of input Stream. In Machine1 we are maintaing POOL of integers which refers to Ports. APP1 picks a port integer from the pool and export the inputStream(We have created RMIInputStream).
PROBLEM:
When we execute application with less concurrency then it worked fine. But when we increase the concurrency then we starts getting following exception
"java.rmi.NoSuchObjectException: no such object in table"
This exception arises when we are reading the data from RemoteInputStream.
I have tried to solve this problem and focused on RemoteInputStream Object. I have seen lot many responses which states about the weak reference of remote object. I have seen it and found that reference is not weak in my case.
I have also modified the dfc properties by increasing the lease value but no effect in my case.
MY OBSERVATION ON THIS PROBLEM:
During testing I observed that every thing works fine if all ports used single time. Suppose If I allocate 20 ports in pool than I will not get any exception in first 20 times. I will get exception when I will start using the same port second time. If I increase the ports count from 20 to 600 then I wll not get exception in first 600 times. It looks like some problem is there with port re-use.
I have added a wait time of 1 minute before sending port integer back to pool. In this case my problem got reduced drastically.
So my conclusion if I export an input Stream object in MACHINE1's port say 55800 and MACHINE2 will read it quicky and APP1 unexport the data and again try to export another remote input Stream object then it will create problem.
I need you all experts view on my problem. Is this problem related to TCP/IP protocol? Am I trying to reuse the same port which is still active in terms of TCP/IP life cycle?
Is there any good way to handle this problem rather than introducing the Wait in returning port.
In production environment in MACHINE1 we have been allocated certain range of Ports integers. Our application is allowed to use only ports between this range. Firewall is open for this specific range of Ports. So when we want to export inputStream we have to be sure that the data should be exported in allowed Port range. So we are using following code
UnicastRemoteObject.exportObject(remoteInputStreamObj, portNo.intValue());
For this purpose we have developed a POOL which maintains the free port integers. If new thread created in APP1 and having 3 XML files which should be processed at APP2 so APP1 will create a request object and create new three RemoteInputStream objects. At the time of creating object 3 ports integers will be removed from the Pool. Once the request got processed at APP2 side and APP1 got the result, in that case APP1 will unexport the object and return the Ports integer back to POOL.
Here Ports POOL means a Pool of integers which maintains the free ports integers. This pool does not means RemoteInputStream objects pool. We create everytime new instance of RemoteInputStream. In MACHINE1 eventhough 6 JVM's are running we have another 7th JVM which maintains singleton reference of Port POOL. So One POOL instance is shared by all the other APP1 JVMs.
In our case we have high level of concurrency. Other than concurrency, One request of APP1 can have more than one XML. In few cases 25-30 files can be there in single request which needs to be read by MACHINE2 APP2 simultaneously. In this case we need to create 25-30 instances of RemoteInputStream object and put it in Request Object. So here we need more that one port at a time.
In actual production environment it may happen that 50 threads of Service1 can be execute simultaneously and each Request Object can have 2-3 XML files whose inputStream object needs to export. In this case we need more than one port.

we starts getting following exception "java.rmi.NoSuchObjectException: no such object in table"
This exception has exactly one meaning. You tried to call a remote method via a stub whose corresponding remote object has been unexported.
Once the request got processed at APP2 side and APP1 got the result, in that case APP1 will unexport the object and return the Ports integer back to POOL.
And here, as stated above, is the source of the problem. You're unexporting objects. And then some client is calling a method on a stub whose remote object has been unexported, and so you get this exception, exactly as described above.
You don't need all this complexity. You can use a single port per JVM for all RMI objects. You don't even need to unexport the remote objects, which is what is causing the original problem. Just let them be DGC'd in the normal course of events.
Throw all this away and return a new RemoteInputStream per request.

Related

In vert.x, does it make sense to create multiple HttpServer instances in a runtime?

I created a verticle named HttpServerVerticle and inside it let it create a HttpServer instance by vertx.createHttpServer(), then in my main verticle I deployed this HTTP verticle with > 1 instances by vertx.deployVerticle("xxx.xxx.HttpServerVerticle", deploymentOptionsOf(instances = 2)).
Does it make sense to have multiple HttpServer instances in a runtime? If it does, why I did not see similar error messages like "8080 port is already in use"?
Vert.x will actually round-robin between your HttpServer instances listening on the same port:
When several HTTP servers listen on the same port, vert.x orchestrates the request handling using a round-robin strategy...
So, when [a] verticle is instantiated multiple times as with: vertx run io.vertx.examples.http.sharing.HttpServerVerticle -instances 2, what’s happening? If both verticles would bind to the same port, you would receive a socket exception. Fortunately, vert.x is handling this case for you. When you deploy another server on the same host and port as an existing server it doesn’t actually try and create a new server listening on the same host/port. It binds only once to the socket. When receiving a request it calls the server handlers following a round robin strategy...
Consequently the servers can scale over available cores while each Vert.x verticle instance remains strictly single threaded, and you don’t have to do any special tricks like writing load-balancers in order to scale your server on your multi-core machine.
So it is both safe and encouraged to creating multiple instances of HttpServers, if required to scale across cores.

Load balancer and celery result backends

I have a task that takes approximately 3 minutes to run. It pulls data from a remote server and makes cpu-intensive analysis on it. This task will be invoked by an api call. Upon the api call, i am planning to give client a unique task id and assign the task to a celery worker. Then the client will poll the server with the given task id to see if the task is completed by celery worker and its result it saved to a result backend. I think of using nginx, gunicorn, flask and dockerize them for a easy deploy in case i need to distribute this architecture across multiple machines.
The problem is that the client may poll different servers due to load balancer and if not handled well, the polled server’s celery’s result backend might not have the task’s result but other server’s celery result backend has it.
Is it possible to use a single result backend over multiple celery instances and make different celery instances wuery the same result backend? What might be other possible ways to solve this other than using cloud storage like S3?
Would I have this problem only if I have multiple machines or would it happen even if I have multiple gunicorn instances in a single machine where nginx acts as a load balancer on them?
Not that it is possible to use a single result backend by all Celery workers, but that is the only setting that makes sense! Same goes for the broker in most cases, unless you have a complicated Celery infrastructure with exchanges, and complicated routes...

Selecting specific worker for connection

So, I'm using a hypnotoad server for my application and is trying to maintain state for connections. Turns out for every connection a different worker is spawned/selected. Can I somehow make this selection explicit? Also is there a way to know which worker was used for my last request and use it again for corresponding requests?
You can ran multiple masters (every with one worker or like morbo - single processes).
And add load balancer before 'em which will be responsible to selection of concrete process per connection.
Typically I used nginx with upstream module sticky setting.

Vertx | Global state of Verticles in a cluster

Newbie alert.
I'm trying to write a simple module in Vertx that polls the database (PostGres) every 10 seconds and pushes the results to the clients. I'm thinking of confining the blocking code (queries the database via JDBC) in a worker verticle and rest of the above layers are completely non-blocking and async.
This module will be packaged as a jar and distributed to a different apps (typically webapps) which can subscribe to the event bus via the javascript bridge.
My question here is in a clustered environment where I have 5 processes of the webapp running with the vertx modules, how can I ensure that there's only one vertx verticle querying the database. I don't want all the verticles querying the database and add more load. Or is there a different way to think to solve this problem. I'm using Vertx version 3.4.1
So there are 2 ways how your verticle can be multiplied:
If you instantiate multiple instances when you deploy your verticle
If you start to cluster your vert.x instances in different jvm's or different hosts
You could try to control the number of instances of your verticle which executes the query. Means you ensure, that the verticle only exists in one of your vert.x instances and your verticle is deployed with only one instance.
But this has several drawbacks:
your deployment is not transparent, means your cluster nodes differ in the deployment structure.
if your cluster node dies, where the query verticle is running, then you have no fallback.
So the best thing is, to deploy the verticle on all instances and synchronize it.
I see 3 possibilites:
Use hazelcast (the clustermanager of vert.x) to synchronize
http://vertx.io/docs/apidocs/io/vertx/spi/cluster/hazelcast/HazelcastClusterManager.html#getLockWithTimeout-java.lang.String-long-io.vertx.core.Handler-
There are also datastructures available, which are synchronized over
the cluster
http://vertx.io/docs/apidocs/io/vertx/spi/cluster/hazelcast/HazelcastClusterManager.html#getSyncMap-java.lang.String-
Use your database as synchronization point. you could add a simple
table which stores the last execution time in millis. The polling
modules, will first check if it is time to execute the next poll. If
the polling module executes the poll it also updates the time. This
has to be done in one transaction with a explicit lock on the time
table.
You use redis with the https://redis.io/commands/getset
functionality. You can store the time in millis in a key and ensure
with the getset method, that the upgrade of the time is atomic. So only the polling module which could set the key in redis, will execute the poll.
I'm giving out my naive solution here, I don't know if it would completely solve your problem or not but here is my thought process.
1) Polling bit, yes indeed you can have a worker verticle for blocking call's [ or else you could use Async bit here too IMHO because you already have Async Postgress JDBC client ] for the every 10secs part. code snippet like this can help you
vertx.setPeriodic(10000, id -> {
// This handler will get called every 10 seconds
JsonObject jdbcObject = fetchFromJdbc();
eventBus.publish("INTRESTED_PARTIES", jdbcObject);
});
2) For the listening part all the other verticles can subscribe to event bus and listen for the that address and would be getting the message whenever things would happen
3) This is for ensuring part that not all running instances of your jar start polling the database, for this I think the best possible way to handle would be not deploying the verticle in any jar and running the verticle in an standalone way using runtime vertx command like
vertx run DatabasePoller.java -cluster
And if you really want to be very fancy you could throw in Service Discovery for ensuring part that if the service of the verticle is already register then no other deployments would trigger registrations.
But I want to give you thumbs up on considering the events for getting that information much better way for handling inter-system communication.

Does multiple azure role instance count means multiple VMs?

What exactly happens when Azure worker role instance count is set to more than 1? Does this mean multiple VMs? I am using worker role do deploy a socket server. If I set instance count to 2 then will it mean that there will be 2 sockets listening for the requests?
Yes, you are right, basically one role instance is a separate VM.
2 instances also means two open sockets. But access to those sockets would be available via one single Endpoint (declared in role config) and would be automatically load balanced between 2 instances.
Based on what I heard in the FailSafe series on Channel9 by Mark Simms - web or worker role instance is another VM loaded in the virtualizing host.