|
by Daniel Brookshier October 24, 2002 -- I discuss JXTA and Peer-to-Peer (P2P) computing every day with developers from all over the world, and my key message is very simple: "JXTA saves money." Without a reliance on servers and their infrastructure, the return on investment to build any JXTA application is phenomenal. The inevitable first question I am asked, however, is: How do I write software without a server? The software patterns for web development and client-server technologies are not easily applied to P2P. In this article, I will introduce the Resolver, a P2P concept that should be comfortable for client-server developers. Although unknown to many JXTA developers, the Resolver is a core JXTA protocol that is similar to the publish-and-subscribe pattern in the client-server world. JXTA, P2P, and the ResolverJXTA and P2P are new, so let's quickly review what they are. P2P is often described as the sharing of processing, storage, and services between personal computers. More specifically, P2P favors the distribution of responsibility and resources, rather than centralizing them on a server. JXTA is a specification that describes P2P protocols and services for general P2P computing. The JXTA APIs that implement the specification are designed with a high level of abstraction that hides much of the drudgery of P2P. JXTA connects PDAs, cell phones, desktops, and laptops into an addressable network of resources and services. JXTA also solves many key problems of P2P computing, such as firewalls, NAT devices, and DHCP, which prevent simple, direct connections between computers. Let's get a little more specific now and talk about message delivery. JXTA has two primary messaging systems: Pipe and the Resolver. There is quite a bit of literature on Pipes, which are similar to sockets, but much more abstract and a bit harder for client-server developers to grasp. The Resolver is not as widely known, mainly because it is used as a core messaging system in the JXTA platform for routing and searching. The Resolver follows a query-and-response pattern that is very useful and thus the focus of this article. What's a Resolver?A Resolver is a simply query-and-response protocol. The client sends an XML message tagged with a name and a payload. The target peers look for the name of the message, process the payload, and return an answer if one is required. This is a broadcaster-and-listener pattern of communications. The software pattern is similar to a publish-and-subscribe, except that the scope of messages is limited by a secondary mechanism called peer groups, rather than a mechanism that routes messages based on a subscription request. A good metaphor for the Resolver is TV broadcasting. A TV only processes the signal from the channel it is currently tuned to. In the same way, a peer only processes a message of a type it is looking for. The Resolver also works in a mode we call propagation. Propagation, in P2P terms, is the forwarding of messages from computer to computer. Propagation is similar to broadcasting, except that each computer may forward the message to others, rather than everyone listening to the same message all at once. Propagation is important because protocols like IP Multicast only work in specific networks and usually not between local area networks. To use the TV broadcasting metaphor again, propagation is similar to forwarding a locally broadcast TV signal to a cable company that converts and forwards it to a cable signal, to reach viewers who don't have antennas to receive the original signal. The response to a Resolver query takes the best path back to its source (rather than broadcasting). This is possible because the originating peer ID is included in the query message. The JXTA router discovers the best route back and sends the message. The responses to a Resolver query can come from multiple sources, or none at all. This may sound strange to the client-server programmer. In fact, such unreliability is reasonable and, in most cases, actually desired in P2P. As an example, if you sent a query to 1000 computers, you might only want one reply from one peer. The reality in a P2P network is that a peer may be a laptop that is not currently connected. So you either try the query later or rely on a replication scheme where the data on the laptop is also on several other peers. Responses may therefore come from several peers, but the odds are greater that you'll get an answer. Finally, there is the issue of message scoping. With thousands of peers, you need a way to limit the messages to just peers that are participating. For example, if you're looking for an entry in a distributed database, you only want to contact peers that have pieces of that database. You do this with a peer group: Only those peers that belong to the peer group the message originated in will be queried. This also allows you to create multiple peer groups to limit messages further; peers that support specific types of data in the database belong to specific peer groups. To summarize, a peer sends a query message that is propagated to the listener peers. When the listeners reply, the message is sent back to the originator for processing. Messages may not reach all listeners and not all listeners may respond. Odds are improved that a query will be answered if several peers are scattered around the network with similar data. If queries are to be made into networks without replicated data, the application must be designed to repeat queries over time. Searching for AnswersWhat types of applications are suitable for the Resolver? We can begin with searching. The discovery mechanism in JXTA uses the Resolver to search information about the network of peers and their services. It's simple to do similar work with a host of other information. If you are already familiar with JXTA, you know that the discovery system lets you publish and search for information. The information is represented as XML documents, and the discovery service allows a simple tag-value search. One mistake many JXTA developers make is that they create advertisements for items to search, and publish the data with the advertisement. This is fine for highly available data of relatively small size. But imagine what would happen if you created and published advertisements for every document on every person's PC. Since advertisements are propagated to multiple rendezvoux (computers that volunteer to store advertisements and accept search requests), each rendezvous might need to be a massive server to hold all the advertisements, plus the document data. The goal instead should just be to direct traffic to the PC that has a particular document type. Data needs to be on the edge of the network. This means that if it's your data, you probably should handle any query about it and be the primary storage. Should someone else copy the information, they too become a manager of the data and thus your backup. In a P2P network, this is OK; the data becomes more available as more peers manage the same data. A Simple PingTo demonstrate the Resolver, we'll now implement a simple broadcast ping. Rather than designate a specific computer, we'll propagate the message to ping any peer that is listening. Here's what we're going to cover:
Starting JXTAFor JXTA to work, it must first be started, so it can start a few threads and get ready to process messages. Internally, JXTA also needs to discover and contact other peers to begin the process of becoming an active member of the JXTA P2P network.
Starting JXTA is actually quite simple: you just need to access the net peer group object. Once this object exists, the platform is operational. Here is the code to get the net peer group:
Once you have the peer group, you have context for all the services in the group. These services include discovery, message Pipes, group membership, and others. In our case, we are interested in the Resolver service. However, we need to avoid the net peer group because its scope is too large; we just need a group that is specific to our application and the scope of our requests. So the next step is to create our own peer group. Peer Groups and the Resolver
The peer group is very important to the Resolver. Peer groups limit the messaging delivery to only the peers in the same group. As you can imagine, this helps isolate the name space we will use to identify the handler. Because of peer group scoping, two peers with the same Resolver message names -- but in different groups -- will not see each other's messages. I have supplied a utility to create and join a custom peer group to do this for you (please refer to the site referenced at the end of this article for the source and documentation on the
We create a Set Up the Query and Response ListenerThe query handler interface is very simple. There are just two methods, one for processing the query and the other for the response. Most peers will handle queries as well as responses (I'll talk about this client/server duality later). Each method takes its appropriate object, which maps to the XML in the Resolver protocol.
The
The
In general,
Here is an example implementation of the query handler. In this example, we simply add a time stamp to the query and send it back to the originator. The only other item of note in this class is
Let's look at the implementation of the
The
The
This is all rather simple. In more complex applications you can use more of the query message, like the sequence number and the certificate. The sequence number helps to discover the order of the query and match it with the response, and the certificate is used to validate the message. You could use a library like Castor to convert your Java objects to and from XML and avoid most of the direct manipulation of XML. Registering the ListenerNow we can use our application peer group to register the handler. We get the Resolver from the group, and then register the handler with a string identifier that will match the identifier used when sending queries.
Sending a MessageSending a message is relatively simple. The whole thing boils down to the following:
You can use In the following example code, we create a query message with a timestamp. Once the message is built, the Resolver sends it to all the peers listening to the message.
Why Clients are Servers
Now that you've seen a simple example, you might wonder why the One of the mind-expanding ideas about P2P applications is that peers are both servers and clients. The key reason is the distribution of resources. Let's look at an example. Imagine an application for displaying maps. Your peer would contain the local areas that you travel in from work to home, and to visit friends and businesses. Someone wanting to drive through your neighborhood would query your peer for the maps you use. Conversely, if you wanted to drive somewhere else, you would ask for map sections that other people host because of where they live and work. Everyone acts as a client and a server, hosting the information they use the most. In the map example, you use your peer to serve map data to yourself and to others interested in your area. The client side requests information for a route and displays it. The server side processes requests and either returns cached data, or requests data from others. Note that there are many copies of the same pieces of the map. For example, your coworkers will have copies of the maps in the neighborhood around your business. This increases the odds of locating a map section, even though several computers may be disconnected from time to time. If you are using a Resolver, you would both make requests and accept queries. In this example, the response should be used only to locate pieces of the map, but not to transfer the data. A Pipe should be used to transfer data from one of the responding peers. The key reason is that you could receive several replies when only one is required. By using a Pipe, only one peer is connected rather than all that responded. The Pipe advertisement to connect to the peer with the map should be passed back to the originator in the query. The query peer can then open the Pipe and request a copy of the map. Watch It WorkClick here to see the rest of the code and an ANT script for running the program. Look at the code and launch it on a couple of computers, or follow the instructions for running multiple JXTA applications on a single computer. If you change any of the functionality, make sure you use a different root application group ID to avoid stepping on others running the original example. Remember that the group ID and the Resolver name are the only methods used to filter messages. Resolver as a PipeThe Resolver as described here will likely appear in a future release implemented as a Pipe (I am already experimenting with a prototype). The code you write based on this article should still follow the same pattern and be simple to convert. The key difference will probably be that a Pipe ID (instead of a string) will be used for registering Resolver handlers. The Pipe ID will allow the subsystem to locate all of the peers participating in the same Resolver network and thus improve efficiency. The Resolver is going to look much different in the next release; for one thing, it will use a more structured organization of rendezvous peers in order to minimize query propagations. For example, the propagation could be a single message moving from peer to peer (similar to an agent) until a response is returned. The current system "floods" a large number of peers with the same query, which can cause a large number of duplicated responses. A flexible propagation system can greatly reduce the problems of flooding and can be tuned for specific applications. See the resources listed under "See Also" (below) for more about the future of the Resolver. SummaryThe Resolver is a powerful P2P query system that is easily understood by traditional client-server and web developers. Similar to publish-and-subscribe, the broadcast query pattern of the Resolver is one of the more important techniques in P2P. Nevertheless, be careful how you use it. Like any other application, manage your resources. JXTA may have reduced the need for a server, but it has not done away with good software architecture and design. Let me emphasize that the Resolver is just a small part of JXTA. Come to http://www.jxta.org and look around. There's a lot more information about JXTA and many open-source projects based on the technology. We also have several very active email lists where you can ask questions about JXTA. And finally, JXTA is new, so email me and let me know about the JXTA applications you're working on. JXTA is a community and we need to work together. About the AuthorDaniel Brookshier is the lead author and editor of JXTA: Java P2P Programming. He is a hands-on Java architect concentrating on JXTA, J2EE, Swing, and mentoring. Daniel is an independent consultant with clients in multiple industries, including such well-known companies as Boeing, Ericsson, and Wal-Mart.
See Also
The JXTA web site
Code for this article and other related info
Scalability overview design proposal for JXTA
The author's web site
Future plans for the Resolver | |||||||||||
|
| ||||||||||||