前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java高并发:在AWS上扩展到数百万用户的系统设计

Java高并发:在AWS上扩展到数百万用户的系统设计

作者头像
用户1289394
发布2020-11-06 10:23:11
1.3K0
发布2020-11-06 10:23:11
举报
文章被收录于专栏:Java学习网Java学习网

第一步:弄清用例与约束

收集需求和问题的范围 通过问问题来弄清用例与约束 讨论假设

我们假定以下用例

用例

解决这个问题需要采用迭代的方法:

  1. 基准/负载测试
  2. 瓶颈检测
  3. 评估替代方案来解决瓶颈
  4. 重复以上

这是将基本设计升级为可扩展设计的良好模式

除非你有AWS的背景或者正在申请AWS的相关职位,否则在AWS上的实现细节不需要了解。然而大部分在这里讨论的原理可以应用到除了AWS以外更通用的地方

我们将问题约束到如下范围
  • 用户发送读或写请求
    • 服务处理,存储用户数据然后返回结果
  • 服务需要从少量用户发展到数百万用户
    • 在我们升级架构来处理大量用户请求时,讨论通用的扩展模式
  • 服务需要高可用

约束和假设

状态假设
  • 流量分布不均
  • 需要关系型数据
  • 从单个用户扩展到千万级用户
    • 用户数+
    • 用户数++
    • 用户数+++
    • 用户增加的标识:
    • 一千万用户
    • 每月10亿次写入
    • 每月1000亿次读取
    • 100:1读写比
    • 每次写入1KB内容
计算方式

如果你想做一个大致估算,请向你的面试官表明以下数据:

  • 每月1TB数据写入
    • 每次写入1KB数据 * 每月10亿次写入
    • 3年有3TB数据写入
    • 假设大多数写入是新的内容而不是已有内容的更新
  • 平均每秒400次写入
  • 平均每秒40000次读取

方便的转换公式:

  • 每月有250万秒
  • 每秒一个请求 = 每月250万个请求
  • 每秒40个请求 = 每月1亿个请求
  • 每秒400个请求 = 每月10亿个请求

第二步:创建高层设计

大致写出包含所有重要组件的高层设计

第三步:设计核心组件

深入每个核心组件的细节

用例:用户发送读或写的请求

目标
  • 对于仅仅的1-2个用户,你只需要一个基本的配置
    • 简单的单体应用
    • 当需要的时候垂直缩放
    • 监控来确定瓶颈
从单体应用开始
  • EC2上的服务器
    • 存储用户数据
    • MySQL数据库

使用垂直扩展:

  • 选择更好性能的机器
  • 密切关注监控指标以确定如何扩大规模
    • 使用基本监控来确定瓶颈:CPU,内存,IO,网络等
    • CloudWatch, top, nagios, statsd, graphite等
  • 垂直缩放可能会很昂贵
  • 没有故障转移措施

替代方案和其他细节:

  • 垂直扩展的替代是水平扩展
从SQL开始,考虑NoSQL

约束里我们需要关系型数据。我们在开始的时候可以在单机上用MySQL数据库.

替代方案和其他细节:

  • 关系型数据库
  • 使用SQL还是NoSQL的原因
分配公网静态IP
  • 弹性IP提供一个重启之后不会更改的公网端口
  • 有效的帮助故障转移,只需要将域名指向新IP
使用DNS

使用Route 53添加DNS将域名映射到实例的公共IP

替代方案和其他细节:

  • DNS
保护web服务器
  • 开启必要的端口
    • 80 - HTTP
    • 443 - HTTPS
    • 22 - SSH(白名单)
    • 允许web服务器对于以下端口回复:
    • 阻止web服务器进行出站连接

替代方案和其他细节:

  • 安全

第四步:扩展设计

鉴于约束条件,确定并解决瓶颈

假设

我们的用户数正在增加并且在我们单体应用上的负载也在增加。我们的基准/负载测试和瓶颈指向了MySQL数据库占用更多内存和CPU资源,同时用户内容正在填满磁盘空间

到目前为止我们可以通过水平扩展解决问题。但不幸的是已经变得非常昂贵并且MySQL数据库和web服务器无法独立扩展

目标
  • 减轻单体应用的负载并且允许独立扩展
    • 将静态内容分开存储到AWS对象存储
    • 移动MySQL数据库到独立的服务上
  • 缺点
    • 这些改变将增加复杂度并且需要Web服务器指向对象存储和MySQL数据库
    • 新组件额外的安全措施
    • AWS的费用将会增加但应该与自己管理类似系统成本进行权衡
分离存储静态内容
  • 考虑使用S3作为对象存储
    • 高扩展和可靠性
    • 服务端加密
  • 移动静态内容到S3
    • 用户文件
    • JS
    • CSS
    • 图片
    • 视频
移动MySQL数据库到独立的服务
  • 考虑使用RDS服务管理MySQL数据库
    • 扩展和管理简单
    • 多个可用区
    • 静态加密
保护系统
  • 在传输和静止时加密数据
  • 使用虚拟私有网络
    • 为单个Web服务器创建公共子网以便可以发送和接收网上的流量
    • 为其他组件创建私有网络,组织外部访问
    • 每个组件仅仅对白名单IP开放端口
假设

我们的基准/负载测试和瓶颈检测表明我们的单体Web服务器在高峰期出现瓶颈,导致回应慢,在某些情况下宕机。随着服务的成熟,我们希望提高可用性和冗余度

