报名参加CloudWeGo黑客松,奖金直推双丰收! 了解详情
写点什么

设计 Web 应用程序时要注意可伸缩性

  • 2010-09-03
  • 本文字数:2132 字

    阅读完需:约 7 分钟

Max Indelicato 是一位软件开发主管和前首席软件架构师,他最近发表了一篇关于如何设计具备可伸缩性的web 应用程序的文章。他提出要选择正确的部署和存储解决方案,选择可伸缩的数据存储和模式,并且使用抽象层。

适合工作的工具

Indelicato 的第一个建议是“为工作选择正确的工具”,想要达到这个目的,就要选择下列架构解决方案中的一种:

  • 使用云部署解决方案
  • 使用可伸缩的数据存储解决方案,像 MongoDB、CouchDB、Cassandra 或者 Redis。
  • 添加高速缓存层,像 Memcached。

他认为在开始开发应用程序的时候,这些解决方案并不是必须的,但是在开始时就选择可伸缩的数据存储解决方案是很明智的,因为那会避免之后再进行切换。将应用程序部署到云中会为我们带来一些好处,特别是对于创业公司来说,因为他们无法准确地确定他们的应用程序在启用之后会有多少人使用。将应用程序部署到云中之后,当需求增加时,就可以让应用程序以优雅的方式进行伸缩。很多软件架构师都讲述了他们不得不对应用程序进行扩展的事件,其中他们会引入高速缓存层,那会解决大部分问题。但是我们应该在设计阶段就考虑相应的解决方案。 这样在之后就很容易实现了。

可伸缩的数据存储

接下来,Indelicato 建议选择支持分区、复制并且有弹性的数据存储,包括以下几种: MongoDB、Cassandra、Redis、Tokyo Cabinet、Project Voldemort,或者选择 MySQL 作为关系型数据库。这是很必要的,因为不管怎样,在应用程序的生命周期中,分区都是必要的。对于可伸缩性来说,分区并不是必需的,但是对于“确保高可用性”就是必需的。灵活性可以让我们快速地增加更多的节点,这可能是出现流量峰值的时候,也可能是“由于硬件故障或升级、大型的伸缩模式的变更或者任何需要让节点下线的情况下,需要对节点进行维护的时候。”

可伸缩的数据模式

Indelicato 建议创建一种模式,从而让我们可以很容易地进行数据 sharding,他还给出了下面的临时组件的例子,User 和 UserFeedEntry:

复制代码
Collection (or Table, or Entries, etc) User
{
UserId : guid, unique, key
Username : string
PasswordHash : string
LastModified : timestamp
Created : timestamp
}<br></br>
Collection (or Table, or Entries, etc) UserFeedEntry
{
UserFeedEntryId : guid, unique, key
UserId : guid, unique, foreign key
Body : string
LastModified : timestamp
Created : timestamp
}

然后他建议根据 UserId 进行分区:

通过根据 UserId 字段对 User 集合和 UserFeedEntry 集合分区,我们会将两种相关的数据块放在同一个节点上。所有 UserId 为 xxx-xxx-xxx-xxx 的 UserFeedEntry 数据和 UserId 为 xxx-xxx-xxx-xxx 的 User 数据会被包含在同一数据片段中。

为什么这是可伸缩的呢? 因为我们对于这个应用程序的需求完全是针对数据的分发的。当每个访问者访问 User 的信息页面时,系统会向数据片段发出请求以获取 User 栏显示用户的详细信息,然后再向同一个数据片段发出请求以获得用户的 UserFeedEntries。这两个请求中,一个会获得一条数据,而另一个会获得多条数据,而这些数据都包含在同一数据片段中。 假设在一天之中对大多数用户的信息都有相同次数的访问,那么我们已经设计了可伸缩的模式,它会支持我们的 web 应用程序的需求。

使用抽象层

