[转载] Message Queues and RPC

本文探讨了消息队列和远程过程调用(RPC)两种通信方式的特点与区别,包括抽象级别、持久化能力、弹性处理及异步通信等方面的优势,并分析了它们在现代分布式系统中的应用。

原文链接: Message Queues and RPC


转载说明 (最后更新于: 2019-04-08, 12:18:57)

  1. 原文链接在国内访问存在异常, 为了避免因某些原因无法继续访问, 特转载至此, 并根据上下文对原文中的部分关键字进行了加粗处理.
  2. 原文中部分链接由于资源不存在已经失效, 博主根据原文中的链接找到文档并对链接进行了更新, 见文中中文注释.
  3. 原文中部分链接由于无法访问或仅仅是指向特定软件产品官网的链接未引用至此, 特此说明.

Tuesday, January 1, 2013

With the arrival of a new year, I’d like to bring up an old question in distributed systems research. What is the “best” way for applications running on separate machines to communicate with each other? Specifically, I’m interested in the case in which you have several different servers running individual pieces of your system architecture that need to communicate (rather than, for example, a client-server model). In my experience, I’ve come across two different basic methods for doing this, namely message queues and remote procedure calls (RPC). Examples of software/libraries include RabbitMQ, HornetQ, and ActiveMQ for message queues, Avro and Thrift for RPC.

What’s the difference?

The key difference between message queues and RPC is the level abstraction they provide the programmer. With message queues, it is generally left to the developer to serialize and deserialize messages to/from the queue and decide how to process each type of message; you work with a basic send/receive paradigm and as a result have a lot of control over the communication. RPC, on the other hand, tries to hide this complexity by making a call to a remote machine look like a call to a local object (hence the name). It’s often the case that RPC functionality is packaged with serialization libraries (e.g. Avro and Thrift) because it relies on some serialization format in order to automatically handle the translation of a method call on one machine to a method call on another.

If that’s where the discussion ended, it would be a pretty clear win for RPC. Abstraction is a programmer’s greatest tool, and it can be argued that someone developing an application shouldn’t need to know whether a method being called is a local or remote object. The convenience associated with this approach has been attributed as one of the reasons why RPC is so popular (it’s used extensively in Google’s infrastructure, and Thrift came out of Facebook) despite some serious criticisms (原文中的该链接已失效, 由博主更新) from almost 20 years ago. It’s my intention to attempt to make sense out of arguments that people have made for and against RPC and discuss what I believe to be important features of message queues that RPC lacks.

Theory vs practice

Many of the discussions about RPC focus on what I’ll call “pure RPC.” What I mean by that is the concept of making local and remote method calls completely indistinguishable. It’s clear that this is impossible given the four concerns of latency, memory access, partial failure, and concurrency brought up here (原文中的该链接已失效, 由博主更新). Instead, I’d like to focus on the practical RPC libraries that people work with and what they offer. In most such cases, the programmer does know that they’re making a method call to an external service by nature of understanding the architecture and having to define the interfaces/data structures to be serialized. This has already broken the abstraction, which takes away some of the benefits of RPC, but there’s still something useful about having your services represented by interfaces and calling methods on them.

What RPC can do

Scalability is one concern that has been brought up about RPC. Message queues are usually an isolated service which provides a decoupling between the sender and receiver, which means that it’s really easy for multiple senders/receivers to operate using the same queue and scale out horizontally. With RPC, it’s not quite a “built-in” feature, but those who claim that you can’t scale it should have a word with Google and Facebook. Since method calls over RPC are typically directed at a single endpoint, it might seem like it won’t scale horizontally, but putting a load balancer in front of your endpoints goes a long way. If you make any assumptions about state it gets a bit trickier, but that’s a problem that both message queues and RPC have to deal with.

Robustness is a second problem people like to talk about with RPC; by robustness I mean what semantics we can guarantee on the execution of a method, e.g. exactly once, at most once, or at least once. Generally, you have two possibilities: if you try a method call once only, you get “at most once” semantics (which is typically very hard to reason about); if you retry method calls until you hear a success, you get “at least once” semantics (which is also hard to reason about, but less so). That might seem problematic, but again message queues suffer from the same issue even with acknowledgements and confirmation of delivery.

Message queues and asynchronous communication

This blog post (see below, by blogger) provides a list of ten important features of message queues that make them a good choice. I will highlight three in particular that differentiate message queues from RPC. The first is durability; many message queues provide support for message persistence. When you send a message to the queue, it will write it to disk before acknowledging your message so that in the event of a failure the message will not be lost. This is difficult to do using RPC because there is no intermediary and it doesn’t make a lot of sense to replay a method call when you no longer have the context (e.g. stack) in which it was made.

Another property of message queues that make them compelling is the fact that messaging is inherently asynchronous. After a message is sent to the queue, the process should not block waiting for a response; instead it can provide a callback or use continuations (e.g. Jetty). This frees up resources while waiting on expensive I/O operations, an important aspect of building systems that perform well under load. Although there’s nothing inherent in the idea of RPC that it has to be synchronous, that’s typically how it’s used because object-oriented programming has taught us all to write procedural code with “blocking” method calls.

