内容


功能丰富的 Perl

Perl 和 Amazon 云,第 3 部分

上传图像并创建、编辑和删除评论

系列内容:

此内容是该系列 # 部分中的第 # 部分: 功能丰富的 Perl

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

此内容是该系列的一部分:功能丰富的 Perl

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

距离我的上一期文章已经有一段时间了,现在我们来回顾一下:

  • 第 1 部分 解释了 S3/SimpleDB 架构以及如何通过实际示例使用它们。
  • 第 2 部分 展示了如何通过 HTML 表单,从一个网页中将文件上传到 S3,从而最小化服务器负载。

现在,让我们真正开始深入了解照片共享网站与 Amazon SimpleDB 的交互,首先了解成功的 URL 如何为上传的文件创建 SimpleDB 记录,然后了解如何以 SimpleDB 记录形式创建、编辑、删除某个用户的照片评论。(记住,我们并不是要比较 SimpleDB 和 Google 的 BigTable 或 CouchDB 之类的独立解决方案)。

和此前的文章一样,我将使用 share.lifelogs.com 作为域名。

查看数据库结构

回顾一下 第 1 部分,我们设置了一个如清单 1 所示的表结构:

清单 1. 来自第 1 部分的表结构
share_photos:
"http://developer.amazonwebservices.com/connect/images/amazon/logo_aws.gif" 
{ user: "ted", name: "Amazon Logo"}

"http://images.share.lifelogs.com/funny.jpg" 
{ user: "bob", name: "Funny Picture",  s3bucket: "images.share.lifelogs.com" }

share_users:
"ted" { given: "Ted", family: "Zlatanov" }
"bob" { given: "Bob", family: "Leech" }

share_comments:
"random-string"
{ 
 url: "http://images.share.lifelogs.com/funny.jpg",
 comment: "Ha ha", 
 posted_when: "2009-03-01T19:00:00+05" 
}

"random-string2"
{ 
 user: "ted",
 url: "http://developer.amazonwebservices.com/connect/images/amazon/logo_aws.gif", 
 comment: "No it doesn't", 
 posted_when: "2009-03-01T20:00:01+05" 
}

"random-string3"
{ 
 url: "http://developer.amazonwebservices.com/connect/images/amazon/logo_aws.gif", 
 comment: "No it doesn't", 
 reply_to: "random-string2", 
 posted_when: "2009-03-01T20:00:01+05" 
}

在这个版本的结构中,您可以将所有有关某个主题的评论存储到一个 comment 结构内部,但是,两名用户同时删除或编辑同一主题的评论是非常危险的。

如我在第 1 部分中谈到的一样,这种结构需要进行修改。SimpleDB 的一大优点就在于其灵活性,因此让我们利用这一点。正如 Emerson 所说,“只有无知的人才会愚蠢地坚持”。当然,他也说过 “我痛恨引用名人语录”。多么无聊的超验主义者。

我发现 SimpleDB 暂存器(scratchpad)比不上从代码直接生成调用,但是您也许会喜欢它。查看 参考资料 了解暂存器 URL。您还可以购买一些 SimpleDB 管理工具,对 Firefox 使用免费工具,或者尝试 typica shell。参考资料 小节提供了所有相关内容。

上传和修改照片

首先,注意 SimpleDB 允许对单一键使用多个值。因此我提到的照片 URL 或评论文本可以是数组而不是单个值。我们不会使用这个特性,为了保持简单对每个键使用一个值。

让我们首先从照片更新开始。每次完成一次上传后,将运行代码来向 share_photos 表添加新照片。第 2 部分 展示了 S3 上传表单;下一次我们将把此表单连接到本文编写的代码中。

现在,让我们编写一个简单的脚本来添加照片。您将获得一个用户名、一个 URL、一个照片名和一个可选的 S3 bucket 名。S3 bucket 就是指表中的一个字段;URL 将用于显示和使用照片。我们希望使用一个复制 URL 来拒绝上传。可以这样做吗?

分布式数据存储的一个问题就是,您放入其中的数据可能无法超越网络的局限性。就好象从日本呼叫欧洲一样(或做任何体验到网络延迟或语音信号延迟的操作):当对方与您保持同步时,每说一句话都会产生轻微的延迟。您可以不间断地开始讲话,但是另一端的回答将会与您的声音重叠,令您感觉自己好像是一个参加重要会议的主管。尽管延迟性可以为您带来这种良好的感觉,但是它不利于展开有序的会话。

