GMTC深圳站本周日开幕,14大专题全部上线,完整日程>> 了解详情
写点什么

怎样实现可扩展的架构?

  • 2021 年 6 月 22 日
  • 本文字数:3088 字

    阅读完需:约 10 分钟

怎样实现可扩展的架构?

本文最初发布于 Miloslav Voloskov 的个人博客,经原作者授权由 InfoQ 中文站翻译并分享。


可扩展性被认为是一个很难解决的问题。人们总是把它看成是一种神奇的东西,是用神秘而特殊的工具完成的,只有身价百万的大块头才能使用。这当然不是真的。其实,那并没有什么神奇之处——那也不过是用普通编程语言编写的普通代码。


首先,要针对工作选择合适工具。你已经看过基准测试了,你知道有些语言在某些方面表现得更好。有些数据库的读取速度更快,而有些数据库的写入速度更快。


即使你已经为任务选择了合适的技术栈,一台服务器也是不够的。这就是有趣的地方。


当然,你可以直接从不同的 AWS 服务级别中进行选择。但是,如果想知道其中的原理,你就应该知道如何在裸金属上实现可扩展的设置。

基本原则

选择恰当的工具


不同的编程语言适用于不同的任务。


例如,Python 有非常丰富的语法糖,非常适合处理数据,而且代码简短而富有表现力。但为了实现这一点,它需要运行在解释器上,在默认情况下,这比编译后在裸金属上运行的 Go 或 C 是要慢的。


NodeJS 的外部工具可能是最丰富的,但它是单线程的。要在多核机器上运行 NodeJS,必须使用像PM2这样的东西,但这样的话,就必须保持代码是无状态的。


数据库也是一样。SQL 提供了图灵完备性来查询和处理数据,但这是有代价的——没有缓存,SQL 几乎总是比 NoSQL 慢。


除此之外,数据库通常是读取优先或写入优先的。这就意味着,它们中的一些在写入数据时速度更快,而另一些在大量读取时性能更佳。


例如,对于需要大量写入、偶尔读取的分析及其他任务,你可能想要选择“写入优先”的数据库,如 Cassandra。


对于显示新闻这样的读取优先任务,最好使用像 MongoDB 这样的东西。


如果两者都需要,就安装两个数据库!这不是不行。这不会造成什么破坏。事情就应该这样做。

多服务器


当一台计算机不够用的时候,可以用两台。当两台不够用的时候,可以买三台,以此类推。


但也有一个陷阱:从 1 到 2 比从 2 到 3 或从 10 到 20 要难得多。


要使用多台计算机,后端应该是无状态的。这意味着你必须将所有数据都存储到数据库中,而后端不保存任何数据。这就是函数式语言在后端如此流行的原因,这也是 Scala 被发明的原因。函数代码默认是无状态的。


无论如何,不同服务器的行为应该完全相同。如果你有大量的有状态服务器,那么根据定义,对相同的输入,它们很容易返回不同的数据作为响应,因为有两个事实来源:数据库和服务器状态。相信我,你不会想让这种事情发生的。


尽快实现无状态。最好从一开始就选择无状态。如果你在使用 NodeJS 和 PM2,如果你想让 PM2 帮你增加运行时以实现负载均衡,那你就必须让代码保持无状态。


负载均衡器会将请求重新路由到最空闲的服务器。显然,对于相同的请求,服务器应该提供完全相同的响应。这就是我们转向无状态的原因。对 NodeJS 来说,PM2 是一个很好的负载均衡选项。如果你用的不是 Node,就选择 Nginx。


会话?把它们保存在 Redis 中,并让所有服务器都可以访问。

缓存和速率限制


想象一下,每 100 毫秒针对每个用户做同样的计算。这将使服务器很容易受到 Slashdot 效应的影响——基本上只是用户访问数据就会导致 DDOS。


增加缓存中间件。只有第一个用户将触发数据查询,其他所有用户将直接从 RAM 接收完全相同的数据。


这也有缺点——默认情况下,数据会过期。通常,缓存中间件允许设置缓存重置时间,数据最终会刷新。


考虑用户和他们的需求,配置相应的缓存。永远不要缓存用户输入。只有服务器输出应该被缓存。


Varnish是一个很好的 HTTP 响应缓存选项,所以它可以用于任何后端。


