<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div>Guys,</div><div><br></div><div>I like this idea a lot.  I hadn't thought about the concept of using a language binding to communicate with upstream proxies, but it makes sense.  Being able to purge something from an HTTP cache by simply making a "purge" call in whatever language I'm using to write my API is a win.  That said, I'm not envisioning a lot of communication going upstream in this manner.  An authentication proxy service, for example, may need to communicate with an IDM system, but should require no input from the API service itself.  In fact, I would try to discourage such communication just to avoid chatter. In cases where this can't be avoided  I would require the proxy services expose a rest endpoint so we can take advantage of it even if a binding isn't available. </div><div><br></div><div>Thoughts?</div><div><br></div><div>-jOrGe W.</div><div><br></div><div><div>On Jul 30, 2010, at 3:23 PM, Michael Gundlach wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">Hi Eric,<div><br></div><div>Well said.  Assuming I understood your argument below, I think we are actually on the same page.  Thanks for taking the time to explain your position in detail.</div><div><br></div><div>I think that you and I are in agreement if the modules that you describe are always simply bindings to another service's API.  For example, I completely agree that we should have a caching module that any layer of the stack can use as needed -- but that it should just be a language-specific binding to a memcached or similar, *running somewhere outside the binary*.  It may be on localhost, or another machine, or be a load balancer with 10 memcached servers behind it.  Similarly, any layer of the stack can use the authorization module, and authentication, etc etc, and they just facilitate calling out to the authorization or authentication services.</div>

<div><br></div><div>I think it would be a *bad* idea if the caching module was just a standalone caching library, which any layer of the stack could "strap on" as needed.  Now that program does two jobs: its original purpose, and caching.  It's more complex, and you can't scale it as precisely (you end up scaling for the slowest of the two jobs.)  If we strapped on authentication, and authorization, etc etc, now this is one complex binary that does everything.</div>

<div><br></div><div>Are we in agreement?  Modules provide language bindings to a URI endpoint but don't provide the logic itself?</div><div><br></div><div>I think my argument for "proxies" came across as if one layer of binaries should wrap the API, and everything had to happen at that point:</div>

<div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">request</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div><div><font class="Apple-style-span" face="'courier new', monospace"></font><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  v</span></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">hardware LB</span></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  |</span></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  v</span></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">proxy layer(s)</span></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  |</span></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  v</span></div><div>

<span class="Apple-style-span" style="font-family: 'courier new', monospace; ">API endpoint</span></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  |</span></div>
<div>
<span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  v</span></div><div><font class="Apple-style-span" face="'courier new', monospace">deeper...</font></div><div><br></div><div>

and I agree that that would inevitably cause us to bubble too much information up the request chain.  Your module argument is more what I had in mind, where individual services still stay simple while being able to make roundtrip calls to other services as needed:</div>

<div><br></div><div><font class="Apple-style-span" face="'courier new', monospace"># In this diagram, => means a roundtrip call</font></div><div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">r</font><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">equest</span></div>

<meta http-equiv="content-type" content="text/html; charset=utf-8"><div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div><div><font class="Apple-style-span" face="'courier new', monospace"></font><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  v</span></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">hardware LB</span></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  |</span></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  v</span></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">service A # does the absolute minimum it can,</span></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  |       # then forwards request downstream</span></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">  v</span></div>

<div><font class="Apple-style-span" face="'courier new', monospace">service B</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      => service C # e.g. authentication</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">              => cache service</font></div><div><font class="Apple-style-span" face="'courier new', monospace">              => storage service</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">                      => some database</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">  v</font></div><div><font class="Apple-style-span" face="'courier new', monospace">service D # e.g. API endpoint</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      => cache service</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  v</font></div><div><font class="Apple-style-span" face="'courier new', monospace">service E # e.g. more specific endpoint, maybe cloud servers endpoint</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      => cache service</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      => service F # e.g. authorization</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  v</font></div><div><font class="Apple-style-span" face="'courier new', monospace">deeper... # the more links in the chain, the better:</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">          # each link is a simpler piece to code and to understand.</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br>

</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="arial, helvetica, sans-serif">and what I had *thought* you meant looked like this in my head:</font></div>

<div><font class="Apple-style-span" face="arial, helvetica, sans-serif"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">request</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">  v</font></div><div><font class="Apple-style-span" face="'courier new', monospace">hardware LB</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">  v</font></div><div><font class="Apple-style-span" face="'courier new', monospace">monolithic binary that did more than one thing</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">  |</font></div><div><font class="Apple-style-span" face="'courier new', monospace">  v</font></div><div><font class="Apple-style-span" face="'courier new', monospace">deeper...</font></div>

<div><br></div><div><br></div><div>In my experience, drawing #2 is the best, and a huge reason is that I can actually explain to you what each service does.  I can tell you what inputs he expects, what outputs he expects, and the one thing that he calculates -- and you can just throw more instances of him in place to scale him.  Whenever a service has accreted too much functionality, you split his code into two new services, and put them serially in the request chain or have one call the other to do some work.</div>