同样地,如果将数据放到 SimpleDB 系统中,当数据流入数据中心时也会产生停顿。目前,Amazon 还没有确认这一点,但是据我所知,它将构成银河意识(galactic consciousness)的一部分,并改善 Runu 星球(距离 Betelgeuse 3 个秒差距,左转并继续逼近,直到您看见它)上类似于蛞蝓的生物的生活。因此每次使用 SimpleDB 时,您就会为 Runu 星球上类似蛞蝓生物做了一件好事。并且您会认为这篇文章不像是教学文章

无论如何,在提高银河意识的同时,您的数据是实时的,并且可以通过查询查看。但是如果在所有一切发生之前发出查询,那么不仅不会提高银河意识,还会得到旧的数据。因此,并不像处理典型的 DB2 数据库(在其中保持数据,并且 ACID 确保事务正如数据库声称的那样被提交)那么简单。使用 SimpleDB 和其他 “非常一致的” 数据库,您不得不忍受这种不确定性。

重点在于,更新照片没有这么简单。我们希望使用一个复制 URL 拒绝上传,但这并不是总是可行的。假设 Alice 上传 http://horsey.com/wilbur.png,与此同时,Bob 也上传了 http://horsey.com/wilbur.png。如果 Alice 的上传排在前面而 Bob 没有注意到它,那么 Bob 的上传将覆盖前者。那么我们该怎么做呢?

首先,您会问,这样有什么危害?用户可能会有些不方便,但是这没什么大不了。而且,同时上传的机率也很小。是的,我们希望用户满意,如果我们过分追求质量的话,也许这个问题将纠缠我们终生。

我们不会把这种痛苦带到坟墓中,相反,我们将针对照片修改表设计,如清单 2 所示:

清单 2. 修改后的表设计
share_photos:

"random-string10"
{ url: "http://developer.amazonwebservices.com/connect/images/amazon/logo_aws.gif",
        user: "ted", name: "Amazon Logo"}

"random-string11"
{ url: "http://images.share.lifelogs.com/funny.jpg", user: "bob", name: "Funny Picture",
        s3bucket: "images.share.lifelogs.com" }

您到目前为止所看到的 random-strings 将为 UUID。它不够完美,但是至少在 URL 相同的情况下照片不会出现冲突。但是等等……照片评论会怎样?很简单;我们只修改外键,如清单 3 所示:

清单 3. 修改外键
share_comments:

"random-string3"
{ 
 image_id: "random-string10", 
 comment: "No it doesn't", 
 reply_to: "random-string2", 
 posted_when: "2009-03-01T20:00:01+05" 
}

现在我们需要注意到 share_photos 中有多个条目使用相同的 URL,但是除此以外系统一切正常。

我们并不是向您展示人为修改的最终版表,而是将所有表遍历一遍。这使我们可以展示的 SimpleDB 灵活性并展示最佳状态的敏捷开发:投入、测试、优化、重复。但是,我们并没有对每一件事情 进行计划,而仅仅做好通往下一个阶段的计划:

  • 我们任何时刻都没有忘记全局性。
  • 在制定或修改架构决策时,不会像对待特定于任务的决策那样随意。

那么照片上传很简单,是吗?只需要使用给定的 URL、照片名和用户名向 SimpleDB 添加一个新条目。S3 bucket 是可选的。这可以通过 PutAttributes 调用完成。

修改照片也很简单,但是目前我们只修改名称。这也是通过 PutAttributes 完成的。

添加和修改评论

参考前面小节有关 share_comments 表的内容。非常简单:添加一个评论需要评论文本、照片 ID、父评论 ID(可选)和一个用户名。目前为止,修改评论意味着只能对评论文本进行修改。

独立脚本

我包含了一个独立的 Perl 脚本(simple_go.pl;可以从本文结束部分的 下载 小节获得)来执行前面列出的任务(添加和修改照片、添加和修改评论)。它不会创建域,因此您需要通过外部方式创建 SimpleDB domains share_photos.share.lifelogs.com 和 share_comments.share.lifelogs.com。这可以通过任何 SimpleDB 管理工具完成。注意 --domain switch 将修改 share.lifelogs.com 以获得完整的域名(存储在 $full_domain)。

脚本使用 CPAN Data::UUID 模块生成新的惟一标识符。

