亿级流量网站架构核心技术 跟开涛学搭建高可用高并发系统

ISBN:978-7-121-30954-0
作者:张开涛
页数:447页
阅读时间:2021-11-28
推荐指数:★★★★★

Java架构师必读书目之一,
从原理出发,一步一步深入,
实战中的解决方案都能在这里面找到,
非常推荐仔细阅读。

亿级流量网站架构核心技术 跟开涛学搭建高可用高并发系统

在资源有限的情况下,一定是先解决当下最核心的问题。
系统设计是一个不断迭代的过程,在迭代中发现问题并修复问题,即满足需求的系统是不断迭代优化出来的,这是一个持续的过程,个人不相信存在完美架构银弹。

1.高并发原则

1.1 无状态

1.2 拆分

   系统维度、功能维度、读写维度、AOP维度、模块维度

1.3 服务化

   进程内服务->单机远程服务->集群手动注册服务->自动注册和发现服务->服务的分组/隔离/路由->服务治理放在括号内。

1.4 消息队列

1.5 数据异构

数据异构、数据闭环。

1.6 缓存银弹

流程节点 缓存技术
客户端 使用浏览器缓存
客户端应用缓存
客户端网络 代理服务器开启缓存
广域网 使用代理服务器(含CDN)
使用镜像服务器
使用P2P技术
源站及源站网络 使用接入层提供的缓存机制
使用应用层提供的缓存机制
使用分布式缓存
静态化、伪静态化
使用服务器操作系统提供的缓存机制

1.7 并发化

2 高可用原则

2.1 降级

开关集中化管理、可降级的多级读服务、开关前置化、业务降级

2.2 限流

2.3 切流量

DNS、HttpDNS、LVS/HaProxy、Nginx

2.4 可回滚

3 业务设计原则

3.1 防重设计

3.2 幂等设计

3.3 流程可定义

3.4 状态与状态机

3.5 后台系统操作可反馈

3.6 后台系统审批化

3.7 文档和注释

3.8 备份

4 负载均衡与反向代理

一个域名可以映射多个ip地址,但是当一个主机故障时,DNS有一定的缓存时间,故障后切换时间长,而且没有对后端服务进行心跳检查和失败重试的机制。

为了提升整体吞吐量,会在DNS和Nginx之间引入接入层,比如使用LVS(软件负载均衡)F5(硬件负载均衡)

接入层、反向代理服务器、负载均衡服务器都指Nginx。

上游服务器配置:upstream server配置

负载均衡算法:配置多个上游服务器负载均衡机制。

失败重试机制:当配置超时或不存活时,是否重试其他上游服务器。

服务器心跳检查:上游服务器健康 检查、心跳检查。

负载均衡算法:轮询、ip hash

Http动态负载均衡、静态配置。

Consul+Consul-template

Consul+OpenResty

5 隔离

系统隔离是为了在系统发生故障时,能限定传播范围和影响范围。

5.1 线程隔离(线程池隔离)

5.2 进程隔离

5.3 集群隔离

5.4 机房隔离

5.5 读写隔离

5.6 动静隔离

5.7 爬虫隔离

5.8 热点隔离

5.9 资源隔离

隔离实现技术:Hystrix、Servlet3

Servlet3请求解析和业务处理线程池分离、Servlet3异步化

可以使用BIO压测、Servlet3 NIO异步化压测。

Tomcat处理流程

1.容器负责接收并解析请求为HttpServletRequest。

2.然后交给Servlet进行业务处理。

3.最后通过HttpServletResonse写出响应。

6 限流

限流算法:令牌桶算法、漏桶算法。

应用级限流:并发数、连接数、请求数。

分布式限流:Redis+Lua实现、Nginx+Lua实现

接入层限流:ngx_http_limit_conn_module、ngx_http_limit_req_module、lua-resty-limit-traffic

节流

1.throttleFirst/throttleLast

指在一个时间窗口内,如果有重复多个相同事件要处理,只处理第一个或最后一个。

前段可以使用jquery-throttle-debounce-plugin实现、Android可以用RxAndroid实现。

2.throttleWithTimeout

也叫做debounce(去抖),限制两个连续事件先后执行时间不得小于某个时间窗口。

Java可以使用RxJava实现。

7 降级

Hystrix可以实现降级、熔断。

Turbine WAR、Hystrix Dashboard WAR

名称 说明
页面降级 切换到指定页面
页面片段降级 商品页商家部分信息错误,可以进行降级
页面异步请求降级 异步加载请求响应慢,可降级
服务功能降级 不太重要的服务异常时不获取信息。
读降级 多级缓存模式,后端有问题降级为只读。
写降级 只进行Cache更新,异步扣除库存信息到DB,保证最终一致性
爬虫降级 将爬虫流量导向静态页或返回空数据
风控降级 识别机器人
超时降级 相应慢自动降级
统计失败次数降级 到一定数量自动降级
故障降级 网络故障等
限流降级 访问量大时