<div><br></div><div>Let me know if I've misunderstood you again,</div><div>Michael</div><div><br></div><div><br></div><div><div class="gmail_quote">On Fri, Jul 30, 2010 at 3:09 PM, Eric Day <span dir="ltr"><<a href="mailto:eday@oddments.org">eday@oddments.org</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Hi Everyone,<br>
<br>
A number of us have been discussing different ways of sharing<br>
components between different projects in OpenStack, such as auth*,<br>
caching, rate limiting, and so on. There are a few ways to approach<br>
this, and we thought it would be best to put this out on the mailing<br>
list for folks to discuss.<br>
<br>
The two approaches proposed so far are a proxy layer that would<br>
sit in front of the service APIs and a library/module that would<br>
encapsulate these shared components and allow the services to consume<br>
it at any layer. The problem we are trying to solve is re-usability<br>
across different services, as well as a layer that can scale along<br>
with the service. I'm leaning towards the library approach so I'll<br>
explain that side.<br>
<br>
The basic idea is to provide a set of libraries or modules that could<br>
be reused and expose a common API each service can consume (auth,<br>
caching, ...). They will be modular themselves in that they could have<br>
different backends providing each service. These interfaces will need<br>
to be written for each language we plan to support (or written once<br>
in something like C and write extensions on top of it). Tools like<br>
SWIG can help in this area.<br>
<br>
The reasoning behind this approach over the proxy is that you're not<br>
forced to answer questions out of context. Having the appropriate<br>
amount of context, and doing checks at the appropriate layer, are key<br>
in building efficient systems that scale. If we use the proxy model,<br>
we will inevitably need to push more service-specific context up<br>
into that layer to handle requests efficiently (URL structure for the<br>
service, peeking into the JSON/XML request to interpret the request<br>
parameters, and so on). I think questions around authorization and<br>
cached responses can sometimes best be handled deeper in the system.<br>
<br>
If we have this functionality wrapped in a library, we can make<br>
calls from the service software at any layer (when the context is<br>
relevant). We still solve the re-usability problem, but in a way that<br>
can both be more efficient and doesn't require context to bubble up<br>
into a generic proxy layer.<br>
<br>
As for scalability, the libraries provided can use any methods needed<br>
to ensure they scale across projects. For example, if we're talking<br>
about authentication systems, the module can manage caching, either<br>
local or network based, and still perform any optimizations it needs<br>
to. The library may expose a simple API to the applications, but it<br>
can have it's own scalable architecture underneath.<br>
<br>
The service API software will already need the ability to scale out<br>
horizontally, so I don't see this as a potential bottleneck. For<br>
example, in Nova, the API servers essentially act as a HTTP<->message<br>
queue proxy, so you can easily start up as many as is needed with<br>
some form of load balancing in front and workers on the other side<br>
of the queues carry out the bulk of the work. Having the service API<br>
also handle tasks like rate limiting and auth should not be an issue.<br>
<br>
You could even write a generic proxy layer for services that need it<br>
based on the set of libraries we would use elsewhere in the system.<br>
<br>
Having worked on systems that took both approaches in the past, I can<br>
say the library approach was both more efficient and maintainable. I'm<br>
sure we can make either work, but I want to make sure we consider<br>
alternatives and think through the specifics a bit more first.<br>
<br>
Thanks,<br>
-Eric<br>
<br>
_______________________________________________<br>
Mailing list: <a href="https://launchpad.net/~openstack" target="_blank">https://launchpad.net/~openstack</a><br>
Post to     : <a href="mailto:openstack@lists.launchpad.net">openstack@lists.launchpad.net</a><br>
Unsubscribe : <a href="https://launchpad.net/~openstack" target="_blank">https://launchpad.net/~openstack</a><br>
More help   : <a href="https://help.launchpad.net/ListHelp" target="_blank">https://help.launchpad.net/ListHelp</a><br>
</blockquote></div><br></div><pre>Confidentiality Notice: This e-mail message (including any attached or
embedded documents) is intended for the exclusive and confidential use of the
individual or entity to which this message is addressed, and unless otherwise
expressly indicated, is confidential and privileged information of Rackspace.
Any dissemination, distribution or copying of the enclosed material is prohibited.
If you receive this transmission in error, please notify us immediately by e-mail
at <a href="mailto:abuse@rackspace.com">abuse@rackspace.com</a>, and delete the original message.
Your cooperation is appreciated.
</pre>
_______________________________________________<br>Mailing list: <a href="https://launchpad.net/~openstack">https://launchpad.net/~openstack</a><br>Post to     : <a href="mailto:openstack@lists.launchpad.net">openstack@lists.launchpad.net</a><br>Unsubscribe : <a href="https://launchpad.net/~openstack">https://launchpad.net/~openstack</a><br>More help   : <a href="https://help.launchpad.net/ListHelp">https://help.launchpad.net/ListHelp</a><br></blockquote></div><br></body></html>