Friday, May 30, 2008 10:07 AM
codingsanity
Discovery Service - Part 1
Metadata Exchange mechanisms such as WSDL are all very well and good, but they fulfil one part of the automatic discovery experience. If you look at WCF a service consists of three parts:
- Contract
- Address
- Binding
So, Metadata Exchange helps you figure out the Contract if you're given the Address and sometimes the Binding. All very well and good for assisting us developers get running in using a service. However, how about a scenario where you already know the Contract but you need to figure out the Address and/or Binding? In other words, what about most deployment scenarios? How can you discover where to find the server? One way would be to have a fixed location which your client connects to in order to query it for server information. However, if you can hard-config this repository, why can't you just hard-config the service location too? Setting the service location in the client configuration file seems to be a fairly common approach.
Another option would be to capture the service location during installation or when the application first runs. This is fairly common as well. However, this assumes a level of technical ability and knowledge on the part of the installer/user that may not be justified. Also, what happens if the service location changes?
UDP Discovery
So, what we would ideally need is a mechanism to help enable the various discovery options. Happily there is a technology ideally suited for discovery, and it's called UDP. UDP is a networking technology fairly similar to TCP/IP. Unlike TCP/IP it does not support connections, each message is sent fire-and-forget. There's no guarantee of delivery, and if your message is broken into multiple packets there's no guarantee what order they'd appear in. This makes UDP a bit hit and miss for most business applications, which is why it's very rarely used by most developers.
However there are two really cool features of UDP: broadcast and multicast. Broadcast allows you to do is to send a message to all the machines on the same subnet, which is fine for discovering the machines near you, but not so good to find servers, which are usually on a different subnet. Broadcast also has the downside that it sends a lot of traffic, one message to each machine on the subnet. Multicast is different. Unlike with broadcast, you have to join a multicast group, and then messages are routed to the machines in the group. Since this is only the machines interested in the message, the number of messages flowing across the network is smaller.
So, if we're looking for machines on our network, UDP would seem to be an ideal mechanism. We'd want to keep the messages small so as to avoid any issues with packet ordering. Now, if we're publishing generic information about various services, we don't really know how much information we'd be sharing. So ideally, we'd want to avoid sharing this generic service information across UDP.
What we can easily share is the location of a more reliable service from which this service information can be gleaned.
So the next question is how the whole UDP thing should work. A common approach is to have the servers broadcast their information at a fixed interval. This has the advantage of simplicity, but it isn't terribly elegant. Even ignoring the fact that the servers are often sending out data that no-one wants, the client machine would sometimes have to wait a while until the server next send out it's data.
So, whilst a bit more complex to code, it makes a lot of sense for the client to send out a request, and the server to respond.
Review
So, what we're looking at here is a three-phase discovery mechanism:
- Client sends out UDP request
- Server responds with address to discovery location
- Client connects to discovery location and retrieves data
So, the client UDP request would be fairly simple, some kind of "Please give me service information" message such as "get\services". The server response would also be relatively simple, an address e.g. "net.tcp://myserver:20231/Discovery". I'm going to assume that we're not going to get into complex binding scenarios such as security and transaction information. This is simply a location to get more information, so we can keep it to the default bindings.
The next question to ask is what information the server should share about the services it exposes? Well, the address of each service would be an obvious starting point. However, what else? Binding information? But that's WCF specific, and who said the services being exposed are WCF? So it probably makes sense to simply allow each service to have a set of properties: name/value pairs that contain contextual information about the service.
In Part Two we'll start looking at how we're going to implement all this.
Filed under: Code, WCF