Indelicato 的最后一条建议是使用下述抽象层中的一种,但不仅限于这些: 元数据库(Repository)、缓存和服务。当创建元数据库层的时候,他建议:

  1. 不要以针对你所抽象的数据存储特有的方式来为方法命名。 例如,如果你抽象的是关系型的数据库,一般我们会为了执行 SQL 查询和命令而定义 Select()、Insert()、Delete()、Update() 函数。不要这么做。 相反,应该让你的函数名不那么专门化,可以使用 Fetch()、Put()、Delete() 和 Replace()。这会确保你更好地遵循元数据库模式,并且当你需要切换底层数据库的时候,工作会更简单。
  2. 如果可能的话使用接口(或者抽象类等等) 将这些接口传递给应用程序中更高的层,这样你永远不会直接引用元数据库的特定的固有实现。这对于构建和单元测试也是非常棒的,因为你可以编写其他固有实现,它们会预先带有与测试案例相关的数据。
  3. 将所有针对存储的特殊代码封装到一个类(或者模块等等)中,真正的元数据库会引用或者继承它。只在每个函数中放置针对存取函数所必需的细节(查询语句等等)。
  4. 时刻要牢记,并非所有元数据库都需要抽象相同的数据存储解决方案。只要你愿意,你可以将 User 存储在 MySQL 中,而将 UserFeedEntries 存储在 MongoDB 中,元数据库要以这样的方式实现,它们支持这么做而不需要付出太多代价。之前的三点建议也间接地有助于我们做到这一点。

Indelicato 说,对于高速缓存层,在开始时他经常会使用“简单的页面(或者视图等等)级别的缓存或者服务层的缓存,因为这是两个不会经常发生状态变更的区域。”

Indelicato 认为需要对服务层进行足够的抽象,这样当需求增加时,我们可以很容易地从服务的内部实现切换到进程之外的实现。

有些人认为在构建应用程序的时候不需要考虑可伸缩性问题,因为那会在必要的时候得到强调。 但是如果我们想要从开始就考虑可伸缩性,你还有什么好的建议呢?

查看英文原文: Designing a Web Application with Scalability in Mind

2010-09-03 19:554191
用户头像

发布了 340 篇内容, 共 134.7 次阅读, 收获喜欢 13 次。

关注

评论

发布
暂无评论
发现更多内容

8张图带你了解大型应用架构演进历程

Silently9527

架构 互联网架构设计

第十周作业 (作业一)

Geek_83908e

架构师一期

第七周-作业

jizhi7

第十一周作业(作业二)

Geek_83908e

架构师一期

架构师训练营第 1 期 - 第 10 周 - 命题作业

wgl

第11周作业

paul

week7-作业二:根据当周学习情况,完成一篇学习总结

未来已来

密码学,心底的凉暖

X.F

密码学

week02

ルンルン

第 07 周 性能压测(响应时间和吞吐量变化)

Airship

极客大学架构师训练营

【架构师训练营 1 期】第十一周作业

诺乐

话题讨论 | 遇到的印象最深的开源项目

soolaugust

话题讨论

week7-性能优化

未来已来

架构训练营第七周作业

一期一会

性能测试 Go 语言

从一次不佳的小组讨论展开

sherlockq

话题讨论 | 2021要来了,你对未来的一年有什么期待

soolaugust

话题讨论

话题讨论 | 未来十年,你认为哪门语言将要脱颖而出

soolaugust

话题讨论

ShardingSphere RAW JDBC 分布式事务 Narayana XA 代码示例

Java 数据库 分布式事务 ShardingSphere

架构师训练营第 11 周学习笔记

郎哲158

架构师训练营 2 期 Week07 总结

Week_11 作业

golangboy

极客大学架构师训练营

与前端训练营的日子 --Week06

SamGo

学习

第十一周 作业

熊桂平

极客大学架构师训练营

【架构师训练营 1 期】第十一周学习总结

诺乐

话题讨论 | 2020就要结束了,你最想对自己说的是什么

soolaugust

话题讨论

腾讯牵头零信任产业标准工作组正式发布零信任联盟标准

腾讯iOA与绿盟、天融信完成产品互认证,助力零信任市场协同发展

架构师训练营 11 周作业

郎哲158

Week_11 总结

golangboy

极客大学架构师训练营

训练营 - 第11周

袭望

第十一周 学习总结

熊桂平

极客大学架构师训练营

设计Web应用程序时要注意可伸缩性_架构_Abel Avram_InfoQ精选文章