Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >简明入门讲义——如何实现可扩展的 Web 服务

简明入门讲义——如何实现可扩展的 Web 服务

原创
作者头像
FesonX
修改于 2021-05-06 02:29:25
修改于 2021-05-06 02:29:25
9280
举报
@Ian Battaglia on unsplash
@Ian Battaglia on unsplash

一. 服务器

可扩展的应用服务器(Application Server)集群藏身于负载均衡器(Load balance,LB)背后,LB 将负载(即用户请求)平均地分配到各个组或集群的应用服务器上,此时负载均衡器可能运行在 TCP 层(Layer 4),分配请求的方式默认是简单的轮询(Round-Robin),即假设有服务器 A-D,请求依次从 A 分配到 D,列表循环。

现在,小明向你的 Web 服务发起请求,第一个请求可能被分配到服务器 A,第二个请求可能被分配到服务器 C,要求小明每次请求总能获得相同的返回结果,无论请求最终落到哪个服务器上

不改变设计,可能出现下面的情况,小明发起第一次请求,填完密码登录,提示 3 天内直接进入无需填写密码。结果再次登录时,路由到另一个服务器,又一次提示小明登录!原因很简单,这台服务器上面没有小明的 Session。

这个示例引出了扩展性的第一个黄金法则:每个服务器都包含完全相同的代码库,不在本地磁盘或内存上存储任何与用户相关的数据,例如会话(Session)或个人资料。

怎么实现会话保持(Sticky Session) 是水平扩展服务器中的常见问题。

假设请求随机到任一服务器,则必须有一个中心化的存储服务用来保存 Session,并且所有应用服务器都可以访问。这项存储服务独立于应用服务器之外,可以是持久化的数据库或者缓存

如果没有额外的存储服务怎么办,假设现在只有负载均衡器和应用服务器?

我们可以让负载均衡器监听 HTTP 层(Layer 7,应用层) 的请求,当小明第一次请求分配到服务器 A 时,产生一个随机数 r,将它写到 Cookie 中随请求返回。当小明再次请求时,负载均衡器层通过一个哈希函数,计算 Cookie 中的随机数 r,请求即可再次路由到服务器 A。

这个方案节省了存储空间,但引入一个问题,服务器 A 挂掉之后,小明还需重新登录,所幸这不是非常关键的数据,还可以接受。但独立存储也存在自己的问题,最明显的,怎么解决单点问题(Single Point Of Failure)?这个后文再谈。

现在你的关键问题是,如何使多个应用服务器发布时都存有同一份代码?可以借助 capistrano 这个开源项目。

将用户数据移出应用服务器,并解决完全相同代码库问题后,就可以打包为服务器镜像进行统一部署了。

二. 数据库

完成第一步用户数据中心化隔离、代码库同步后,不费多大力气就可以添加多个应用服务器,使你的 Web 服务处理大量并发请求。但 Web 服务还是会变慢甚至挂掉,原因就在中心化的数据库上!

最好从一开始就走反范式的数据设计方式,数据库只做简单的写入和查询操作,其他复杂的操作、约束都通过代码解决。这样你的数据库会更容易进行水平扩展,更方便做迁移,单个数据库实例也不需要很大。

否则,数据量一大,迁移、修改等操作,还是会由于数据库外键约束,导致长时间锁表等问题,或者比反范式设计的数据库消耗更多的内存和 CPU,成本与日俱增。

在进行数据库复制(Replication)时,一般使用主从模式(Master-Slave)。这里的主从采用读写分离,主库负责写,从库定时同步主库的数据,接收读请求。当主库挂掉的时候,从库也不能提升为主库。

为了解决这个问题,在主库上引入双主(Master-Master)或者待命(Standby)模式双主即两个主库(或者两个集群)都可以接收写请求,无论哪一方收到写请求,另一方会立刻同步。待命模式则同一时刻只有一个接收写请求,另一方只做同步。当主库宕机,待命方将自己升为主库,继续提供服务