脚本在处理错误方面有些随意,在任何可能的情况下都会选择 die()。这种方式非常懒惰并且叫人看不起,因此您不应选择这样做,除非您在撰写文章并向人们展示写文章的程序员有多么糟糕。

最后一个任务是提交 SELECT 语句并删除一个项。我将展示如何实现它们,因为这些任务很简单,并且您稍后就将用到。

要列出照片,需要像清单 4 一样调用脚本:

清单 4. 列出照片
./simple_go.pl -l -i --ak=accesskey --sk=secretkey

注意:确保您运行脚本的机器不会被其他人使用。他们会查看进程列表并获知您的 Amazon 秘密密匙。类似地,如果位于一个保存历史的 shell 中,您的秘密密匙将出现在您的历史文件中。更好的方法是传递一个文件名并从该文件中获得密码,但是为了保持简单性,我没有实现这种方法。

要列出评论:

清单 5. 列出评论
./simple_go.pl -l -c --ak=accesskey --sk=secretkey

目前为止,一切都很简单。脚本在内部调用 $service->select() 方法,解析结果,使用 show_list() 输出数据。执行所有操作的前提就是键只有一个值(注意我们在 put() 方法中指定 Replace=true),因此这并不是一个通用 SimpleDB 脚本。

为什么不选择通用脚本?我们不需要它。现在让我们使用一个简单的解决方法。如果需要多个值,可以稍后采用脚本或编写些新代码。这个脚本是创建网站数据库结构的基础。

不要在实际站点中尝试使用这个脚本(“我将仅调用 system() 并让错误进入到日志文件中”)。是的,它包括几百行代码并且可以工作,但是必须毫不犹豫地扔掉所有原型,这样才可以编写一个真正的程序。这个脚本也不应该有例外,即使我们已经有点喜欢上它以一个空格为缩进的散漫(或者说 “有创意”)布局。

回到脚本中来。创建一个新照片非常简单(bucket 是可选的):

清单 6. 创建一个新照片
./simple_go.pl -i --ak=accesskey --sk=secretkey -u ted --url="any url"
  --name="any name you like" --bucket=mybucket

编辑照片名字(-l -i 提供了一个 ID 25EC17B8-0F6B-11DE-A1A1-944E07F9DEC1)。这将创建一个具有惟一 UUID 的照片:

清单 7. 创建具有惟一 UUID 的新照片
./simple_go.pl -i --ak=accesskey --sk=secretkey --name="new name"
  --id=25EC17B8-0F6B-11DE-A1A1-944E07F9DEC1

类似地,创建评论也很简单(userrefcommentid 是可选的):

清单 8. 创建一个评论
./simple_go.pl -c --ak=accesskey --sk=secretkey -u ted --refimageid="any image ID"
  --text="the text" --refcommentid='any comment ID'

同样,评论 ID 将是一个惟一 UUID。编辑评论的文本也执行类似的操作:(-l -c 提供了 ID 4BE2EA0A-0F6B-11DE-976B-A542FC6BD07C):

清单 9. 创建具有惟一 UUID 的评论
./simple_go.pl -c --ak=accesskey --sk=secretkey --text="the text"
  --id=4BE2EA0A-0F6B-11DE-976B-A542FC6BD07C

最后,像下面这样删除照片或评论:

清单 10. 删除图像和评论
./simple_go.pl --delete -i --ak=accesskey --sk=secretkey
  --id=25EC17B8-0F6B-11DE-A1A1-944E07F9DEC1
./simple_go.pl --delete -c --ak=accesskey --sk=secretkey
  --id=4BE2EA0A-0F6B-11DE-976B-A542FC6BD07C

结束语

本期文章展示了如何在一个 SimpleDB 数据库中创建、编辑和删除照片和评论,SimpleDB 数据构成了我们所构建的照片共享站点的基础。

我们确立了松散的模式,并实现一个工具来添加、列举、修改和删除照片和评论。我们使用 UUID 作为照片和评论的主键,防止出现两个用户同时上传相同的照片 URL。

我们还确定将对每个键使用一个单一值,因为目前的模式不需要使用多个值,并且我们希望保持简单性。这一缺陷可能需要在以后解决,但是目前我们将继续保持下去。

在第 4 部分中,您将看到如何将所有功能集成到 mod_perl 网站中。


下载资源


相关主题

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux, Open source
ArticleID=406697
ArticleTitle=功能丰富的 Perl: Perl 和 Amazon 云,第 3 部分
publish-date=07062009