【第四周】架构师训练营作业
作业:
一个典型的大型互联网应用系统使用了哪些技术方案和手段,主要解决什么问题?请列举描述。
0. 前言
一个大型的网站需要面对诸多挑战,这些挑战集中体现为“高并发”、“高性能”、“高可用”,为了应对不同场景带来的挑战就产生了诸多技术及应用,接下来我会简单的介绍一下涉及的技术已经他们所适配的场景。
(图 1)
图 1 列举了一些技术体系并标注的常见的开源实现,接下来我们参考图 1 内容依次介绍。
1. GeoDNS 和 CDN
为什么把这两个放在网站之外,因为大多数网站都是外采服务,自建的比较少。
升级版 DNS
先来说说 GeoDNS,想必 DNS 大家都不陌生。GeoDNS 是可以返回距离用户较近的数据中心 IP 地址。如果我们哟多个数据中心(地域负载均衡和异地多活的目的),因为网络传输的原因,我们当然希望用户访问距离自己更近的数据中心,网络传输距离短可以带来更低的损耗和延时。所以如果我们有多数据中心(不同地域),传统 DNS 可以不适合我们的需求,我们需要更加智能的 GeoDNS。
云中缓存
再说一下 CDN,CDN 全称内容分发网络,CDN 的主要目的是希望用户在离自己最近的 CDN 节点服务器上访问到缓存的信息。通常我们将静态内容,如 HTML 页面、JS、CSS、图片等放到 CDN 上。CDN 有两种方式缓存内容,源网站主动推送,首次访问回源。CDN 还有一个目的是优化访问网络链路,这样对于动态内容请求也会从网络传输角度有一定加速访问效果。如果我们网站中有大量的静态资源,且查询场景比较多,可以适时使用 CDN 提升用户访问速度和体验。
2. 防火墙
定义
安全是网站重要需求,所以与外网交界的第一个入口就交由防火墙处理。
防火墙支持丰富的攻击防范功能。包括:Land、Smurf、UDP Snork attack、UDP Chargen DoS attack (Fraggle)、Large ICMP Traffic 、Ping of Death、Tiny Fragment 、Tear Drop、IP Spoofing、IP 分片报文、ARP 欺骗、ARP 主动反向查询、TCP 报文标志位不合法、超大 ICMP 报文、地址扫描、端口扫描等攻击防范,还包括针对 SYN Flood、UPD Flood、ICMP Flood、DNS Flood、CC 等常见 DDoS 攻击的检测防御。
以上内容是我 copy 的,总之,安全是大型网站重中之重,也会贯穿整个系统,防火墙就是第一道防线。通常防火墙由硬件提供,我们也可以购买高仿 IP 等云服务产品提供一定的安全能力。
3. 网关服务
定义
网关作为业务层对外提供服务的边界(防火墙应该不算业务),将系统外用户请求进行统一收口管理。
功能
试想一下,当我们将系统按照业务线进行纵向划分之后,我们会发现总有重复的一些前置业务(原来写在 filter 中)需要各个业务线重复开发,这包括:
认证、鉴权
限流、服务降级、熔断
防爬
监控告警
路由转发,参数转换
跨域
重复开发就是“坏味道”,为了消除这样的坏味道,我们将这些重复功能提升到网关层统一实现。
网关层作为系统业务边界也起到了保障系统安全,但和防火墙不同的是,防护墙防范的是网络类型攻击,而网关保障的业务安全性。
4. 负载均衡
定义及场景
大型网站都不可能只部署于一台服务器之上,通常都是多机集群方式部署。一是多机方式分担访问压力,二是避免单点,一台机器故障,依然有其他机器提供服务。
负载均衡就是将用户请求根据不同的负载均衡算法将用户请求转发分配的后端服务器进行处理。
负载均衡面面观:
分类
负载均衡有四层(TCP)和七层(HTTP)之分,前者工作在四层网络使用 IP 地址和端口作为分配依据,后者工作于七层网络使用 URL 和 HTTP head 作为分配依据。
负载均衡有软硬之分,顾名思义,硬负载均衡由硬件实现(F5),软负载均衡由软件实现(Nginx)。
算法
负载均衡算法有:轮询,加权轮询,最小连接数,加权最小连接数。我们可以根据业务场景选择。
附加功能
通常负载均衡还支持用户黏连,当下使用集中式 session 管理居多,这个功能也就不常用了。
负载均衡也支持服务健康检测,定期向后端服务发送心跳请求确实服务是否健康,将不健康服务移除。
现实应用
图 1 中画了两个负载均衡,一个在 Web 服务器之前,一个在后端服务器之前,理论上集群前需要配置负载均衡,但是实际场景中很多框架和中间件都自带服务负载均衡的能力,如 Dubbo,K8s 等。
通常各大网站都在 Nginx 基础上开发自己的软 SLB 服务,增加集群管理,动态配置,多种负载均衡算法,后端连接优化等功能,满足日常高性能、高可用需要。
5. Web 服务器
职责
Web 服务器的主要职责是为 HTTP 协议提供静态页面(HTML)的服务容器,承接用户对静态页面的访问请求。
前后分离、动静分离
前后端分离这种开发模式不仅方便前端工程师和后端工程师人员职责分工。也将用户的展示需求和数据需求做了技术职责分工。Web 服务器专注于静态页面展示,而后端服务器专注于数据获取,两种服务器各司其职,只专注于自己的使用场景(这很符合 SRP),可以达到更好的性能。
Web 服务器是前后分离模式和动静分离模式实践工具。
6. 静态页面缓存服务器
职责
页面缓存服务器也是一种代理服务器,通常至于后端服务之前。缓存服务器会根据缓存规则,在用户首次请求时,将 URL 请求的页面整体进行缓存,用户再次请求时,直接从缓存服务器获取,无需访问后端服务器。这样带来两个好处:提升用户访问速度,降低后端服务压力。
场景
在非前后分离模式的系统中,页面渲染工作由后端服务负责(例如 JSP,servlet,frammark 等),如果我们有大量的静态或半静态(实时性要求不高)页面显示需求,就很适合使用缓存服务器。
但是在前后端分离模式的系统中,页面渲染由 Web 服务器(静态页面)和用户终端(浏览器、APP)负责。后端服务只提供动态数据,无法对其进行页面维度缓存。这里再使用缓存服务器就得不偿失了。
7. 分布式服务
为什么需要分布式服务?
随着业务规模扩大单体应用架构发展的一定阶段之后必然带来代码庞大,编译、上线困难,业务耦合无法快速等诸多困难。
将单体应用拆分为分布式应用可以为系统带来独立的业务扩展性,每个业务可以由单独团队独立开发、测试、部署、上线,快速支撑业务。
除了业务扩展性,技术扩展性分布式服务带来的另一大优势,我们无需固守统一技术栈,可以根据业务特点选择不同的技术栈开发落地。
面临的问题
从单体应用到分布式服务演化之后,进程内方法调用就会变成远程调用(RPC),提到远程调用就不可避免的涉及以下问题:
调用、被调用方传输数据的序列化、反序列化问题
调用、被调用方进程间通信方式和协议问题
被调用方如何让调用发发现自己。
如何确保服务间高可用
调用方、被调用方代码必须简单,易于集成
以上这些问题都是分布式服务中间件解决的问题,分布式服务中间件封装了 RPC 的底层细节和复杂性,让我们像调用本地方法一样使用远程服务。
如何解决
所以为了应对分布式拆分后代理的 RPC 挑战,我们需要选择一款合适的分布式服务中间件将 RPC 调用细节和业务逻辑解耦,让团队更加专注于业务实现,让业务梳理落地。
8. 分布式协调服务
什么是分布式协调服务?
想要了解什么是分布式协调服务,需要先了解什么是分布式协调?
我举个例子:snowflake 算法我们应该都了解,使用 snowflake 算法的节点需要确定自己的 workId,workId 不能重复(不能用 UUID 呀,有位数限制)。这样场景如何处理?简单的思路是节点间相互询问,第一个节点上线时候自己定义一个数值,第二个节点上线查看第一个节点值然后个自己分配一个不同的数值,第三个节点需要查看前两个节点的值后重复相同动作,后续节点以此类推。
在分布式系统中,某个节点需要通过了解其他节点信息或行为才能确定自己的信息或行为的场景就是分布式协调问题。如上面的例子,每个节点为了保证 workID 不同,都需要知道其他节点的 workerID 信息,显然单靠节点间是无法保证的,因为没有一个节点知道所有节点的信息。我们需要一个“上帝视角”的服务,这个服务会知晓所有节点信息以协调各自。而这样的服务就是分布式协调服务。
系统中分布式协调场景
根据分布式协调定义,我们能发现系统中很多类似场景:
主从(备):节点间协调谁是主、谁是从(备),一旦主节点异常,在从节点中协调出新的主节点。
服务注册、服务发现:服务的消费者节点需要了解所有服务生产者节点以备调用。
分布式锁:协调那些节点可以获得锁,那些节点需要等待。
这些问题是只是我们在分布式场景下遇到的一部分,分布式协调服务就是将这些问题抽象化,通过提供共性接口为我们解决形形色色的分布式协调问题,让我们能更加关注业务,而不会陷入到分布式协调的泥坑中。
9. 分布式缓存
场景:
还记的刚才我们说的静态页面缓存服务器吗,除了页面缓存之外,我们也可以对动态的数据进行缓存,分布式缓存就是承接这样的工作。通常我们将复杂的计算结果和缓慢的数据源返回结果进行缓存,下次访问系统数据直接从缓存获取,在一定时间内避免重复计算和数据获取。既即提升用户访问速度,又降低了缓存背后服务压力。
使用缓存是大型网站提升性能很重要的技术手段,前面的 CDN,页面缓存服务器都是这种思路的实际体现。
10. 分布式消息队列
面临问题:
分布式系统通常面临很多问题?
模块间接口相互调用,接口响应时长无法保证,接口间强依赖,一个接口调用失败会影响其他接口。
模块间业务相互依赖,相互耦合。业务修改往往牵连多个部分被动修改。
存在访问不均现象,有短时间涌入大量请求的情况。系统很难对这种顺势洪峰做到快速适配,容易被压垮。
如何解决:
消息队列有三个典型的使用场景:
异步
通过消息可以将系统间同步调用变为异步调用,提升效率,降低依赖。
解耦
通过消息队列以发布订阅的模式运行,发布者无需关心订阅者业务,做到业务解耦。
消峰
短期洪峰请求可以暂存队列中,待后续慢慢处理,避免一下将系统压垮。
以上三个场景就可以应对上面三个问题。消息队列也是在分布式系统中经常被使用的工具。
11. 分布式存储:
场景:
大型网站通常会产生很多数据,其中有一部分是结构化,文本化数据我们可以存储于数据库中,还有一部分类似于图片、各类文件等数据,不适合存储于数据库中,我们需要一类存储服务,既可以提供存储这类非结构数据的能力,又可以隐层底层实现,满足可扩展和高可用需求。分布式存储系统就是解决这类问题的。
分类:
分布式存储通常分为:
块存储
使用方式相当于直接使用硬盘,提供硬盘的分配、挂载、读取、写入能力,通常程序不会使用。
文件存储
使用方式和普通的文件管理系统类似,可以创建、查看目录、写入、读取、查找文件,不是很常用。
对象存储
类似于键值对数据库的使用方式,通过 key 找到相应的对象(文件)。完全摒弃了目录结构和文件访问方式,更加符合互联网使用场景。也是我们最多用到的场景,通常我们将图片、日志文件、备份信息等零散小文件存储于对象存储中。
12. 分布式数据库
场景
数据是网站运行的核心,可以说一起业务都是围绕的数据开展的。为数据寻找一个可靠、稳定存储方十分重要。关系型数据库作为业界通用的数据存储解决方案,有着广泛的使用。但伴随着互联网业务兴起,网站业务量递增,对数据存储和使用也提出了新的要求,数据库面临的压力越来越大,传统当单库单表数据库使用模式无法满足日益增长的数据需求(即使通过垂直扩容依然无法满足)。我们开始寻求分布式解决方案(水平扩容),将数据库单一节点,扩充到分布式集群。业务上将原来一个数据库一张表中存储的数据拆分到多个数据库多张表。水平扩容既可以提升数据存储也提升了访问性能。
面临的问题
分布式架构虽然带来了收益,但也会面临诸多复杂问题。
如何制定分库分表策略(时间、哈希)
制定好策略之后如何根据策略写入不同数据库不同表中
读取数据的时候如何根据策略选择相应的表
分库后本地事务变成分布式事务
数据库中间件
针对上述问题,在业务开发工程中通过编码的方式解决这些问题显然不太现实。于是各种分布式数据库中间件应运而生,这些中间件屏蔽了分库分表带来的复杂性,让我们像操作单表一样访问数据库,使我们能更加专注于业务逻辑。
谨慎使用
分布式数据库虽然解决了单台数据库存储容量和性能扩展的问题,但是也带来了诸多复杂性,虽然有分布式数据库中间件帮我们屏蔽一定的复杂性。但是依然有一些天然的问题阻碍我们对他的使用。例如分布式事务问题,聚合函数性能问题,复杂 SQL 无法支持等问题。
所以我们遇到问题的时候我们应该首先优化单库性能,或进行垂直升级。只有当其他手段使用过之后依然无法满足需求,我们才会考虑分库分表。我们还要根据业务选择合适的分库策略,我们还要规避或解决分库分表天然问题。
总之,分布式数据库不是解决数据库问题的银弹,我们在使用它之前需要问问自己是否真的需要分布式数据库,我们是否能从分布式数据库中收益并有效规避不利场景。
13. NoSQL 数据库
场景
如果说关系型数据库诞生于企业级系统应用时代,而 NoSQL 数据库就是诞生于互联网应用时代,所以天然适合互联网场景中对数据存储、性能及扩展性的要求。
特性
没有声明式查询语句
不强迫要求预定义模式
非结构数据,格式灵活
最终一致性,非关系数据库的 ACID 特性
对分布式更加友好
分类
键-值数据库:Redis
文档数据库:MongoDB
列族数据库:Cassandra
图数据库:Neo4J
每种数据库都有各自的使用场景,我们可以根据我们业务场景灵活使用,作为关系型数据库的有力补充。
14. 搜索引擎
场景
相信网站建立的初期,你一定写过这样的 SQL"content like '%hello%'",我们就是用这样简陋的技术支持用户初期的对于内容搜索需求。
但随着业务网站内容越来越丰富,简单的 like 已经不能满足用户对搜索结果和效率的需求。用户希望可以有更灵活的查询入口,用户希望返回的查询结构更加精确、智能,用户希望查询的结果根据相关性进行排序,用户希望更快的结果返回速度,总之,用户需要更专业的全文检索服务,搜索引擎就是提供此类服务的不二之选。
15. 大数据平台
场景
随着网站步入正轨,业务蒸蒸日上,为了支撑网站日常运营的各类数据报表需求也与日俱增,原来我们在业务数据库跑一个 SQL 两分钟能统计出来的数据,现在需要跑几个小时。时间还是次要的,当我们发现我的的统计数据的数据源不完全来自于数据库,还来自于运行日志,应用采集的各类数据,如果将这些数据都存储于数据库中后通过 SQL 去统计分析看似是一个不可能完成的任务。更进步一步,老板不再满足于看看运营数据报表,我们需要通过用户以往的行为产生的数据的进行深入的挖掘,勾勒出用户画像,依次为用户提供量身打造的服务,以提升用户满意度,已达到精细化运营的目的。好吧,现在我们明白数据库已经无法满足我们需求,我们需要更专业的解决方案。以 Hadoop 为代表的大数据解决方案就是满足以上场景的最佳选择。
16. 监控平台
场景
如果说前面的描述都是针对各个业务模块的技术解决方案,监控平台就是贯穿于这些模块之中,根据各种监控指标采集、存储、展示各种监控信息和日志信息,让我们能实时了解网站运行状态,出现问题及时发现并迅速定位解决。所以监控平台也是大型网站不可缺少的模块之一。
17. 持续集成部署平台
场景
上面都关注于静态的技术实现,网站的动态开发过程也是我们值得关注地方。CICD 通过持续集成、交付、部署,打通日常的开发、测试、上线的流程,将我们从繁重的打包部署工作中解放出来。
18. 总结
以上简单的介绍了一下大型网站系统所使用的技术和试用场景。最后做三点总结:
不要堆砌技术,每种技术的使用都是循序渐进的,是要解决功能性或非功能性需求的,如果没有相应的场景就没有必要引入对应的技术。如果还是单体应用就不需要分布式中间件。如果数据量不大也不上大数据平台,我们应该将精力放在解决紧要问题之上。
不要一上来陷入某一个具体技术实现中,我们首先要了解业务场景、面临什么问题,选择一个解决这类问题的技术体系和解决方案,选定技术体系后再根据细节做技术选型,确定使用哪种框架或中间件。比如应对数据存储问题,我们可以选择分布式数据或者 NoSQL 数据或者选择混合存储方式,需要先确定我们解决问题的技术体系和解决方案,最后选择合适的技术实现。
不要被技术体系紧固,没有某种技术就是只能做某种业务的。Redis 也可以做消息队列,MongoDB 也可以做缓存,kafka 也可以做数据库,MySQL 也可以实现分布式锁。如果我们都某个场景需求相对简单,也可以从现有系统中间件中选择一种快速实现,避免过早引入过多组件造成系统复杂,未来有更多需求的时候可以替换更专业的实现。
评论