即使有了缓存,每 10 毫秒就会出现不同的请求,也可能会导致服务器宕机,因为服务器会为它们计算不同的响应。这就是为什么你需要一个速率限制器——如果距离上次请求的时间不够长,正在进行的请求将被拒绝。这将使你的服务器保持活跃。

划分职责


如果你正在使用 SQL 数据库,并且仍然使用后端计算外键,那么你没有充分利用数据库的能力。只需设置记录之间的关系并允许数据库为你计算外键——查询规划器总是比后端更快。


后端应该有不同的职责:哈希、从数据和模板构建网页、管理会话等等。


对于任何与数据管理或数据模型相关的内容,将其作为存储过程或查询移到数据库中。

大数据量


即使是使用数据库集群,最大容量也受限于服务器的主板。你不能只是把无限多的硬盘放在那里。如果想要无限增长,除了使用分布式数据库之外,没有其他选择。它将数据存储在不同的服务器上,最大容量接近所有服务器容量的总和。如果存储空间不足,只需添加另一台服务器即可。


通过主从复制,你可以将 DB 加倍并实现负载均衡,但容量不会无限增长。

可能存在的瓶颈


  • 单线程、有状态、不可扩展的服务器。为了实现负载均衡及运行多台服务器,代码必须是无状态的。

  • 服务器做数据库的工作。将任何与数据相关的工作移到数据库中。

  • 单数据库实例。实现数据库负载均衡,请选用集群。

  • 把读取优先和写入优先搞混了。分析常见任务,有针对性的使用不同类型的数据库。

  • 距离客户端太远。请使用 CDN。

设置举例

小猫



这是你一个晚上就可以在 LAMP 技术栈上构建的基本设置。它是有状态的——它在内存中存储会话和其他杂七杂八的东西。你猜对了,它根本无法扩展。但是,它仍然非常适合小型周末项目。


  • 数据:GB 级

  • 用户:几千

  • 瓶颈:可用性。单服务器,很容易受 Slashdot 效应影响

  • 工具:常规的 LAMP 技术栈

大猫



我们添加了缓存。虽然速度提升了,但由于架构是有状态的,所仍然不可扩展。当你的周末项目用户增加时,你应该这样做。


  • 数据:GB 级

  • 用户:几万

  • 瓶颈:有状态服务器。即使有了缓存,服务器仍是不可扩展的

  • 工具:MongoDB、Express 作为速率限制器和内存缓存

猎豹




这是可扩展的!你可以拥有任意数量的服务器。现在,你可以处理所有可能导致“大猫”宕机的请求,但数据库仍然是运行单个实例,必须处理所有请求。尽管如此,它还是非常适合小型项目、电子商店或类似的东西。


  • 数据:TB 级

  • 用户:十几万

  • 瓶颈:单数据库。使用函数式语言,服务器是可扩展的。但是单个 DB 可能无法处理大量的请求

  • 工具:Go、Redis 缓存、MongoDB

老虎




这个架构速度很快,而且可扩展。看它有多漂亮。DB 和后端都做了负载均衡。这里的瓶颈是,当你运行单个服务器或数据中心时,海外用户可能会面临高延迟,因为他们距离很远。但是,这种设置仍然可以应对许多用户,非常适合新闻网站。


  • 数据:数百 TB

  • 用户:上百万

  • 瓶颈:距离。服务器速度很快,但如果用户距离很远,速度也可能会慢

  • 工具:Go、Redis + Cassandra + MongoDB

狮子




这是一个 CDN——一种完全不同的东西。你在世界各地有多台服务器,它们可以像主服务器一样为请求提供服务。这不像缓存,它们是全功能的。


来自不同大洲的用户通过 DNS 进行隔离。


尽管服务器速度很快,但你仍然受限于一台服务器的容量。你的数据库是主数据库的副本,因此你受限于主数据库的容量。


这非常适合托管提供商、大型电子商务之类的东西。


  • 数据:数百 TB

  • 用户:上千万

  • 瓶颈:大数据量。使用主从复制,无法处理大数据量,你受限于一台 DB 服务器的容量

  • 工具:同上,但 MongoDB 是集群

剑齿虎





这是终极形式。有了 Riak 这样的图形数据库,容量将不再受限。当存储资源不足时,你只需购买一个新的存储服务器并将其添加进去。


非常适合创建像谷歌或 Facebook 那样的应用。


  • 数据:无限

  • 用户:全球用户

  • 瓶颈:价格。其成本就像太空项目

  • 工具:Go、Riak

