内容


用 Amazon Web Services 进行云计算,第 4 部分

用 SQS 进行可靠的消息传递

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 用 Amazon Web Services 进行云计算,第 4 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:用 Amazon Web Services 进行云计算,第 4 部分

敬请期待该系列的后续内容。

Amazon SQS

Amazon Simple Queue Service (SQS) 是一个可伸缩且可靠的消息传递框架,可以使用它简便地创建、存储和获取文本消息。可以使用它构建基于 Amazon Web Services 的应用程序。使用 SQS 是构建松散耦合的 Web 应用程序的好方法。只需根据使用量为消息付费。整个队列框架在 Amazon 数据中心的安全环境中运行。

SQS 提供以下特性:

可靠性
SQS 能够跨多个数据中心冗余地存储消息,保证它们随时可用。
简单性
访问和使用 SQS 的编程模型非常简单,而且可以通过多种编程语言使用 SQS。
安全性
SQS 提供很高的安全水平。只允许授权的用户访问消息。
可伸缩性
可以用 SQS 创建基于队列的应用程序,这些程序可以读写数量不限的消息。
低成本
SQS 以非常低廉的费率满足您的消息传递需求。

下面讨论支撑 SQS 框架的概念。

消息

消息 包含不超过 8 KB 的文本数据。每个消息一直存储到被应用程序接收为止。当接收消息的应用程序从队列中读取一个消息时,指定可见性超时值(以秒为单位)。它的作用就像是锁:

  • 确保在指定的时间段内队列的其他消费者看不到已被接收的消息。
  • 只有当超时周期过期时,而且读取消息的应用程序没有删除它,消息才会重新出现在队列中。

消息在队列中保留四天。

SQS 会自动删除在队列中超过四天的消息。SQS 采用 “最终一致性(eventual consistency)” 模型,这意味着您可以向队列发送消息,但是队列的消费者不一定能够在特定的时间段内看到它。消息最终会投递,但是一定要考虑您的应用程序是否在意消息的次序。

消息由表 1 所示的几个部分组成。

表 1. 消息的组成部分
部分 说明
MessageId引用此消息的惟一 ID。
ReceiptHandle在从队列获取消息时返回的惟一句柄。每次从队列获取消息时返回的句柄都不一样。在删除消息时需要使用它。
MD5OfBody非 URL 编码的消息体字符串的 MD5 摘要。
Body实际的消息数据。

队列

队列 是消息的容器。每个消息必须指定将容纳它的队列。发送给队列的消息保留在队列中,直到显式地删除它们。队列采用 “先进先出” 次序,但是并不保证次序。每个队列的默认可见性超时值是 30 秒。可以为整个队列修改这个值,也可以在获取消息时单独为每个消息设置。队列或消息可见性超时值的最大值是两小时(7,200 秒)。如果队列中连续 30 天没有活动,SQS 保留自动删除它们的权力。

设计考虑因素

SQS 与常见的队列框架有点儿不一样。在设计基于 SQS 的应用程序之前,您必须考虑三个问题:

  • SQS 不保证队列中消息的次序。

    消息在队列中的次序是宽松的;它们实际上并不按照在队列中添加消息的次序存储。SQS 会尝试保持消息的次序,但是不保证接收消息的次序与发送它们的次序完全相同。如果消息的次序对于您的应用程序很重要,就需要在每个消息中添加序列数据。

  • SQS 不保证删除队列中的消息。

    在设计应用程序时,必须保证多次处理同一消息不会对程序产生影响。SQS 把每个消息存储在多台服务器上,从而提供冗余和高可用性。如果在删除一个消息时其中一个服务器不可用,那么在以后接收消息时有可能再次获取此消息的拷贝(尽管这种情况很少出现)。

  • SQS 不保证在查询时返回队列中的所有消息。

    SQS 使用基于加权随机分布的消息取样,在查询消息时,它只从取样的一部分服务器返回消息。尽管一次查询请求可能不会返回队列中的所有消息,但是如果一直从队列中获取消息,最终会取样所有服务器,您就会得到所有消息。

API 版本

有两个 SQS 版本:最初版本 (2007-05-01) 和 2008-01-01 版本。API 的版本号通常采用发布日期。2007-05-01 API 将于 2009 年 5 月 6 日废止,在此之后只支持 API 的最新版本。强烈建议用户:

  • 尽快开始迁移使用老 API 版本的应用程序。
  • 为了尽可能减少麻烦,在用 SQS 创建新应用程序时,应该使用 API 的最新版本。