当你引入了多个数据库(集群)时,最好不要通过硬编码(Hard-code)来解决故障重连问题,开发同学没必要了解你的架构拓扑,而且在你扩展或者收缩集群的时候,开发同学可不想跟着你加班发布。

这时同样可以引入负载均衡器来解决扩展问题。如果你还需要根据用户名分区操作,比如小明分到了新手区 Z,小红分配到新手区 X,那么负载均衡器可能解决不了,因为 MySQL 请求内容是二进制的,对 LB 是透明的

你可以引入分库分表的中间件,在代码层面解决。对于业务开发团队而言,这个中间件的处理过程同样是透明的。

但这个时候请求也只是“可用”,还不够快,是时候考虑引入缓存了。

三. 缓存

相同配置下,以 Redis 为例,缓存在读取和写入上要远胜于 MySQL 这样的关系型数据库。建议只使用 Redis 或者 Memcached 这类基于内存的缓存服务,不要使用基于文件的缓存,这会使数据迁移和复制(水平扩展)变得复杂。

保存缓存数据一般有两种方式

请注意,这里不是在讨论缓存更新的模式,如果感兴趣,可以阅读 缓存更新的套路

其一是基于数据库查询(SQL-Based)来缓存,不难理解,就是把数据库的查询结果保存到缓存中,键名(Key)可以是查询的 SQL 语句哈希,简单粗暴。但这会存在问题,例如前面我们已经用了反范式的设计,尽量避免使用 JOIN 查询,一个语句有时候解决不了查询,怎么办?

这就有第二种方式,直接缓存对象(Object-Based)。一个请求(多次)查询后的数据在代码中“组装”(Assemble)完毕后。例如一个嵌套的数据结构,查询一个小明的个人信息和他的订单,其中订单数组中是一个个独立的订单对象。可以在代码中将数据组装完毕后,直接缓存整个对象。

想想看如果是第一种,你还需要分开缓存多个查询,下次读缓存还要读两次,再组装数据返回给用户,太麻烦了,用户可等不及!

四. 异步

做完了上面的三个步骤,用户可能还在抱怨我不想等!Web 服务的设计可不能像排队买所谓的网红奶茶一样,让一排用户在原地死等。

想象一下你到一个面包店买蛋糕,有这样的情况:

  1. 你要的蛋糕已经提前做好了,店员直接给你,交易完成
  2. 你要的蛋糕卖完了,新一批晚上才出炉
  3. 你要的蛋糕有,但你是给小明祝寿的,上面要有小明寿比南山的字。

情形一对应 Web 服务中的第一种异步模式,提前把内容生产好,等用户消费。典型的场景是个人博客、新闻网站等,提前将 HTML 渲染完毕,通过自动的定时任务或者手动执行脚本将内容上传到服务器,必要的时候配合 CDN(Content Delivery Network)进行加速,用户就可以快速的访问你的网页内容了。

情形二、三你肯定不想在蛋糕店干等,而是希望制作完成的时候,蛋糕店通知你来取就可以了。面包店有自己的订单队列,有些订单可能是加急(加钱)订单,面包店还需要优先处理。这对应 Web 服务中第二种异步方式,将用户的请求转化为异步任务在后台排队处理,用户注册一个监听器,处理完成后就会收到通知了。

相关的服务例如 RabbitMQ、Celery 等等。一旦你发现 Web 服务中有需要等的动作,务必将它异步处理。

参考文献

  1. Lecture 9 Scalability Harvard Web Development David Malan(视频)
  2. Scalability for Dummies