总结


我们回顾了几乎每类项目的一些最常见的设置。不一定非要使用上述设置——根据自己的需要进行设计。只要记住,每个工具都有它的用途,务必选择适合你的工作的合适工具。


保证可扩展,保证无状态!


原文链接:


https://mvoloskov.hashnode.dev/scalable-architecture-without-magic-and-how-to-build-it-if-youre-not-google?fileGuid=gr8wsimng4sTPe0C

2021 年 6 月 22 日 11:321281
用户头像

发布了 391 篇内容, 共 174.5 次阅读, 收获喜欢 944 次。

关注

评论 2 条评论

发布
用户头像
大佬您好,这篇文章可以转载到公众号吗?会保留原文出处的
2021 年 06 月 23 日 10:21
回复
没有更多了
发现更多内容

高德 Serverless 平台建设及实践

阿里巴巴云原生

Serverless 运维 云原生 监控 中间件

Spring Cloud Kubernetes之实战服务注册与发现

Damon

微服务 5月日更

技术干货|7个 React 性能提升技巧

拍乐云Pano

React

工商银行分布式服务 C10K 场景解决方案

阿里巴巴云原生

容器 微服务 云原生 监控 应用服务中间件

开发者必看,面试官心中的最佳数据库人才模型是什么样?

华为云开发者社区

面试 开发者 华为云数据库 数据库人才

jmeter命令行执行测试并对测试报表进行初步分析

行者AI

测试 Jmeter

Github连夜下架!阿里新产Java全栈面试突击小册太香了

马小晴

Java 编程 程序员 面试 架构师

华为云PB级数据库GaussDB(for Redis)揭秘第九期:与HBase的对比

华为云开发者社区

HBase 华为云 开源数据库 NoSQL数据库 数据库GaussDB(for Redis)

前端开发:基于原生JS的时间过滤实现

三掌柜

5月日更

【LeetCode】解码异或后的排列Java题解

HQ数字卡

算法 LeetCode 5月日更

五一假期回乡,跟大家聊聊感触

架构精进之路

心情 杂记 5月日更

HarmonyOS开发者创新大赛预选赛结束,23支队伍脱颖而出闯入决赛

Geek_283163

鸿蒙

技术实践丨如何解决异步接口请求快慢不均导致的数据错误问题?

华为云开发者社区

JavaScript typescript 前端 浏览器 angular

Python OOP-5

若尘

oop Python编程 5月日更

精选Hive高频面试题11道,附答案详细解析

五分钟学大数据

大数据 hive 5月日更

腾讯T6大牛体系化带你学习Java面向对象,网友:这详解,太清晰了

牛哄哄的java大师

Java 面向对象 面向对象编程

架构实战营-详细架构设计文档

Simon

架构实战营

腾讯云大神亲码“redis深度笔记”,从基础到源码,应有尽有

Java 编程 程序员 架构

阿里云入选 2021 Gartner APM 魔力象限,国内唯一入选云厂商

阿里巴巴云原生

阿里云 容器 微服务 运维 云原生

大数据实战:网站流量日志数据分析

大数据技术指南

大数据 5月日更

耗时1年的前端技术框架切换之旅

华为云开发者社区

前端 软件工程 React 框架

SICP 习题2.6之丘奇数

程序员历小冰

函数式编程 SICP 5月日更

使用docker compose快速部署前后端分离项目案例

皮特王

nginx Docker Vue Docker-compose

一个朋友学会Java泛型后直接薪资翻倍!

北游学Java

Java 泛型

5分钟快速梳理你的HTTP体系

程序员海军

方法论 网络协议 HTTP 语言 & 开发

百度大脑UNIT拍了拍你,提醒你报名智能对话训练营

百度大脑

物联网 智能对话

只会重装系统的运维,不是好运维

运维研习社

Linux 5月日更 系统修复

自动发布.NET Core Web应用

DisonTangor

DevOps 运维自动化 jenkins dotnet

恍然大悟丨Java 中 RMI 的使用

Java架构师迁哥

腾讯Java一面失败后刷题学习3个月,四月斩下腾讯T3 Offer,我的逆袭之路

Crud的程序员

Java spring 编程 程序员 架构

打破思维定式(六)

Changing Lin

5月日更

2021星空论坛:破局创新,论道数字化转型

2021星空论坛:破局创新,论道数字化转型

怎样实现可扩展的架构?-InfoQ