2008-01-01 版本更新了定价,这降低了大多数用户的 SQS 使用费用,还包含更多特性和改进。但是,它也引入了与老 API 不兼容的更改。用老版本构建的所有库和工具都需要修改。关于版本之间的差异的详细信息可以在 SQS 网站上找到(见 参考资料)。

Amazon Web Services 和 SQS 入门

要想开始使用 SQS,首先需要注册一个 Amazon Web Services 账户(见 参考资料)。本系列的 第 2 部分 详细介绍了如何注册 Amazon Web Services 账户。

创建账户之后,必须为账户启用 Amazon SQS 服务:

  1. 注册 Amazon Web Services 账户。
  2. 导航到 SQS 主页
  3. 单击页面右边的 Sign Up For Amazon SQS
  4. 提供必需的信息并完成注册过程。

与任何 Amazon Web Services 的所有通信都要通过 SOAP 接口或查询/REST 接口。在本文中,使用一个第三方库的查询接口与 SQS 通信。

需要获得自己的访问键,可以通过在 Web Services Account information 页面上选择 View Access Key Identifiers 获得访问键。现在设置了 Amazon Web Services 并为账户启用了 SQS 服务。

与 SQS 交互

这个示例使用第三方 Pythonboto,通过在 Python shell 中运行代码来熟悉如何使用 SQS。

安装 boto 并设置环境

下载 boto 的最新版本,撰写本文时的最新版本是 1.4c。把存档文件解压到您选择的目录中。进入此目录并运行 setup.py 把 boto 安装到本地 Python 环境中,见清单 1。

清单 1. 安装 boto
$ cd directory_where_you_unzipped_boto

$ python setup.py install

设置一些环境变量,引用 Amazon Web Services 访问键。可以从 Web Services Account information 页面获得访问键。

清单 2. 设置环境变量
# Export variables with your AWS access keys
$ export AWS_ACCESS_KEY_ID=Your_AWS_Access_Key_ID 
$ export AWS_SECRET_ACCESS_KEY=Your_AWS_Secret_Access_Key

启动 Python shell 并导入 boto 库,从而确认所有设置都是正确的,见清单 3。