公众号:程序员的碎碎念

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【万人收藏】Twitter工程师从0到1教你设计百万级并发应用
万里征途总是从第一步开始的,构建一个复杂系统也是如此。我们从简单的部分着手,先让所有的功能都在一个服务器上运行。图1-1展示了如何配置单台服务器,让一切都在其上运行,包括Web应用、数据库、缓存等。
博文视点Broadview
2024/01/15
2360
【万人收藏】Twitter工程师从0到1教你设计百万级并发应用
简明入门讲义——一文理清负载均衡和反向代理
负载均衡器(Load Balance,下文简称 LB)更像是一个请求调度中心,主要是为了分发请求。这一角色使得它可以
benny
2021/06/17
1.1K0
简明入门讲义——一文理清负载均衡和反向代理
🏗️ 架构设计中的性能优化与可扩展性:如何找到平衡点? ⚖️
这里推荐一篇实用的文章:《CQRS 与 Event Sourcing:如何高效处理复杂业务场景!》,作者:【喵手】。
bug菌
2024/12/02
2290
🏗️ 架构设计中的性能优化与可扩展性:如何找到平衡点? ⚖️
MySQL - 扩展性 3 负载均衡:眼花缭乱迷人眼
基于这个思路,我们通常的做法是在服务器前端设置一个负载均衡器。负载均衡器的作用是将请求的连接路由到最空闲的可用服务器上。如图 1,显示了一个大型网站负载均衡设置。其中一个负责 HTTP 流量,另一个用于 MySQL 访问。
北国风光
2019/05/09
6320
MySQL - 扩展性 3 负载均衡:眼花缭乱迷人眼
【经典必读】web网站架构演变过程,电商网站升级打怪
前言 我们以javaweb为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变。 该系统具备的功能: 用户模块:用户注册和管理 商品模块:商品展示和管理 交易模块:创建交易和管理 阶段一、单机构建网站 网站的初期,我们经常会在单机上跑我们所有的程序和软件。此时我们使用一个容器,如tomcat、jetty、jboos,然后直接使用JSP/servlet技术,或者使用一些开源的框架如maven+spring+struct+hibernate、maven+spring+springmvc+mybatis
java思维导图
2018/03/15
1.1K0
【经典必读】web网站架构演变过程,电商网站升级打怪
一步一步理解Java企业级应用的可扩展性
老实说,“可扩展性”是个全面且详尽的话题,而且往往得不到充分理解。人们通常认为可扩展性等同于高可用性,笔者见过编程新手和架构师“老手”都建议将集群作为可扩展性和高可用性的解决方案。建议确实没错,但问题是,人们通常是通过互联网搜索,而非实际理解应用本身的情况来实现集群。
九州暮云
2019/08/21
1.1K0
一步一步理解Java企业级应用的可扩展性
1024—牛码同行
1024程序员节来了,我放慢了脚步,打算静下心来,好好享受,可是城市的声音太嘈杂,于是我戴上了耳机,那一刻,时间仿佛停止了,我的世界只有我!
知孤云出岫
2024/10/26
1830
1024—牛码同行
Nginx系列教程(4)nginx处理web应用服务负载均衡功能
在关于高并发负载均衡一文中已经提到,企业在解决高并发问题时,一般有两个方向的处理策略,软件、硬件,硬件上添加负载均衡器分发大量请求,软件上可在高并发瓶颈处:数据库+web服务器两处添加解决方案,其中web服务器前面一层最常用的的添加负载方案就是使用nginx实现负载均衡。
北梦木系生南国
2020/04/02
5530
阿里P9架构师简述从单机至亿级流量大型网站系统架构的演进过程
阶段一、单机构建网站 网站的初期,我们经常会在单机上跑我们所有的程序和软件。此时我们使用一个容器,如tomcat、jetty、jboos,然后直接使用JSP/servlet技术,或者使用一些开源的框架如maven+spring+struct+hibernate、maven+spring+springmvc+mybatis;最后再选择一个数据库管理系统来存储数据,如mysql、sqlserver、oracle,然后通过JDBC进行数据库的连接和操作。 把以上的所有软件都装载同一台机器上,应用跑起来了,也算是一
Java架构
2018/05/04
1.4K0
阿里P9架构师简述从单机至亿级流量大型网站系统架构的演进过程
如何理解 Scalability?
关注「前端向后」微信公众号,你将收获一系列「用心原创」的高质量技术文章,主题包括但不限于前端、Node.js以及服务端技术
ayqy贾杰
2020/01/14
2.2K0
如何理解 Scalability?
普元应用服务器高可靠方案
伴随着网络带宽的提升和移动终端的普及,现代的web应用平台几乎时时刻刻都在处理着来自用户成千上万的访问请求。在某些特定的场景下(如电商抢购、春运抢火车票等),这些web平台要承受瞬间暴涨的用户访问量。如何在高并发请求的情况下做到服务不瘫痪并且给与用户良好的使用体验,是所有web平台都要面临的挑战。构筑具备高可靠的web平台,是企业避免用户流失的重要手段,是增强自身竞争力的必要环节,具有十分重要的意义。
yuanyi928
2022/09/27
1.3K0
普元应用服务器高可靠方案
浅谈Web网站架构演变过程及各阶段所用的技术和架构设计(转)
  我们以javaweb为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变。
