<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Apr 25, 2013 at 4:06 PM, Eric Windisch <span dir="ltr"><<a href="mailto:eric@cloudscaling.com" target="_blank">eric@cloudscaling.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">><br>
> What about making all of those arguments except topic part of the constructor for a Connection, and just instantiating more than one of them to talk to different services?<br>
</div>If we can figure out what they are, or how to make this per-driver and store them in a reasonable way - I think we might be on the right path.<br>
<div class="im">><br>
><br>
><br>
> It seems like the host and port options for rabbit and qpid map to the same values for the matchmaker, don't they? The fact that the actual message doesn't go to the matchmaker is an implementation detail of ZMQ that it can hide.<br>

</div>The matchmaker is pluggable. Some matchmakers use a flat file or local database, not a network service (although this may practically become a requirement for a network service, in the long run?).  There may not be a single IP or DNS based endpoint for this, it may be multiple hosts, or a multicast address for communications, etc. I think it is premature to suggest that all the backends will have a host/port/user/password associated, and that other configuration fields won't be necessary.<br>
</blockquote><div><br></div><div style>OK, I was thinking of something like this:</div><div style><br></div><div style># in openstack.common.rpc </div><div><br></div><div style>def make_connection_factory(config, rpc_driver_name):</div>
<div style>    driver = load_driver(rpc_driver_name)</div><div style>    conn_factory = driver.make_connection_factory(config)</div><div style>    return conn_factory</div><div style><br></div><div style># in the driver</div>
<div style><br></div><div style>class ConnectionFactory:</div><div style>    def __init__(self, config):</div><div style>       # know how to find useful configuration settings for the driver, </div><div style>       # like the amqp server or the location of the matchmaker.</div>
<div style><br></div><div style>    def __call__(self, host):</div><div style>       # driver-specific logic for combining "host" with the values pulled in __init_</div><div style>       # to have enough connection parameters</div>
<div style>       return Connection(those_parameters)</div><div style><br></div><div style># in the app</div><div style><br></div><div style>cf = make_connection_factory(cfg.CONF, cfg.CONF.rpc.driver_name)</div><div style>
c = cf(host)</div><div style>response = c.call(topic, message)</div><div style> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Also, I think that at least optionally, the matchmaker might become tied to the AMQP drivers. That might be a good thing, at least in leveling the field. The more we talk about message encryption, and in some models, even for signing, we might find having the matchmaker advantageous. TBD.<br>

<div class="im">> Right, it seems like the host portion needs to be passed as a separate argument and the AMQP drivers can combine it with the topic, instead of going the other way around.<br>
</div>I'm suggesting we let "service.host" be a valid topic, but *also* pass the host variable into the call/cast so that drivers can do what they will with it. It won't be *necessary* for the topic to be called "service.host", but it won't be illegal.<br>
</blockquote><div><br></div><div style>I'd rather not mix and match. If the host value is just a way to limit the recipient of the message going to topic (or to have the sender choose instead of message broker), then the fact that we define a separate queue for that is an implementation detail of the driver, just like the fact that the ZMQ driver doesn't have a broker, but is always communicating point-to-point.</div>
<div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
> > > For ZeroMQ, a control_exchange is effectively a zmq_port *AND* its<br>
> > > associated matchmaker, which is pluggable. Plugins usually will have<br>
> > > their own host/port/auth. The MatchMaker basically maintains a mapping<br>
> > > of topics to consuming peers. Technically, we could lookup all topics<br>
> > > here, even "compute.host" topics, but we can circumvent a global<br>
> > > lookup by sending messages directly to "host".<br>
> ><br>
> ><br>
> > Understood (because well explained, thanks :)<br>
><br>
> How does the ZMQ driver know where the host is without asking the matchmaker? Is that "host" value assumed to be resolvable via DNS?<br>
</div>Either because it infers it from the call/cast command (presently by inspecting the topic - which is no longer a valid source of authority), or if there is no host to be inferred, by looking up in the matchmaker.<br>

<br>
The host itself is whatever is passed as CONF.rpc_zmq_host, which MUST match whatever Nova's CONF.host is set to. This defaults to the FQDN, such that DNS resolution is required. In *practice*, we override both of these variables to the system's IP address (for the interface on which messaging should happen)<br>
</blockquote><div><br></div><div style>OK, so host is intended to be the sort of thing you could pass as part of an address when creating a socket. If we make the host argument to ConnectionFactory.__call__ optional then the topic values can be consistent (i.e., not include the host) and the caller can still control who receives the message by constructing the Connection appropriately. That way the semantics of the call are controlled by the right arguments. The topic says "the message is about this" and the host limits the "audience" that gets the message.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">><br>
><br>
> > > Perhaps an rpc-abstraction level concept of a "cell" or "project" is<br>
> > > needed? That would be an identifier encompassing all the connection<br>
> > > details (i.e. host/control_exchange, zmq_port/matchmaker), however<br>
> > > such may be defined for the driver being used?<br>
> ><br>
> ><br>
> > That sounds like a good idea to me. That's what I called "connection" in<br>
> > my previous mail actually. This may be just an abstract class<br>
> > implemented by each driver in its own way.<br>
><br>
><br>
> What defines a "cell" for RPC? Just the alternate host and port for rabbit, qpid, or matchmaker? If so, then the caller just needs to create a new Connection with the right settings, and we don't need to have the concept of "cell" leak into the RPC library API at all. It's there now because we're using a global connection object, but sometimes want to talk to something different. If we stop having a global, the awkwardness will go away and the API can be simpler.<br>

</div>You have this basically correct. Part of the problem is that we don't have that abstraction currently, and the parameters passed from the cell code for host/etc are really ill-matching for the MatchMaker requirements… and confused with the unclear separation of zmq_port and control_exchange for ZeroMQ -- and a question if ZeroMQ messages should, or should not, be brokered through to child cells (which may be necessary for some network security purposes, but unnecessary for queue scaling)<br>

<br>
What I'd like to have, ideally, is the cell configuration essentially reconfigure the ZeroMQ settings as necessary, per the deployer's preference. A brokered-to-cell solution wouldn't be available, at least not presently, but such a design would allow that to be a possible feature addition/request, should it be requested.  (I also don't want to bike shed or overdesign too much on what people *might* do or want down the road)<br>
</blockquote><div><br></div><div style>Given the fact that we have completely different calls right now, it seems like the caller must already know when it is talking to a cell. Instantiating a separate Connection for those cases should be fine, as long as we can find the matchmaker for that cell using the configuration data passed to make_connection_factory(). Maybe we need a cell_name argument to that call?</div>
<div style><br></div><div style>Doug</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Regards,<br>
Eric Windisch<br>
<br>
<br>
<br>
</blockquote></div><br></div></div>