The last important feature that I want to discuss is a corollary of asynchronous communication, which is elasticity. Suppose that a system is suddenly subjected to a hundred times the typical load, but only for a brief period. With an RPC-based architecture, there would be many threads all blocked on method calls to remote services as they slowly processed the increased volume of requests; as many know, this is an easy way to kill a system or at the very least make it non-responsive. A message queue helps absorb sudden load spikes because it allows senders to asynchronously send a message and then free its resources. The messages accumulate in the queue (they are designed to handle this) while the recipients process them, and every component in the system behaves normally. Again, a continuation system would let you return control to the original sender once its message has been processed.

Conclusion

Both message queues and RPC solve the problem of communicating between applications running on different machines. The discussion about which method is “better” is a good way to evaluate what is the right choice in specific situations. Empirical evidence suggests that you can build robust, scalable systems with either one, so it’s hard to say if there’s necessarily a wrong choice here. Message queues provide some benefits that RPC lacks, though, and I would argue that those are important enough that they should be addressed in some other way if an RPC approach is taken.

Posted by Jeffrey Wang at 5:02 PM
Labels: distributed systems, software engineering

原文链接: Message Queues and RPC


注释于 2019-04-08, 以下内容摘自 Top 10 Uses For A Message Queue, 详情请点击链接.

We’ve been working with, building, and evangelising message queues for the last year, and it’s no secret that we think they’re awesome. We believe message queues are a vital component to any architecture or application, and here are ten reasons why:

  1. Decoupling

    It’s extremely difficult to predict, at the start of a project, what the future needs of the project will be. By introducing a layer in between processes, message queues create an implicit, data-based interface that both processes implement. This allows you to extend and modify these processes independently, by simply ensuring they adhere to the same interface requirements.

  2. Redundancy

    Sometimes processes fail when processing data. Unless that data is persisted, it’s lost forever. Queues mitigate this by persisting data until it has been fully processed. The put-get-delete paradigm, which many message queues use, requires a process to explicitly indicate that it has finished processing a message before the message is removed from the queue, ensuring your data is kept safe until you’re done with it.

  3. Scalability

    Because message queues decouple your processes, it’s easy to scale up the rate with which messages are added to the queue or processed; simply add another process. No code needs to be changed, no configurations need to be tweaked. Scaling is as simple as adding more power.

  4. Elasticity & Spikability

    When your application hits the front page of Hacker News, you’re going to see unusual levels of traffic. Your application needs to be able to keep functioning with this increased load, but the traffic is anomaly, not the standard; it’s wasteful to have enough resources on standby to handle these spikes. Message queues will allow beleaguered components to struggle through the increased load, instead of getting overloaded with requests and failing completely. Check out our Spikability blog post for more information about this.

  5. Resiliency

    When part of your architecture fails, it doesn’t need to take the entire system down with it. Message queues decouple processes, so if a process that is processing messages from the queue fails, messages can still be added to the queue to be processed when the system recovers. This ability to accept requests that will be retried or processed at a later date is often the difference between an inconvenienced customer and a frustrated customer.

  6. Delivery Guarantees

    The redundancy provided by message queues guarantees that a message will be processed eventually, so long as a process is reading the queue. On top of that, IronMQ provides an only-delivered-once guarantee. No matter how many processes are pulling data from the queue, each message will only be processed a single time. This is made possible because retrieving a message “reserves” that message, temporarily removing it from the queue. Unless the client specifically states that it’s finished with that message, the message will be placed back on the queue to be processed after a configurable amount of time.

  7. Ordering Guarantees

    In a lot of situations, the order with which data is processed is important. Message queues are inherently ordered, and capable of providing guarantees that data will be processed in a specific order. IronMQ guarantees that messages will be processed using FIFO (first in, first out), so the order in which messages are placed on a queue is the order in which they’ll be retrieved from it.

  8. Buffering

    In any non-trivial system, there are going to be components that require different processing times. For example, it takes less time to upload an image than it does to apply a filter to it. Message queues help these tasks operate at peak efficiency by offering a buffer layer–the process writing to the queue can write as fast as it’s able to, instead of being constrained by the readiness of the process reading from the queue. This buffer helps control and optimize the speed with which data flows through your system.

  9. Understanding Data Flow

    In a distributed system, getting an overall sense of how long user actions take to complete and why is a huge problem. Message queues, through the rate with which they are processed, help to easily identify under-performing processes or areas where the data flow is not optimal.

  10. Asynchronous Communication

    A lot of times, you don’t want to or need to process a message immediately. Message queues enable asynchronous processing, which allows you to put a message on the queue without processing it immediately. For long-running API calls, SQL reporting queries, or any other operation that takes more than a second, consider using a queue. Queue up as many messages as you like, then process them at your leisure.

We believe these ten reasons make queues the best form of communication between processes or applications. We’ve spent a year building and learning from IronMQ, and our customers are doing amazing things with message queues. Queues are the key to the powerful, distributed applications that can leverage all the power that the cloud has to offer.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值