8 超时与重试机制

代理层超时与重试:Haproxy、Nginx、Twemproxy

Web容器超时:Tomcat、Jetty

中间件客户端超时与重试:JSF、Doubbo、JMQ、CXF、Httpclient

数据库客户端超时:MySQL、Oracle

NoSQL客户端超时:Mongo、Redis

业务超时:任务型、服务调用型

前端Ajax超时

9 回滚机制

事务表、消息队列、补偿机制(执行/回滚)、TCC模式(预占/确认/取消)、Sagas模式(拆分事务+补偿机制)

9.1 代码库回滚

9.2 部署版本回滚

版本化、小版本增量发布、大版本灰度发布、架构升级并发发布、

9.3 数据版本回滚

9.4 静态资源版本回滚

10 压测与预案

10.1 系统压测

压测方案:压测接口、并发量、压测策略(突发、逐步加压、并发量)、压测指标(机器负载、QPS/TPS、响应时间)、压测报告、成功率、相关参数(JVM参数、压缩参数)。

压测工具:JMeter、Apache ab

线下压测、线上压测、全链路压测、读压测、仿真压测、隔离集群压测、单机压测。

10.2 系统优化和容灾

代码走查

10.3 应急预案

首先进行系统分级,然后进行全链路分析、配置监控报警,最后制定应急预案。

网络接入层、应用接入层、Web应用层和服务层

11 应用级缓存

11.1 缓存

经常读取数据、频繁访问数据、热点数据、IO瓶颈数据、计算昂贵数据、符合5分钟法则和局部性原理数据均可进行缓存。

CPU->L1/L2/L3->内存->磁盘

11.2 缓存命中率

缓存命中率 = 从缓存中读取次数/[总读取次数(从缓冲中读取次数+从慢速设备上读取次数)]

11.3 缓存回收策略

基于空间、容量、时间、Java对象引用、弱引用。

TTL(Time To Live):存活期,即缓存数据从创建开始直到到期的一个时间段(不管在这个时间段内有没有被访问,缓存数据都将过期)。

TTI(Time To Idle)空闲期,即缓存数据多久没被访问后移除缓存的时间。

回收算法:

FIFO(First In First Out)先进先出。

LRU(Least Recently Used)最近最少使用算法。

LFU(Least Frequently Used)最不常用算法。

实际中使用LRU比较多,如:Guava Cache、Ehcache。

堆缓存:使用Java堆内存来存储对象。好处是没有序列化/反序列化,是最快的缓存。缺点是数据量大时GC暂停时间会变长,存储容量受限于堆空间大小。

实现:Guava Cache、Ehcache 3.x、MapDB

堆外缓存:存储在堆外内存,可以减少GC暂停时间,可以支持更大的缓存空间,只受机器内存大小限制,不受堆空间影响。但是读取数据需要序列化/反序列化,比堆缓存慢很多。

实现:Ehcashe 3.x、MapDB

磁盘缓存:存储在磁盘上,JVM重启时数据还在,而堆缓存、堆外缓存都会丢失。

实现:Ehcache 3.x、MapDB

分布式缓存:

  1. 单机容量问题

  2. 数据一致性问题

  3. 数据不命中问题

单机:存储最热的数据到堆缓存,相对热的数据到堆外缓存,不热的数据到磁盘缓存。

集群:存储最热的数据到堆缓存,相对热的数据到堆外缓存,全量数据到分布式缓存。

缓存使用模式:

Cache-Aside、Cache-As-SoR、Read-Through、Write-Through、Write-Bhind、Copy Pattern

SoR(System-Of-Record):记录系统

可以用JMH进行测试。

11.4 HTTP缓存

Last-Modified文档最后修改时间。

F5刷新、Ctr+F5强制刷新、Age响应头、Vary代理层缓存、Via代理层、ETag发送到服务器进行内容变更验证。

11.5 HttpClient客户端缓存

Cache-Control设置说明