目的
  • 以下目标尝试解决Web服务器的扩展问题
    • 基于基准/负载测试和瓶颈检测,你可能只需要实现这些技术中的一个或者两个
  • 使用水平扩展处理不断增加的负载并解决单体故障
    • ELB是高可用的
    • 如果你想配置自己的负载均衡器, 在多个可用区配置主-主或主-备可以提高可用性
    • 在负载均衡器上关闭SSL去减少在后端服务器上的计算负载并简化证书管理
    • 添加负载均衡器
    • 使用多个Web服务器分布到多个区域
    • 使用多个主从故障切换模式的MySQL实例来增进冗余度
  • 将Web服务器和应用服务器分开
    • 独立扩展和配置这两层
    • Web服务器可以作为反向代理服务器
    • 比如你可以添加应用服务器处理读API而其他应用服务器处理写API
  • 移动静态(和一些动态)内容到CDN比如CloudFount去减少负载和延迟

注意: 为了避免过于混乱,没有显示内部负载均衡器

假设

我们的基准/负载测试和瓶颈检测表明我们的读请求很多(100:1读写比),我们的数据库因为大量读取请求导致性能不佳

目标
  • 以下目标尝试去解决在MySQL数据库上的问题
    • 基于基准/负载测试和瓶颈检测,你可能只需要实现这些技术中的一个或者两个
  • 移动以下数据到内存缓存,比如Elasticache去减少负载和延迟:
    • Web服务器变成无状态服务,允许自动缩放
    • 首先,在实现内存缓存之前试图配置MySQL数据库的缓存看是否足以解决瓶颈
    • 在MySQL中经常读取的内容
    • 来自Web服务器的session数据
    • 从内存读取1MB需要250微秒,而SSD需要4倍的时间,从硬盘读取需要80倍时间
  • 添加MySQL只读副本来减少主服务器的负载
  • 添加更多Web服务器和应用服务器来提升响应
添加MySQL只读副本
  • 除了增加和扩展内存缓存外, MySQL只读副本也能帮助减轻MySQL主节点的负载
  • 添加Web服务器的逻辑来分开读写数据
  • 在MySQL只读副本前添加负载均衡器(图里没画)
假设

我们的基准/负载测试和瓶颈检测表明在正常工作时间内流量激增,在用户离开办公室时显著下降。我们认为我们可以根据实际负载自动调整服务器来降低成本。我们是个小公司,因此我们希望尽可能多地自动缩放

目标
  • 添加自动缩放来根据需求提供实例数量
    • 跟上流量的高峰
    • 通过关闭未使用的实例来减少费用
  • DevOps自动化
    • Chef, Puppet, Ansible等
  • 继续监控指标以解决瓶颈
    • 主机级别 - 查看单个EC2实例
    • 汇总级别 - 查看负载均衡器统计信息
    • 日志分析 - CloudWatch, CloudTrail, Loggly, Splunk, Sumo
    • 外部网站性能 - Pingdom或New Relic
    • 处理通知和时间 - PagerDuty
    • 错误报告 - Sentry
添加自动缩放
  • 考虑AWS的托管服务自动缩放
    • 自动缩放可能会带来复杂性
    • 系统可能需要一段时间才能适当扩展以满足不断增长的需求,或者在需求下降时缩小规模
    • 一段时间内的指标:
    • CPU负载
    • 延迟
    • 网络流量
    • 自定义指标
    • 为每个Web服务器和应用服务器创建一个组, 每个组放到多个可用区中
    • 设置最小和最大实例数
    • 通过CloudWatch触发向上和向下扩展
    • 缺点
假设

随着服务继续朝着约束中的数字增长, 基准/负载测试和瓶颈检测继续迭代来发现和解决新的瓶颈

目标

由于问题的限制,我们将继续解决扩展问题:

  • 如果我们的MySQL数据库开始变得非常大,我们可能会考虑只将有限时间段的数据存储在数据库中,同时将其余数据存储在Redshift等数据仓库中
    • 像Redshift这样的数据仓库可以轻松处理每月1TB的新内容
  • 每秒平均读取请求4万次,读取常用数据的流量可以通过扩展内存缓存来解决,这对于处理不均匀分布的流量和流量峰值也很有用
    • SQL只读副本可能在处理缓存未命中时遇到问题,我们可能需要采用其他SQL扩展模式
  • 对于单个SQL写服务来说,每秒400次平均写入次数(可能更高的峰值)可能很难,同时也表明需要额外的缩放技术

SQL扩展模式包括:

  • 联合
  • 分片
  • 非规范化
  • SQL调优

为了进一步解决高读取和写入请求,我们还应考虑将适当的数据移动到NoSQL数据库,例如DynamoDB

我们可以进一步分离应用服务器来允许独立的缩放。不需要实时完成的批处理和计算可以使用队列和工作程序异步完成:

  • 例如,在照片服务中,照片上传和缩略图创建可以分开:
    • 创建缩略图
    • 上传到数据库
    • 存储缩略图到对象存储
    • 客户端上传图片
    • 应用程序服务器放一个任务到队列
    • 工作服务从队列中拉取到任务:
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java学习网 微信公众号,前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一步:弄清用例与约束
    • 用例
      • 我们将问题约束到如下范围
    • 约束和假设
      • 状态假设
      • 计算方式
  • 第二步:创建高层设计
  • 第三步:设计核心组件
    • 用例:用户发送读或写的请求
      • 目标
      • 从单体应用开始
      • 从SQL开始,考虑NoSQL
      • 分配公网静态IP
      • 使用DNS
      • 保护web服务器
      • 假设
      • 目标
      • 分离存储静态内容
      • 移动MySQL数据库到独立的服务
      • 保护系统
      • 假设
      • 目的
      • 假设
      • 目标
      • 添加MySQL只读副本
      • 假设
      • 目标
      • 添加自动缩放
      • 假设
      • 目标
  • 第四步:扩展设计
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档