配置环境:
服务器环境: 4 台服务器(阿里云服务器: 4核8G 内存)
云原生迁移: 10 台服务器环境 ----- kubernetes 容器云
1、 如何从架构的角度思考问题, 如何构建一个高可用, 高性能的架构的系统(架构设
计, 架构思路—如何选择一个合适的架构)gateway作为网关,springcloud alibaba作为微服务
架构,nacos作为注册中心,feign作为rpc调用,sentinel作为限流组件,前置openrestry 3台用来存放静态页面,jwt鉴权,redis操作,缓存操作等,然后路由到3台gateway,gateway作为路由分发到后置微服务,微服务操作mysql,mysql2主2从架构,保证高可用,redis采用3主3从集群。rocketmq2主2从异步刷盘架构。
2、 压力测试, 及时发现系统的问题, 系统瓶颈; 根据压力测试结果, 对系统进行性能
的优化, 问题修复, 验证优化结果。一般mysql的压力在写操作,这里做读写分离策略。
3、 服务端优化(tomcat 服务器优化, undertow 优化), 压力测试。尽量多用undertow,因为undertow底层做了优化,不在提供jsp,专注于对外提供http 服务。
4、 JVM 优化(GC 日志分析, 根据调优日志对 jvm 进行进一步的线上的环境调优--- jvm
调优原理)easygc可以很好的进行监控调优,并且提供了可视化的界面操作。
5、 数据库调优(数据库调优, 连接池, 缓存, 表设计,)jmeter压测mysql获取连接池的最好
参数,一般为cpu的核数的2倍。表结构设计尽量不要采用三范式,三范式虽然没有数据冗余但是
效率低下,尤其是连表操作。
6、 多级缓存(堆内缓存, 分布式缓存, 接入层缓存: openresty 内存字典 , lua+redis
实现缓存)。三级缓存分别为: openrestry->jvm(guava)->redis
7、 秒杀下单(高并发下写操作)----- Lock 锁, Aop 锁, 分布式锁(MySQL, redis, zookeeper)。分布式锁尽量用redission架构,效率高,不要使用mysql的悲观锁和乐观锁。
如果要保证数据强一致性用zk作为分布式锁也是可以的。效率比redis低比mysql高。
--- 对锁进行优化
8、 写异步(队列对下单进行优化 : BlockingQueue,RocketMQ),使用阻塞队列或者rocketmq来进行削峰填谷,大流量泄洪等。
9、 数据一致性问题处理(RocketMQ 最终消息一致性) ---- 考虑性能,rocketmq的事务性消息可以很好的保证数据的一致性,两阶段提交可以做到mysql和redis一致性,我们也可以通过延迟双删,redission锁或者canal来保证一致性,最方便的就是用redission来操作。
10、 架构进行重构 (单体架构重构为微服务架构, SpringCloud alibaba)
11、 分布式环境下接口幂等性的问题。1.通过业务状态位来记录 2.也可以通过openresty标记处理进度+aop来拦截该操作+自定义注解可以很好的屏蔽掉幂等性问题,让程序员专注于业务。
12、 分布式环境下数据一致性的问题(强一致性),1.加锁redission来解决 2.rocketmq事务性消息来保证
13、 防刷限流技术(防止后端服务被大流量冲垮)。1.单机:guava,redis都可以限流 2.集群sentinel.
14、 kubernetes 云原生迁移(把微服务架构迁移到云原生模式下)
二:架构策略
分层: 分层拆分(表现层, 业务层, 持久层)
分割: 连接池分割, 机房, 进程(分布式)
分布式: 分布式架构
集群: 高可用
缓存: 堆内存缓存, redis 缓存, lua 缓存
异步: 写异步
冗余: 数据库设计, 读, 写
安全: 数据安全(加密)、 系统安全
自动: 运维, 扩容, 缩容;
敏捷: 可持续集成, 交付, 部署
三:单体架构能否承受住亿级流量
场景: 某电商网站, 100w 订单 / day 订单产生时间段
计算系统流量:
每下一单, 发送了多少个请求? ? ? ---- 平均下一单: 50 请求
流量: 100w * (50 x 3) = 1.5 亿
计算: 平均每一台服务器需要承担多大并发? ?
1.5 亿 / 12h = 1250w QPS /h
1250QPS / 60 = 21w QPS /h
21w / 60s = 3400 QPS / s ----- 4cpu,8GB
结论: 单体架构完全可以承受亿级流量; 根据以上估算, 最终落在每台服务器 3400 / s QPS,
因此对于单体架构来说, 完全 ok;
缺点:如果流量集中则会系统崩溃
4.软件架构中的高可用设计
高可用 HA(High Availability):通过设计减少系统不能提供服务的时间
服务年度可用时间%=(1-故障时间/年度时间) × 100%
5个9,即可用率99.999%,全年有5分钟停机
解决高可用问题具体有哪些方案:
1、 负载均衡:DNS&nginx 负载均衡
以上负载均衡方案是接入层的方案, 实际上负载均衡的地方还有很多:
1、 服务和服务 RPC --- RPC 框架 提供负载方案 ( SpringCloud)
2、 数据集群需要负载均衡(mycat,haproxy,rocketmq)
可以通过插件模块来监控nginx:
插件名:nginx_upstream_check_module
Nginx安装及 nginx_upstream_check_module(nginx主动健康检查模块)和nginx-upsync-module(nginx服务发现模块)安装 - 知乎1.在 /opt/下安装,进入/opt/目录 cd /opt/获取nginx-1.19.6.tar.gz安装包 wget http://nginx.org/download/nginx-1.19.6.tar.gz2.下载对应模块 nginx_upstream_check_module:nginx主动健康检查模块和nginx-upsyn…https://zhuanlan.zhihu.com/p/431011724
2、 限流
2.1: 漏桶算法:把请求比作是水, 水来了都先放进桶里, 并以限定的速度出水, 当水来得过猛而出水不够快时就会导致水直接溢出, 即拒绝服务
2.2: 令牌桶算法
2.3:Tomcat 限流
2.4:接口限流
2.5:Redis 限流
2.6:Nginx 限流
对于 Nginx 接入层限流可以使用 Nginx 自带的两个模块:
连接数限流模块 ngx_http_limit_conn_module
漏桶算法实现的请求限流模块 ngx_http_limit_req_module
3、 降级
当访问量剧增、 服务出现问题( 如响应时间长或不响应) 或非核心服务影响到核心流
程的性能时, 仍然需要保证服务还是可用的, 即使是有损服务。 系统可以根据一些关键数据
进行自动降级, 也可以配置开关实现人工降级
4、 隔离:发生故障后不会出现滚雪球效应, 从而保证只有出问题的服务不可用, 其他服务
还是可用的。在实际生产环境中, 比较多的隔离手段有线程隔离、 进程隔离、 集群隔离、 机房隔离、 读写隔离、 快慢隔离、 动静隔离等。
4.1线程隔离主要指的是 线程池 隔离。 请求分类, 交给不同的线程池进行处理。 一个请求
出现异常, 不会导致故障扩散到其他线程池
4.2进程隔离:
把项目拆分为一个个的子项目, 然后让这些子项目进行物理隔离。 项目和项目之间没有调
用关系
4.3集群隔离
项目上线后, 一定会进行集群部署, 为了提高服务高可用性, 采用集群隔离术
对项目进行集群部署; 每一个部署结构都是一个进程, 当一个进程发生问题的时候, 其他
进程不会受到影响
4.4读写隔离
Redis 主从 – 读写分离
4.5:动静隔离
把静态资源放入 nginx, CDN 服务。 达到动静隔离。 防止有页面直接加载大量静态资源
因为访问量大, 导致网络带宽打满,导致卡死, 出现不可用
4.6:热点隔离
秒杀、 抢购属于非常合适的热点例子, 对于这种热点, 是能提前知道的, 所以可以将秒
杀和抢购做成独立系统或服务进行隔离, 从而保证秒杀/抢购流程出现问题时不影响主流程。
还存在一些热点, 可能是因为价格或突发事件引起的。 对于读热点, 使用多级缓存
来搞定, 而写热点我们一般通过缓存+队列模式削峰
5、 超时与重试
(1) 代理层超时与重试: nginx
(2) web 容器超时与重试
(3) 中间件和服务之间超时与重试
(4) 数据库连接超时与重试
(5) nosql 超时与重试
(6) 业务超时与重试
( 7) 前端浏览器 ajax 请求超时与重试
退款: 按钮 – 手抖, 多点击几次----------- 接口 幂等性
6、 回滚
7、 压测与预案
压测一般指性能压力测试, 用来评估系统的稳定性和性能, 通过压测数据进行系
统容量评估, 从而决定是否需要进行扩容或缩容。
压测之前要有压测方案〔 如压测接口、 并发量、 压测策略( 突发、 逐步加压、 并
发量) 、 压测指标( 机器负载、 QPS/TPS、 响应时间) 〕 , 之后要产出压测报告
〔 压测方案、 机器负载、 QPS/TPS、 响应时间( 平均、 最小、 最大) 、 成功率、
相关参数( JVM 参数、 压缩参数) 等〕 , 最后根据压测报告分析的结果进行系统
优化和容灾
四:什么是高并发
QPS: 每秒响应请求数。 在互联网领域, 这个指标和吞吐量区分的没有这么明显。
并发用户数: 同时承载正常使用系统功能的用户数量。 例如一个即时通讯系统, 同时在线量
一定程度上代表了系统的并发用户数。
重点:
1、 QPS : 每秒查询数量
2、 TPS : 每秒事务数量, 一个接口请求从发送请求到接收到响应为止, 代表一个 tps
3、 吞吐量: 每秒请求数量
QPS ,TPS , 吞吐量有何区别? ?
解释: 在大多数情况系下, qps = tps = 吞吐量
例如: 访问/index.html (css,js,index.do)
QPS = 3
TPS = 1
系统的处理速度:
程序内数据读写 > redis > mysql > 磁盘
单机网络请求 > 局域网内请求 > 跨机房请求
如何保障系统的高并发?
1、 服务尽量进行拆分部署(分布式: SOA,微服务) ; --- 业务纵向拆分, 化整为零, 资源拆
分, 横向扩展
2、 尽量将请求拦截在系统上游(越上游越好) ; --- 限流, 缓存
3、 读多写少多使用缓存(缓存抗读压力) ; --- 读缓存, 写异步
4、 浏览器和 APP: 做限速(漏桶原理) --- 限速, 限流
5、 站点层: 按照 uid 做限速, 做页面缓存
6、 服务层: 按照业务做写请求队列控制流量, 做数据缓存 – 队列缓冲
7、 数据层: 压力就小了, 无忧无虑 –-数据库优化
其他方面: 结合业务做优化
具体的解决方案:
1、 缓存(应用级别缓存、 http 缓存、 多级缓存)
2、 连接池
3、 异步
4、 扩容
5、 队列
数据库优化: --- RT --- 吞吐量
1、 集群(分表、 分库、 读写分离【解决读压力】)
2、 索引
3、 开启缓存(mysql8已经去除了)
4、 SQL 优化
5、 冗余设计(反范式设计)
6、 防止写复杂 SQL
7、 冷热数据分离
分布式文件系统:
1、 开源文件系统 FastDFS
2、 云服务
日志数据/搜索数据/简单业务数据:
elasticSearch ms
Redis 缓存
应用层优化:
1、 web 服务器优化 (线程池, 连接队列)
2、 JVM 优化
3、 代码结构优化(code review)
4、 分布式拆分(提高吞吐量, 提高集群部署网络数量)
5、 异步架构
6、 异步并发编程
7、 队列
8、 线程池
9、 nosql
前端优化工作:
1、 DNS 缓存
2、 CDN 缓存
3、 浏览器缓存
4、 nginx 缓存
多级缓存应用
http 缓存:
1、 DNS 缓存
2、 CDN 缓存
3、 浏览器缓存
4、 nginx 缓存
项目来说: 构造项目缓存 – mybatis : 一级缓存, 二级缓存
1、 堆缓存
使用 Java 堆内存缓存对象。 使用技术方案: Ehcache 实现缓存。
2、 内存缓存
内存缓存, 缓存的大小取决于内存大小。 技术方案: Ehcache 实现缓存
3、 磁盘缓存
缓存数据存储在磁盘, JVM 启动后, 还能从磁盘加载。 技术方案: Ehcache 实现缓存,
设置过期时间
4、 分布式缓存
使用第三方缓存服务器: Redis
堆缓存: 对象不需要序列化/反序列化
堆外数据: 反序列化
连接池详解
连接池目的: 通过连接池减少频繁创建连接, 释放连接, 降低消耗, 提升性能 (吞吐量)
连接池: 数据库连接, Redis 连接池, Http 连接池……..
技术方案: Apache commons pool2 , jedis, druid, dbcp…………..
各位程序员: 是否知道连接池怎么配置? 设置多少个队列, 设置多少个线程? ?
例如:
1w QPS 2W TPS 连接池应用设置多少? ? ?
回答: 尽量设置大些吧, 设置个 500 吧 ---- 此话是否正确? ?
通过 oracle 公司公布的测试数据发现:
连接池设置变小了, 执行数据反而变快了, RT 时间变短了….. , 性能更好了…… 这是什么
原因造成的? ? ?
回答: 线程池数据量太大, 就会造成创建的线程过多, CPU 使用的是时间分片切换线程的
使用权, 多个线程的频繁切换会消耗大量的时间。
线程池是否越少越好呢? ? 肯定不行, 线程池一定要设置一个合适值。
理想状态:
4 核 CPU 机器: CPU 密集型 --- 线程池数量 == CPU 核心数量
IO 密集型: 占用大量的 IO 资源, CPU 占用比较少
线程池: 2*4 = 8
六:线程池和cpu的关系
公式一:
Ncpu = CPU 核心数量
Ucpu = cpu 使用率
W/C = 线程等待时间 /(等待时间+计算时间)
线程池数量 = Ncpu * Ucpu * (1 + w/c)
经验值设置:
Cpu 密集型: threads = N + 1
Io 密集型: theads = 2*N
异步 Future
线程池配合 Future 实现, 但是阻塞主请求线程, 高并发时依然会造成线程数过多、 CPU
上下文切换。
通过 Future 可以并发发出 N 个请求, 然后等待最慢的一个返回, 总响应时间为最慢的
一个请求返回的用时
异步 Callback
通过回调机制实现, 即首先发出网络请求, 当网络返回时回调相关方法, 如
HttpAsyncClient 使用基于 NIO 的异步 I/O 模型实现, 它实现了 Reactor 模式, 摒弃阻塞 I/O
模型 one thread per connection, 采用线程池分发事件通知, 从而有效支撑大量并发连接。
这种机制并不能提升性能, 而是为了支撑大量并发连接或者提升吞吐量
实现高并发需要考虑:
(1) 系统的架构设计, 如何在架构层面减少不必要的处理(网络请求, 数据库操作等)
例如: 使用 Cache 来减少 IO 次数, 使用异步来增加单服务吞吐量, 使用无锁数据结构来减
少响应时间;
(2) 网络拓扑优化减少网络请求时间、 如何设计拓扑结构, 分布式如何实现?
分布式, 微服务
(3) 系统代码级别的代码优化, 使用什么设计模式来进行工作? 哪些类需要使用单例,
哪些需要尽量减少 new 操作?
Gc – stw(整个程序停止, 进行 gc)
(4) 提高代码层面的运行效率、 如何选取合适的数据结构进行数据存取? 如何设计合适
的算法?
(5) 任务执行方式级别的同异步操作, 在哪里使用同步, 哪里使用异步?
读缓存, 写异步
( 6) JVM 调优, 如何设置 Heap、 Stack、 Eden 的大小, 如何选择 GC 策略,控制 Full GC
的频率?
响应时间优先, 并发优先
( 7) 服务端调优( 线程池, 等待队列)
( 8) 数据库优化减少查询修改时间。 数据库的选取? 数据库引擎的选取? 数据库表结构
的设计? 数据库索引、 触发器等设计? 是否使用读写分离? 还是需要考虑使用数据仓库?
连接池优化, MySQL 查询语句优化, 表结构设计优化; 架构优化( 分表分库)
( 9) 缓存数据库的使用, 如何选择缓存数据库? 是 Redis 还是 Memcache? 如何设计缓
存机制?
( 10) 数据通信问题, 如何选择通信方式? 是使用 TCP 还是 UDP, 是使用长连接还是短
连接? NIO 还是 BIO? netty、 mina 还是原生 socket?
内网: tcp
连接: 长连接, 保证连接的复用性, 提高性能