public 共享缓存,客户端和代理服务器都可缓存,响应可被缓存。
private 私有缓存,客户端可缓存、代理服务器不能缓存,永恒私有内容不能共享。
no-cache 允许缓存者缓存响应,但需要回源验证。
no-store 请求和响应禁止缓存。
max-age 保鲜期和Expires类似,根据该值校验缓存是否新鲜。
s-maxage 与max-age区别是仅用于共享缓存,不新鲜时遇到此头要重新验证。
max-stale 缓存的最大陈旧时间,如果缓存不新鲜但还在该最大陈旧时间内,则可以返回陈旧的内容。
min-fresh 最小新鲜期,使用(保鲜期-当前Age)< min-fresh判断内容是否新鲜。
must-revalidate 当缓存过了新鲜期后,必须回源重新验证。与no-cache类似,但更严格,不能使用后台重新验证,而no-cache允许后台重新验证。
proxy-revalidate 与must-revalidate类似,但是,只对缓存代理服务器有效,客户端遇到此头需要回源重新验证。
stale-while-revalidate 请求时,表示在指定的时间内可以先返回陈旧的内容,后台进行重新验证(异步验证)。
state-if-error 在指定时间出现500、502、503、504时,可以使用陈旧内容。
only-if-cached 该头表示只从缓存获取响应,如果没有则504,Gateway Timeout

11.6 Nginx HTTP缓存设置

11.7 Nginx 代理层缓存

11.8 如何缓存数据

不过期缓存:首先写数据库,如果成功则写缓存。不要把写缓存放到事务中。

过期缓存:懒加载,先读取缓存,不命中则查询数据,异步写入缓存并设置过期时间。

11.9 大Value缓存

Memcached来缓存大Value;或者对Value进行压缩;或拆分多个小Value。

12 连接池

池子不能太大,会影响GC的扫描时间。

池化可以使用:Apache commons-pool2来实现。DBCP、Jedis都是使用这个实现。

12.1 数据库连接池

C3P0、DBCP、Druid、HikariCP

注意网络阻塞、不稳定时的级联效应,等待超时应该尽可能小点。

12.2 HttpClient连接池

实现:HttpClient

12.3 线程池

减少频繁创建和销毁线程来降低性能的损耗。

I/O密集型、CPU密集型。

13 异步并发

当服务比较慢时,让出线程和CPU来处理下一个请求。

当一个线程在处理任务时,通过Fork多个线程来处理任务并等待这些线程的处理结果,这种应用并不是真正的异步。异步是针对CPU和I/O的,当I/O没有就绪时要让出CPU来处理其他任务,这才是异步。

13.1 异步Future

阻塞主请求,高并发时会造成线程过多、CPU上下文切换。

13.2 异步Callback

通过回调机制实现,并不能提升性能,而是为了支撑大量并发连接或者提升吞吐量。

13.3 异步编排CompletableFuture

使用ForkJoinPool实现异步处理。

场景一是三个服务异步并发调用,然后对结果合并处理,不阻塞主线程。

场景二是两个服务并发调用,然后消费结果,不阻塞主线程。

场景三是Service1执行完成后,接着并发执行Service2和Service3,然后消费相关结果,不阻塞主线程。

13.4 异步Web服务实现

Servlet3、CompletableFuture实现异步Web服务。

13.5 请求缓存

将GetProductService包装一层JVM缓存。

13.6 请求合并

CompletableFuture必须提前构造好批量查询,而Hystrix支持将多个单个请求转换为单个批量请求。可以按照单个命令来请求,但实际是以批量请求模式执行。

14 如何扩容

单体应用垂直扩容:升级硬件配置

单体应用水平扩容:部署多个镜像

应用拆分、数据库拆分(分库分表、取模分区)、Sharding-jdbc读写分离、数据异构。

查询维度异构、聚合数据异构。

任务系统扩容:Thread、Timer、ScheduledExecutor、Quartz单机版即可。

分布式任务:Quartz集群版、tbschedule、Elastic-Job、Elastic-Job-Lite。

15 队列术

异步处理、系统解耦、数据同步、流量削峰、扩展性、缓冲。

缓冲队列、任务队列、消息队列、请求队列、数据总线队列、混合队列、优先级队列、副本队列、镜像队列、队列并发数、推送拉取。

实现:Disruptor+Redis队列、Canal实现数据异构。

16 架构

16.1 架构1.0

IIS+C#+SQL Server架构,扛不住时加了一层memcached来缓存数据。

16.1 架构2.0

MQ消息通知、Java Worker调用多个依赖系统、rsync同步到其他机器、Nginx静态页、接入层负责负载均衡。

16.1 架构3.0

迅速响应迅速变化的需求和各种变种的需求、支持各种垂直化页面改版、页面模块化、AB测试、高性能、水平扩容、多机房多活异地多活。

17 OpenResty

单DB架构、DB+Cache/数据库读写分离架构、OpenResty+Local Redis+MySQL集群架构、OpenResty+Redis集群+MySQL集群架构

Redis+Twemproxy

MySQL+Atlas

Nginx+Lua

技术选型:

MQ:ActiveMQ

RPC:Dubbo

KV:SSDB或者ARDB

缓存:Redis

前端模板拼装:OpenResty

SSDB/Redis分片使用Twemproxy

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容