Saturday, October 31, 2009

Recipe 16.14. Automatically Discovering DRb Services with Rinda










Recipe 16.14. Automatically Discovering DRb Services with Rinda




Credit: James Edward Gray II



Problem


You want to distribute Ruby code across your local network without hardcoding the clients with the addresses of the servers.




Solution


Using Ruby's standard
Rinda library, it's easy to provide zero-configuration networking for clients and services. With Rinda, machines can discover DRb services without providing any addresses. All you need is a running RingServer on the local network:



#!/usr/bin/ruby
# rinda_server.rb

require 'rinda/ring' # for RingServer
require 'rinda/tuplespace' # for TupleSpace

DRb.start_service

# Create a TupleSpace to hold named services, and start running.
Rinda::RingServer.new(Rinda::TupleSpace.new)

DRb.thread.join





Discussion


The RingServer provides automatic service detection for DRb servers. Any machine on your local network can find the local RingServer without knowing its address. Once it's found the server, a client can look up services and use them, not having to know the addresses of the DRb servers that host them.


To find the Rinda server, a client broadcasts a UDP packet asking for the location of a RingServer. All computers on the local network will get this packet, and if a computer is running a RingServer, it will respond with its address. A server can use the RingServer to register services; a client can use the RingServer to look up services.


A RingServer object keeps a service listing in a shared TupleSpace (see Recipe 16.12). Each service has a corresponding tuple with four members:


  • The literal symbol :name, which indicates that the tuple is an entry in the RingServer namespace.

  • The symbol of a Ruby class, indicating the type of the service.

  • The DRbObject shared by the service.

  • A string description of the service.


By retrieving this TupleSpace remotely, you can look up services as tuples and advertise your own services. Let's advertise an object (a simple TupleSpace) tHRough the RingServer under the name :TupleSpace:



#!/usr/bin/ruby
# share_a_tuplespace.rb

require '
rinda/ring' # for RingFinger and SimpleRenewer
require '
rinda/tuplespace' # for TupleSpace

DRb.start_service
ring_server = Rinda::RingFinger.primary

# Register our TupleSpace service with the RingServer
ring_server.write( [:name, :TupleSpace, Rinda::TupleSpace.new, 'Tuple Space'],
Rinda::SimpleRenewer.new )

DRb.thread.join



The SimpleRenewer sent in with the namespace listing lets the RingServer periodically check whether the service has expired.


Now we can write clients that find this service by querying the RingServer, without having to know which machine it lives on. All we need to know is the name of the service:



#!/usr/bin/ruby
# use_a_tuplespace.rb

require 'rinda/ring' # for RingFinger
require 'rinda/tuplespace' # for TupleSpaceProxy

DRb.start_service
ring_server = Rinda::RingFinger.primary

# Ask the RingServer for the advertised TupleSpace.
ts_service = ring_server.read([:name, :TupleSpace, nil, nil])[2]
tuplespace = Rinda::TupleSpaceProxy.new(ts_service)

# Now we can use the object normally:
tuplespace.write([:data, rand(100)])
puts "Data is #{tuplespace.read([:data, nil]).last}."
# Data is 91.



These two programs locate each other without needing hardcoded IP addresses. Addresses are still being used under the covers, but the address to the
Rinda server is discovered automatically through UDP, and all the other addresses are kept in the
Rinda server.


Rinda::RingFinger.primary stores the first RingServer to respond to your Ruby process's UDP packet. If your local network is running more than one RingServer, the first one to respond might not be the one with the service you want, so you should probably only run one RingServer on your network. If you do have more than one RingServer, you can iterate over them with Rinda::RingFinger#each.




See Also


  • Recipe 16.12, "Creating a Shared "Whiteboard"

  • Recipe 16.18, "A Remote-Controlled Jukebox"

  • Eric Hodel has a Rinda::RingServer tutorial at http://segment7.net/projects/ruby/drb/rinda/ringserver.html













No comments:

Post a Comment