wuweixiang
2019/03/12
2K0
浅谈Web网站架构演变过程及各阶段所用的技术和架构设计(转)
大型Web网站架构演变之9大阶段
我们以Java Web为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变。
Java编程指南
2019/08/05
6140
大型Web网站架构演变之9大阶段
图解:从单个服务器扩展到百万用户的系统
你开发了一个网站(例如网上商店、社交网站或者其他任何东西),之后你把它发布到了网上,网站运行良好,每天有几百的访问量,能快速地相响应用户的请求。
刘盼
2019/05/14
1.6K2
可扩展的Web架构和分布式系统(翻译)
原文:Scalable Web Architecture and Distributed Systems
早起的鸟儿有虫吃
2019/06/03
1.1K0
6000 字+,帮你搞懂互联网架构演变历程!
点击关注公众号,Java干货及时送达 作者:小M 来源:https://cnblogs.com/xiaoMzjm/p/5223799.html 前言 我们以javaweb为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变。 该系统具备的功能: 用户模块:用户注册和管理 商品模块:商品展示和管理 交易模块:创建交易和管理 阶段一、单机构建网站 网站的初期,我们经常会在单机上跑我们所有的程序和软件。此时我们使用一个容器,如tomcat、jetty、jboos,然后直接使用JSP/servlet技术
Java技术栈
2022/06/08
3210
6000 字+,帮你搞懂互联网架构演变历程!
架构设计--互联网架构演化
我们常见的大型网站,如百度、淘宝、京东等,都是一个分布式系统。这么复杂的系统也不是一天建成的,每个系统都经历了漫长的演变过程。
爱敲代码的猫
2019/10/16
6500
架构设计--互联网架构演化
大型网站的自强之路
1、大型网站的自强之路 当年马云筹办阿里巴巴的时候并没有说我要做个大型网站,搞个双11,成交额做到千亿级别;马化腾也没有说以后我要做个通讯工具,让13亿乃至更多用户都成为我们的用户……我们现如今看到的各个大型网站或产品都是一步步踏踏实实走过来的,在各种坑和故障中成长起来的。 1.1、一台电脑就是服务器 做过课程设计或者毕业设计的计算机相关的同学都应该有过搭建项目的经验。画一堆界面,结合js和后台实现数据的展现,当然还要有数据来源——数据库,启动一个容器比如tomcat,那么我们就可以在本机上访问我们的网站了
JackieZheng
2018/01/16
8130
大型网站的自强之路
『学习笔记』如何使用 WebLogic 实现负载均衡
🎈今日推荐——https://cloud.tencent.com/developer/article/2465656
数字扫地僧
2024/11/14
2270
『学习笔记』如何使用 WebLogic 实现负载均衡
Java高并发:在AWS上扩展到数百万用户的系统设计
除非你有AWS的背景或者正在申请AWS的相关职位,否则在AWS上的实现细节不需要了解。然而大部分在这里讨论的原理可以应用到除了AWS以外更通用的地方
用户1289394
2020/11/06
1.4K0
推荐阅读
相关推荐
【万人收藏】Twitter工程师从0到1教你设计百万级并发应用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档