Does GRPC ManagedChannel use DNS-RR for load balancing? - java

When creating a channel like this
ManagedChannelBuilder.forAddress("mybackend", 6565)
And mybackend is a DNS A record with multiple IP addresses.
Does GRPC round-robin between the records or does it just stick to one for the lifetime of the channel?
If not, would it work if I do?
ManagedChannelBuilder.forTarget("dns:///mybackend:6565")
Or is this capability just not available?

NettyChannelBuilder.forAddress(SocketAddress) is the API that can only access a single IP, due to InetSocketAddress's eager resolution.
forAddress(String, int) was retrofit to use forTarget(String) internally. So it is a convenience and converts to something similar to forTarget(host + ":" + port), but with some extra logic to handle IPv6 literals. The "dns:///" prefix is added to target strings when they fail to parse. See the forTarget() docs for both details. So it is essentially equivalent to using forTarget("dns:///mybackend:6565").
gRPC, by default, doesn't round-robin over multiple addresses. By default it does "pick-first" which stops on the first working address (potentially choosing a different address when reconnecting). You can change that via a service config or defaultLoadBalancingPolicy("round_robin").

Related

In Apache Camel, how can I receive an error if an endpoint doesn't exist?

We are using Camel fluent builders to set up a series of complex routes, in which we are using dynamic routing using the RecipientList functionality.
We've encountered issues where in some cases, the recipient list contains a messaging endpoint that doesn't exist (for example, something like seda:notThere).
A simple example is something like this:
from("seda:SomeSource")....to("seda:notThere");
How can I configure the route so that if the exchange tries to route to an endpoint that doesn't already exist, an error is thrown?
I'm using Camel 2.9.x, and I've already experimented with the Dead Letter Channel and various Error Handler implementations, with (seemingly) no errors or warnings logged.
The only logging I see indicates that Camel is (attempting to) send to the endpoint which doesn't exist:
2013-07-03 16:07:08,030|main|DEBUG|o.a.c.p.SendProcessor|>>>> Endpoint[seda://notThere] Exchange[Message: x.y.Z#293b9fae]
Thanks in advance!
All endpoints behave differently in this case.
If you attempt to write to a ftp server that does not exist, you certainly get an error (connection refused or otherwise)..
This is also true for a number of endpoints.
SEDA queues gets created if the do not exist and the message will be left there. So your route actually sends to "notThere" and the message will still be there until the application restarts or someone starts to consume messages from seda:notThere. This is the way seda queues are designed. If you set the size of the seda queue by to("seda:notThere?size=100"), then if there is noone reading (or reading slowly) you will get exceptions on message 101 and forward.
If you need to be sure some route is consuming your messages, use "direct" instead of "seda". You can even have some middle layer to use the features of seda with respect to staging and the features of direct knowing there is a consumer active (if sent from recipient list with perhaps user input (god forbid).
from("whatever").recipentList( ... ); // "direct:ep1" work, "direct:ep2" throws exception
from("direct:ep1").to("seda:ep1");
from("seda:ep1").doRealStagedStuffHere();

JGroups function to list available Groups or Clusters

I have a series of clients which communicate with each other using JGroups library, they basically create a communication channel attached to a cluster name:
communicationChannel = new JChannel(AutoDiscovery.class.getResource("/resource/udp.xml"));
communicationChannel.connect("cluster1");
Now I would like them to first list available clusters to connect to and let the user decide which cluster connect to without hardwiring the name of the cluster in the code as above.
Apparently the API has getName() which returns the logical name of the channel if set but there's no method to retrieve set up clusters.
I though using the org.jgroups.Message.getHeaders() and reading the header would yield the active clusters but nothing.
Any help please?
There's no way to find the currently available clusters, I suggest maintaining some extra state which stores (in-memory) all cluster names and their associated configuration.
Once thing you could do though is develop a custom protocol (insert it below GMS), which does the following:
- Catches down(Event evt): if evt.getType() == Event.CONNECT*** (4 events), grab the cluster name ((String)evt.getArg()) and add it to a set
- Catches down(Event evt): if evt.getType() == Event.DISCONNECT, grab the currently cluster name and remove it from the set
This doesn't give you the config info; you could get this too, if you subclasses JChannel and overwrote connectXXX() and disconnect().

Attempting to connect to a CORBA Service using corbaloc url

String[] orbargs= {};
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(orbargs, null);
org.omg.CORBA.Object cobj = orb.string_to_object("corbaloc:iiop:10.1.1.200:6969/OurServiceHelper");
_OurServiceHelper cpsh = _OurServiceHelperHelper.narrow(cobj); // Get's stuck
cpsh.ourMethod();
That narrow just hangs.
My service is setup to run on a static port. And we know it works since we usually look it up through the NamingService.
What am I doing wrong?
If you're using the NamingService, you should actually be using a corbaname url instead of a corbaloc url. The below will work if your naming service is on port 6969. If "OurServiceHelper" is on 6969 but the NamingService is on a different port, you need to specify the port of the naming service in the url below instead of 6969. The port of the server object is embedded in the ior returned by the NamingService so that's why it doesn't need to be specified.
"corbaname:10.1.1.200:6969#OurServiceHelper"
Re: Comment:
First a note about IORs and serving up objects. If you want your served objects to be persistent across process restarts, you have to set the PERSISTENTlifetime policy on the POA that contains the objects. Also, the IOR embeds the ip and port of the server, so if you want to generate IORs that remain consistent across restarts you have to use a static IP and port number as well as using the persistent lifetime policy.
The name service makes things easier by allowing you not to have to worry about a lot of this stuff. As long as the name service is reachable at a known location, all of your server objects can just register themselves with the name service when they are instantiated and clients can then access them without having to know where they're located.
If you're determined not to use the name service you're code will have to change somewhat. If you use the corbalocurl then you are using the Interoperable Naming Service (INS). See: http://java.sun.com/j2se/1.4.2/docs/guide/idl/INStutorial.html. Using the INS, you need to use the functionality of the NamingContextExt object. Specifically, to resolve the corabloc url that you construct you should call the NamingContextExt::resolve_strfunction and pass in the url.
The key part of the corbaloc URL (string after the slash), could possibly be incorrect or not registered correctly, and the serverside orb isn't able to map the key to the object reference.
How are you running the server?
This should work:
<server> -ORBInitRef OurServiceHelper="file://server.ior"
So when the corbaloc request comes in the orb should be able to match the key to the ior and return you the ior. Different ORB's have different ways of doing this for registering an initial reference, TAO have a propriety interface called IORTable for example.
The corbaloc has no type info in it, so the ORB is checking the type you're narrowing to by making a remote call (_is_a). Try using an unchecked narrow, which won't call _is_a:
_OurServiceHelper cpsh = _OurServiceHelperHelper.narrow(cobj);
It's odd that the _is_a call doesn't return for you. My guess is that the unchecked_narrow will work work (you'll get a non-null result), but the object reference won't work.

How to fetch all DNS entries from JAVA application?

As of now, I'm using the below code to get DNS name of the given IPAddress. Instead of fetching it for each IPAddress in the network, I want to fetch all the DNS entries (IPAddress - HostName mapping) from the DNS Server in one go. Is it possible? If so, how to do it?
InetAddress addr = InetAddress.getByName(address);
dnsname = addr.getCanonicalHostName().trim();
From a public DNS server, there is no way to pull out all the data it holds. Enumerating all the IP addresses one by one is the only solution.
If you have a special relationship with the DNS server (for instance, it is managed by your employer), you may request from the DNS administrator a right to transfer the whole zone (the DNS request known as AXFR). They may authorize your IP address or gives you a TSIG key to authentify yourself.
Then, you will have to find a way to do a zone transfer (possibly with TSIG authentication) in Java. Using these keywords, I find some code and documentation. Use a code search engine like Google Code Search or Krugle to find examples of use.
[DNS experts will probably scream "Use zone walking on NSEC" but most DNS zones are not signed with NSEC.]

how to set specific source port

I'm using Spring's RestTemplate class to get XML from a web service outside my organisation.
Due to a change in local firewall rules, I need to specify a specific source port in my HTTP requests. Now I can't find anything in the api, on stackoverflow or any tutorial on how to do this.
Is this not possible?
More generally, in descriptions online, I have found that using a specific source port was generally done with UDP based connections/applications. Is this something that is not usually done with TCP?
(I really don't think it helps, but here's the code snippet, as asked by a commenter below):
MyRequest request = new MyRequest(); //whole thing done via jackson
RestTemplate templ = new RestTemplate();
this.serviceUrl = String.format("%s:%d", properties.getServiceUrl()
properties.getServicePort());
ExptectedResponse response = templ.postForObject(serviceUrl, request, ExptectedResponse.class);
The source port of a TCP connection is chosen at random from the ephemeral port range 49152-65535. TCP port ranges are shown here: RFC 6056 - Ephemeral Ports
"The dynamic port range defined by IANA consists of the 49152-65535
range, and is meant for the selection of ephemeral ports."
The port selection process differs depending on the operating system being used. This is much lower level than a typical Java application and therefore is out of your applications control.
Technically you can could force the OS to select a specified port, but as I mentioned is OS specific and breaks the classic portability of a Java application. There is a good post on Super User that talks about this subject here.
I would suggest talking to the department that made the firewall change and see if they can allow outbound connections from normal port range.

Categories

Resources