JOSH SZMAJDA: All right. You guys ready to talk about SOA? Woo! I'm Josh. Hi. How you doing? I'm the CTO at Optoro. We make software for retailers. Help them deal with their stuff at scale. I'm working on a project called RACK-AMQP. RACK-AMQP is a collection of different projects, including an RC, some client libraries, and most notably, Jackalope, which is a new Ruby web application server, like Unicorn, Passenger, Thin, or, or anything like that. Except that it's special-purpose. It's for service-oriented architectures. And it doesn't actually speak HTTP at all. So. Why am I doing this crazy thing? Well, my app drove me to it. My app is huge. It's really complicated. This is kind of a services diagram of my app. Or where we'd like to go with it. There's over three-hundred and fifty models in one Rails application. The test suite takes over eight hours. It's kind of a headache. You could put it. So we decided the way to move forward with it is to break it up into smaller applications that work together. And, of course, that means SOA. Now, I mean, SOA is really wrapped up in a lot of pretty awful baggage, when you come down to it. SOA, you think about enterprise service buses. You think about strict interface definitions. Versions. I mean it's a lot of complexity that you have to worry about. Extra load balancers. More configuration. More distributed tracing and monitoring. I mean, it's a, it's a real pain. So I, I hate SOA, right. It makes me feel like this. So, but when you get down to it, SOA is actually not all of that. SOA is really just independent actors communicating. They're working together to get something useful done. So, really, SOA can mitigate complexity by enforcing simplification. Each service only has to think about its own little bubble. It only has to worry about its little component. And it doesn't have to think about anything else that goes on in its entire system. You can let your system architect worry about what's going on across the whole thing. All you have to do is pay attention to your one little service and you can be pretty happy. So, when you get down to it again, SOA is really just independent actors communicating. Now that communicating bit is important. How they communicate actually determines how your application behaves. And the kinds of communication you can use impacts the kind of application you can write. So, the typical communication pattern that we're most familiar with as programmers is sort of direct messaging. I am an object. I can send a message to my friend. My friend is gonna give me back a response. It's very normal. It's what, in fact, we use all the time with HTTP. But when you think about it, what we actually want to do is be able to send different kinds of messaging structures. We want to publish that something happened in my system and have people subscribe to that event and take some interesting action. It's all about decoupling. I don't have to know about my neighbor anymore. I just need to know that I did something, and then somebody else might care that, oh, you did something. That's great. Let me do something about that. But again, like I said, let me. We're Rails developers. We're used to writing web applications. We speak HTTP all the time. HTTP allows us to do direct messaging, so that's what we tend to do. I'd say most SOAs out there, when they get off the ground, they start building web applications that speak with each other through HTTP. It's what we're familiar with. But what would we actually like our transport mechanism to be? We want it to be, you know, data structure independent. HTTP specifies that there be a body, but it doesn't specify the format of the body. We want it to be fast. We want it to be open, transparent, understandable, clear. You know, debuggable. Observable. And flexible. So, is HTTP all of those things. We also need, not only direct request response type of messaging, like RPC, but we also need pub, subscribe, and broadcast. Additionally, we don't need more load balancers. More SSL certificates. Distributed logging. Trying to figure out what's going on in this service over here versus that one over there. It's a nightmare. And, you know, looking up the various services in your system, it's a pain. So, again, I mean, HTTP, you know, it has, it is blind. It's fast. It's open, clear, it's well-understood. It's what we know. It's really great for RPC. It's a better alternative. And that's AMQP. AMQP is blind, also. It doesn't care what data you're transmitting across it. It's extremely fast. It's an open system. It's great for all messaging pattern. Not just direct messaging, but pub/sub, and queue-based messaging. It's centralized, which in terms of a service-oriented architecture is very beneficial, in that you have one point to manage, one point to pay attention to everything at. And the only issue is that it's not what we're familiar with. It's not what we know. You know, again, we're web developers. We're not AMQP developers. At least not the most of us. So it's a challenge. So the RACK-AMQP project that I'm working on is really designed to make AMQP simple. We are trying to introduce as few opinions as absolutely necessary in order to make this possible. And to give you a stepping stone into the world of AMQP where you can start to integrate more advanced concepts into the system, without having to relearn your entire world. So it also lets us continue to build what we know. Because it's built on Rack, you know, we're web-developers. We can continue to use the web concepts that we're familiar with. We can developer locally on our web machines using the systems that we're comfortable with. And then when we deploy, we simply deploy it to Jackalope, instead of to Unicorn or Passenger or whatever, and it's magically in this world of AMQP. So. How does that work? Well, let's look at AMQP a little bit more in depth, first. So AMQP is the advanced messaging queue, message queueing protocol. It is an open standard. It's developed by Oasis, which is an open standards body. It, again, like I said, uses a centralized distribution pattern. That centralized distribution pattern allows you to do the various kinds of messaging that are really handy for us. The pub/sub and the other interesting thing. This implies that we have a broker in the center that all of our services connect to and transmit messages through that broker. And that broker can make intelligent decisions about how to route those messages. AMQP messages themselves, they have headers and bodies, just like HTTP. There are well-known fields, like content type and priority, in this case. And we can actually leverage the conventions that we understand from HTTP to pull AMQP into the world. So AMQP, like I mentioned, has these headers and bodies. It has well-known fields. And HTTP essentially has headers and bodies and also well-known fields. So we can essentially emulate HTTP over AMQP without too much trouble. And, again, the AMQP supports the RPC messaging pattern, which is what HTTP is. So, one of the parts of the project is the AMQP HTTP RC, which, it simply does as little as it has to to define the structure. It's just a documentation on how we're doing the mapping. One of the other goals is that we want to make inner-operability with other languages and other platforms really easy. So having an RC will allow it, allow us to have just a central document to refer back to in constructing other servers. So let's look at HTTP a little bit more in-depth. How does HTTP work? Well, you know, when we send a request, we send a specific request to a server, to a, you know, specific IP address and port. And we get back a response. And, of course, the request has things like the HTTP verb, the path, headers, the bodies. And the response comes back with a response code. It's all stuff we're familiar with. So all we had to do is map that into AMQP terms, which is essentially what we've done here. And this is just a reference for just a few of the things that we're doing. Like content type. There's already a content type header in AMQP, so we just reuse that. Some things didn't make sense. Like the protocol for example. In HTTP you've got HTP or HTPS or HTTP plus dev or whatever. But with AMQP, your protocol's already negotiated when you connect to the broker. So it doesn't really make sense for us to worry about that in the messages we're passing around the system. The host name becomes, essentially, the routing key. The queue target that we're sending to in AMQP. And it makes it really simple. So, this looks like this, essentially, in code. This is an example of how you could write a client that speaks AMQP, HTTP. You create a call-back queue. We'll get back to that in one sec. You publish a message that looks like an HTTP message to the target queue. And then you wait for a response. Now, the callback queue is actually a really important thing here. AMQP is a hundred percent queue based. It's all asynchronous under the hood. But, you know, we want to write a synchronous system. HTTP is synchronous. I send a request. I wait for the response, or receive the response and move on. So, to do that in AMQP, we create a respond queue that we are going to listen to in the broker. It's an anonymous queue. There's a great convention. We're doing this in AMQP. It's very easy. So we create a response queue, we get the name of that queue, and then as part of the message we send to our target, we say, here's the response queue to reply back at. And then we simply wait for the response on that call-back queue to come back. So that lets us get the synchrony that we're familiar with, that we need, with HTTP style programming, while still having an asynchronous system under the hood. RACK, of course, we're all using RACK today. Even if you're not familiar with it. RACK, of course, is what runs all Ruby web application servers. Turns out that RACK actually doesn't care about HTTP. All that RACK really defines is that you had defined a call method that receives an environment, which is basically a hash, and it responds back with a three-element array. The HTTP response code, headers, and the body. That hash doesn't actually have to be anything but a hash. It just has to look like an HTTP environment. So emulation was actually pretty simple. So this is basically how it looks. We subscribe to a queue on the server, and then for every message we receive back for that queue, we unpack some things into variables. We create what looks like the HTTP environment and we have the request method and query string. If you ever wrote CGI way back in the day, this might look familiar to you. And then we essentially pass that environment onto our RACK application, receive the response from the RACK app and then publish that back to the response queue. So this is what Jackalope is doing for us. Jackalope is emulating HTTP for our RACK applications. And it just works. I'll show you a demo at the end. You don't have to modify your code at all. You can just simply deploy to it, and it's speaking AMQP instead of HTTP. So that's it. We're done. We can go on vacation, right? Well. I didn't talk about how to actually put this in production, other than just use Jackalope. So you have to choose a broker in AMQP. So what we're using is RabbitMQ. RabbitMQ is a well-known AMQP broker. If you're doing any AMQP you're probably using RabbitMQ, most likely. It's used by giants out there. I mean, Google, VMWare, NASA. All these people are using Rabbit pretty heavily. It's extremely scalable. It's fault-tolerant. It's distributable. And it's secure. It does everything you'd ever want. And it also gives you a really great management console. We can go in and see what's going on in your system. Like I mentioned, the distributed logging we saw in the, in the last talk, if you were here for that, trying to get an idea of what's going on across your system can be challenging. Rabbit doesn't tell you everything you'd want to know, but it at least gives you an idea of what queues are being used. Their depths at the point. The kind of information that can help you get, at least get a handle on it. Additionally, you're gonna have to think about how you talk to the real world. I mean, AMQP is all well and good behind the scenes, but how do I continue to interact and serve my clients that I actually care about, to the point of getting paid, right. So this is the architecture we typically use at Optoro. We have our Rabbit server in the middle, and all the various services sitting on Jackalope that talk to Rabbit. And then additionally we have one or more API services that are continuing to be deployed on Unicorn, in our case. They talk to the outside world and internally translate the, the needs through AMQP and the rest of the system. One of the things we actually published for each of our services is a client gem that kind of isolates the worry, the worry about exactly which transport we're using away from the consumer, the API here. So it actually is, is really simple. And so the way that we do that is we typically have been using HTTParty for our HTTP communication needs. So we wrote, as one of the other projects part of RACK-AMQP, is AMQParty, which is just a API-compliant version of HTTParty. So we can actually just drop in the AMQParty constant in place of the HTTParty constant, and you can see down below, that transport variable, we typically configure that at boot time to be either HTTParty or AMQParty. And everything, again, just works. We change the, the url a little bit, too. But we do that all part of the, part of this setup for each server. For each client. Of course, if you don't want to use HTTParty, some people like the various other options that are out there, we also are publishing RACK-AMQP client, which is what H, AMQParty is built on. It, it's a very simple API. You get a client, you tell it which Rabbit to connect to. You send a request to your target queue with your uri as part of it, with any, you know, your HTTP method and all that. You get back your response. It's synchronous. It's simple. It's actually built on Bunny, which is a really great AMQP gem out there, and that also is very easy to use. Additionally, we're publishing a sample SOA using Rails. It's a work-in-progress at the moment. BUt the userland and userland_client are mostly built as, you can see where things are at the mo- at the current state. It kind of gives you an idea about how we think about SOA at Optoro, and how you might be able to use Jackalope and the RACK-AMQP project in your own projects. So userland is a, is Rails service that essentially publishes a user's concept out into the world. And then userland_client is a gem that consumes the userland service and interface uses the userland gem to talk to the userland service. And so then, you know, how fast is this? Well, there's this bench mark I've got. I'll show you it in just a sec. The only weird thing we have to do here is tell AMQParty which Rabbit to talk to, and you kind of saw that in the, in the client gem a little bit, so that's a little bit of setup we do. Again, like I said, when we make the decision about which, whether HTTParty or AMQParty. So we tell it which Rabbit. And then, inside, we, five hundred times, request this JSON using AMQParty and then five hundred times request the same thing using HTTParty. So here, I'll show you that in, in use. Let's see. OK. Let's make this big. All right. So here I'm gonna boot the app using Unicorn. So Unicorn is listing on port 8080. Wow. That's really big. Trust me, it's 8080 there. I'm gonna boot the same map using Jackalope. The only difference I have to do to boot the app is I have to say with the right queue name, so it's going to listen to the test dot simple queue. So there it is running. And then down here I'm gonna starty the bench mark. And like I said, it's gonna five hundred times hit each service. What it actually does is hit each service three times, just to make sure that it's warm, and then it can go through and hit it all the way through. And there we go. So you can see, it's two point nine seconds total to do five hundred AMQP requests, and three point six seconds total to do five hundred HTTP requests. I was actually surprised when I got this result. Jackalope is beta. I mean, it's, we're using it at Optoro, but it's not really been battle-tested. But it's faster, at the moment. So why is it faster? Well, maybe I haven't written all the code yet. But more likely it, more likely it's because of this concept in TCP called the slow-start phenomonon. And also, your whole TCP negotiation. So each one of these five hundred HTTP requests, close the connection, open the connection, send the message, receive the response. When you open the TCP connection you go through a whole sinaq phase, which I didn't put slides in for and maybe should have. But it's. I highly recommend checking out Eliot Gregorich's talks, by the way, about how HTTP works, how TCP works. But basically, you go through protocol negotiation for any TCP connection, and then there's a feature of TCP called the slow-start feature, which essentially allows you to negotiate your connection speed. And that's really great when you're talking over the internet, and you're not sure of the latency or the availability of routers to be decent along the way. But when you're doing internal applications, it just gets in your way. It just slows you down. So AMQP, we hold a persistent connection to the AMQP broker. We do one sinaq cycle, and then we get our maximum connection speed and we stay there. And then we can multiplex information over that single connection and it works really well. Now, you could write that with HTTP if you did a keep-alive connection, held over that connection and talk to the same thing back and forth. But, the bottom line is that most of us don't do that when we write HTTP. We're using something like HTTParty or, I always forget the tiforce or tif- whatever it is. Sorry. Most of the time, you know, we drop the connection, you know, in between requests. We don't hold it open. It's just not something we think about. So using AMQParty or any of the libraries that we're published, it holds that open and it just makes it more efficient overall. So I hope that's the primary explanation of why it's so much faster. So I just wanted to mention a few references, a few things that were really inspriring when we kind of went down this road. You know, this is really a departure from what we're used to in Rails. And the Architecture: The Lost Years talk and Matt Wynne's original Hexegonal Rails talks were all about departing from what we're used to, I think. So those are really interesting. If you haven't checked those out, definitely do. Additionally, Martin Fowler posted a recent article that was awesome, called Micro Services. Definitely, definitely read this if you are looking into service-oriented architectures. It lets you not think about that heavy-weight bloat that we think about with SOA. It's really a revisitation of the idea of, just, you have independent services that are collaborating to get something done in a very simple way. And that's really, again, also influenced the direction we're taking here. We want to introduce as few specific choices as possible to just kind of give us a simple transport to, to build on top of. Additionally, the Ruby AMQP gem has some awesome docs about how AMQP works, how to use it with Ruby. And RabbitMQ also publishes some really great documentation on what AMQP is, how it works. How to use it in the organization in your applications. And there's also this really great article I found about how HTTP works, in general. It's, I think a piece of school material from a university in Singapore. Definitely check it out. It's got really great diagrams. Thanks. Again, I'm Josh. I'm at jszmajda on the Twitters. I am the CTO at Optoro. We have blinq dot com. We have retailers with their returned goods and excess goods, help them figure out what it is, what the current value is and move it quickly. Additionally, I am the host of the Ruby hangout. Just a quick blurb for the Ruby hangout, it's a online meetup. It's really handy when you can go face-to-face and talk to people if you have a local meet up. If you don't have a local meet up or if you're too busy or if you can't make it for whatever reason, the Ruby hangout is an online meet up to, essentially, give you that local meet up feel, as much as we can online. So check that out. It's a lot of fun. I'm one of the co-organizers of the DC Ruby Users group. And I want to give a quick shoutout to Jonathan. Thanks Jon. He's on my team, helped me get Jackalope over the, over the finish line. So super helpful on that. All the code's on GitHub. Github dot com slash rack dash amqp slash rack dash amqp is where the RC lives and has bookmarks to the other parts of the project. And I would love to take your questions, because that talk was way short. And I've got, actually, a whole bunch of stuffed Jackalopes up here for good questions. So please feel free to come grab one.