清单 3. 检查设置
$ python
Python 2.4.5 (#1, Apr 12 2008, 02:18:19) 
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import boto
>>>

用 boto 体验 SQS

SQSConnection 类提供与 SQS 交互的主要接口。使用 boto 的中介是 Python 控制台。示例调用 SQSConnection 对象上的不同方法,然后查看 SQS 返回的响应,这有助于熟悉 API 和体验 SQS 概念。

第一步是使用前面导出到环境中的 Amazon Web Services 访问键,创建一个连接到 SQS 的连接对象。boto 库总是先检查是否设置了这些环境变量。如果设置了这些变量,boto 在创建连接时自动地使用它们。

清单 4. 创建到 SQS 的连接
>>> import boto
>>> sqs_conn = boto.connect_sqs()
>>>

然后,可以使用 sqs_conn 对象与 SQS 交互。可以通过指定队列名称和可选的可见性超时值创建队列。如果没有指定超时值,boto 将用 SQS 提供的默认值(30 秒)创建队列。

清单 5. 创建队列
>>> q1 = sqs_conn.create_queue('devworks-sqs-1')
>>> 
>>> q1.get_timeout()
30
>>> q2 = sqs_conn.create_queue('devworks-sqs-2', 60)
>>> 
>>> q2.get_timeout()
60
>>>

获取所有队列的列表,这返回一个结果集对象,它实际上是一个 Python 列表,见清单 6。可以循环遍历这个列表并访问每个队列的所有相关信息。

清单 6. 列出所有队列
>>> all_queues = sqs_conn.get_all_queues()
>>> 
>>> len(all_queues)
2
>>> 
>>> for q in all_queues:
...     print q.id
...     print q.count()
...     print q.get_timeout()
...     print q.url
... 
/devworks-sqs-1
0
30
http://queue.amazonaws.com/devworks-sqs-1

/devworks-sqs-2
0
60
http://queue.amazonaws.com/devworks-sqs-2

在删除队列之前,必须删除队列中的所有消息。可以使用 boto 中的 clear() 方法删除队列中的所有消息。

清单 7. 清空并删除队列
>>> q2.clear()
0
>>> sqs_conn.delete_queue(q2)
True
>>>

可以向队列发送大小不超过 8 KB 的文本消息。使用 boto Message 类创建新消息,见清单 8。

清单 8. 发送消息
>>> from boto.sqs.message import Message
>>> 
>>> m1 = Message()
>>> 
>>> m1.set_body('Hi there devworks!')
>>> 
>>> status = q1.write(m1)
>>> 
>>> print status
True
>>>

获取队列中的消息会返回一个结果集对象,它是一个包含消息对象的 Python 列表。每个消息对象有相关联的惟一 ID 和收件句柄。在从队列中读取消息之后,队列的其他所有消费者就看不到这个消息,直到可见性超时周期过期为止。过期之后,消息再次出现在队列中,让其他消费者有机会获取和处理它。但是,如果在可见性超时周期过期之前从队列中删除了消息,消息就永远消失了,不会再次出现在队列中。

清单 9. 获取消息
>>> msgs = q1.get_messages()
>>> 
>>> len(msgs)
1
>>>
>>> for msg in msgs:
...     print "Message ID: ",msg.id
...     print "Message Handle: ",msg.receipt_handle
...     print "Queue ID: ", msg.queue.id
...     print "Message Body: ", msg.get_body()
... 
Message ID:  9a930aaf-87de-48ad-894d-b22dd0b1cd1b

Message Handle:  Prl0vft3nRjgDDT33svtLnzyPQGWFpRusXdn2v3Lwq+TDtD3hk3aBKbSH1mGc4hzO/VZO
IC0RFyAd7MhbJKPGHn3x35CTz9dAQeNoKYAHiwERXc/xrYXBLGngyuJI+kGmbjvIKqA/wpfQpqzPk2bVA==

Queue ID:  /devworks-sqs-1

Message Body:  Hi there devworks!
>>>

可以通过指定消息数量获取多个消息。boto 中的默认设置是返回一个消息。我们在队列中添加另一个消息,然后获取所有消息,见清单 10。请记住,新添加的消息出现在队列中可能要花费一分钟左右。

清单 10. 获取多个消息
>>> m2 = Message()
>>> 
>>> m2.set_body('Still there?')
>>> 
>>> status = q1.write(m2)
>>> 
>>> print status
True
>>>
>>> msgs = q1.get_messages(10)
>>> 
>>> len(msgs)
2
>>>
>>> for msg in msgs:
...     print "Message ID: ",msg.id
...     print "Message Handle: ",msg.receipt_handle
...     print "Queue ID: ", msg.queue.id
...     print "Message Body: ", msg.get_body()
...     print "*"*80
... 
Message ID:  9a930aaf-87de-48ad-894d-b22dd0b1cd1b

Message Handle:  Prl0vft3nRjgDDT33svtLnzyPQGWFpRusXdn2v3Lwq+TDtD3hk3aBKbSH1mGc4hzO/VZOIC0R
FyAd7MhbJKPGHn3x35CTz9dAQeNoKYAHiwERXc/xrYXBLGngyuJI+kGmbjvIKqA/wpfQpqzPk2bVA==

Queue ID:  /devworks-sqs-1

Message Body:  Hi there devworks!


Message ID:  ce1632b3-0a6e-4ee2-a5b0-b2e9821d150f

Message Handle:  Prl0vft3nRiRunVNVvjOQEc7Tm+uSBQpW4bZcpFMbzWTDtD3hk3aBKbSH1mGc4hzO/VZOIC0R
FxbhtlykUxvNbRQNWJqrMXrxj5m6GwhA7iX0Nu9mqjo+9/hnda8Ou0df+LQ3dOMfXSybzbhed128w==

Queue ID:  /devworks-sqs-1

Message Body:  Still there?
>>>

可以通过调用 delete_message() 从队列中删除消息。请记住,在删除队列之前,必须删除队列中的所有消息。

清单 11. 删除消息
>>> msgs = q1.get_messages()
>>> 
>>> len(msgs)
1
>>> print msgs[0].get_body()
Hi there devworks!
>>> 
>>> q1.delete_message(msgs[0])
True
>>>

结束语

本文介绍了 Amazon 的 SQS 服务。学习了一些基本概念和 boto(一个用于与 SQS 交互的开放源码 Python 库)提供的一些功能。强烈建议您通过 Amazon SQS 开发人员指南了解更多信息(见 参考资料)。

这个 “用 Amazon Web Services 进行云计算” 系列的 第 5 部分 讨论如何用 Amazon SimpleDB 在云中处理数据集。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=386137
ArticleTitle=用 Amazon Web Services 进行云计算,第 4 部分: 用 SQS 进行可靠的消息传递
publish-date=04292009