微服务架构实战笔记

为什么MQ 比写DB快,因为MQ99% 都是顺序写,DB 99% 都是随机写。

异步架构中,网关层不用接入MQ是因为网关层是用来过滤掉大量的请求,如果写入mq 则会有大量的脏数据

nginx 不要做web 容器,运维负责 主要做反向代理 和 简单的限流 根据ip限流

微服务使用场景

需求层面

微服务是需求比较频繁,像ERP、OA系统需求就不是很频繁,更新频率低

性能层面

吞吐量会变高,每一层都可以横向扩展,

数据一致性层面

一致性 1、强一致性 如果你要保证强一致性,基本上你的吞吐量就没有了。 2、最终一致性,用分布式事务解决的是最终一致性的问题。
最终一致性有两种解决方案,一种是异步的最终一致性,一种是同步的最终一致性

微服务架构的目的

1、快速迭代
微服务架构就是为了快速迭代,提高开发效率,并行开发,以前上线需要很多人支持,现在上线是谁相关谁上线

2、项目持续交付

拆分业务层 和数据层的意义?
比如商品业务层需要用户信息,那么就需要用商品业务层直接掉用户数据层,而不是商品业务层调用用户数据层。这样就可以避免循环调用,比如用户又要调用商品信息。

再比如:商品业务层、交易业务层,它们都是业务层,商品层需要调用交易数据层,交易业务层又需要调用商品数据层,都是从上往下调用,而不是左右调用。

image.png

公共逻辑层一定不能反向调用。

Service Mesh 多了两次protobuf 序列化/反序列化,每个消息也发了两次。

互联网高可用设计

为什么需要高可用
硬件
生命周期:x86 3年
硬件故障
网络划分

软件
Bugs 软件总是有bug的
性能极限
软件之间相互影响

传统高可用评估方式
一段时间(比如一年)的停机时间占比
停机时间/总时间
2个9:一年停机时间不能超过88小时 365天24小时1%=88;
3个9:一年停机的时间不能超过9个小时
4个9 :一年停机的时间不能超高跟53分钟
5个9:一年停机的时间不能超过6分钟
1个9,90%

微服务高可用手段
1、服务冗余 无状态化
服务冗余:服务部署在不同的机柜或者机架上,用来防止单个机柜停电宕机而造成的不可用。
无状态化:不同的服务,关系是对等的,用户请求到任何服务都是可以的,这就是无状态化,无状态也不是这么简单,比如用户的session,如果存在网关层,这样就不是幂等的了,这样就会出现一会登陆,一会没登陆。如果每台网关服务器都缓存全量的Session,就不能说网关是无状态的。因为当有两台网关服务器,其中一台网关服务器挂了,这时候重启一个备份网关服务器,此时备份网关服务器就没有全量的Session,此时备份服务器跟另外一台服务器就是不对等的,这种情况它就不是无状态的。当然我们做无状态的目的:1、快速扩容;2、快速的缩容;

2、幂等设计 负载均衡
负载均衡:比如网关对应两台业务逻辑服务器,如果有一台服务器挂了,网关会剔除故障的服务器,将流量切换到正常的服务器。

3、异步化设计 超时机制
异步化的目的就是为了提升吞吐量,提高并发。什么样的场景适合异步化呢?对实时性要求不高,不是核心链路,不太关注结果,减少主流程

4、服务限流降级熔断 数据复制/缓存/Sharding
数据复制是数据层的高可用,缓存减少数据库压力, sharding :
5、架构拆分、服务治理

服务实时监控
请求平均耗时,黄线是昨天耗时,红线是今天耗时
请求异常数:黄线是昨天异常数,红线是今天的异常数
5秒打一个点,请求耗时都是打在日志里,通过flume 采集到kafka里面去,通过大数据spark 实时计算频率耗时
请求异常会报警

服务分级

如何降低或者避免服务出现故障

服务级别定义标准
一级服务1、服务每天PV达到5000w以上
2、收入达到公司在线收入1/10
3、核心系统
4、后端基础服务至少为1个一级服务提供主服务
二级服务1、服务每天PV达到1000w以上
2、收入达到公司在线收入1/20
3、重要商务系统
4、后端基础服务至少为1个二级服务提供主服务
5、公司内部核心信息系统
三级服务其他
服务级别服务名称
一级服务列表系统,详情页系统,发布系统
招聘业务服务,计费系统,支付系统,订单系统
IDC网络,DNS
二级服务消息系统,个人中心,呼转服务,
交友系统,CRM,OA,权限系统,BI系统
办公网络,VPN
三级服务其他
事故定级影响程度低影响程度中影响程度高
一级服务严重重大特大
二级服务一般严重重大
三级服务N/A一般严重
影响程度定级影响程度低影响程度中影响程度高
对外完全停止服务时间2-7分钟7-30分钟30分钟以上
系统对用户产生拒绝,占当日预期流量的比例0.1%-1%1%-6%6%以上
系统返回结果不符合预期占当日总流量的比例0.5%-2%3%-15%15%以上
受影响的用户占系统用户比例3%-20%20%-40%40%以上
影响数据程度部分数据丢失但能恢复部分数据丢失不能恢复所有数据丢失但不能恢复
收入损失,占日平均营收(线上加线下)比例2%-5%5%-30%>30%
网络丢包率5%-10%10%-30%>30%

高可用案例--如何无缝停止线上服务
网关层已具备热切换能力
热开关切换

假设 APP->网关->业务逻辑层->数据访问层->DB
假设网关已经具备热切换功能,假设20:00以后开始切,此时将开关打开,此时拒绝20:00以后的请求,已经请求的要等请求完成之后再关机。
什么时候20:00左右的请求处理完成?有两种方案:
1、查看各个层有无访问日志,如果没有请求日志了,然后重启
2、根据前端超时时间来设置,比如APP超时时间是5秒,20:00访问 20:00:05秒开始重启。其实就算你不返回给前端用户,前端用户也已经超时了,所以再等服务器处理完毕已经没有意义了。

关机顺序:先关网关 再关业务逻辑层 再关数据访问层。

长连接也是这么关闭的。

假设网关层不具备热切换能力
可以通过防火墙来实现,防火墙限制只出不进
IPTABLES

互联网高并发设计手段

吞吐量(Throughput)

响应延迟(Response Delay)

性能优化目标
缩短响应时间
提高并发数(增加吞吐量)
让系统处于合理状态

优化手段

1、空间换时间
系统时间是瓶颈
例如:缓存复用计算结果,降低时间开销,因为CPU时间较内存容量更加昂贵

2、时间换空间
数据大小是瓶颈

例如一:网络传输是瓶颈,使用系统时间换取传输的空间,使用HTTP的gzip压缩算法

例如二:App的请求分类接口,使用版本号判断哪些数据更新,只下载更新的数据。比如IM 即时通讯的用户列表,如果每次登陆就去拉一次用户列表,这样就会耗费大量的流量,用户列表其实更新没有那么频繁,可以在App端缓存一个版本号,与服务器版本号对比,如果版本号一样,就代表没有更新,就无需去拉取用户列表,当版本号发生改变,则拉取用户列表。

3、找到系统瓶颈
分析系统业务流程,找到关键路径并分解优化;
一个服务集群4W的QPS,调用量前5的接口贡献了3.5万的QPS

对关键路径的代码优化收益最大,当然系统剩下的部分也不能忽视,比如剩下5K QPS接口若性能也有问题,也可能把整个服务性能拖垮。比如这5千都是慢查询。

整个解决思路:调用了多少RPC接口;载入多少数据;使用什么算法;非核心流程能否异步化,没有数据依赖的逻辑能否并行执行

优化层次

优化层次:整体到细节,从全局角度到局部视角

架构设计层次

关注系统控制、数据流程

如何拆分系统,如何使各部分系统整体负载更加均衡,充分发挥硬件设施性能优势,减少系统内部开销等。

算法逻辑层次

关注算法选择是否高效,算法逻辑优化,空间时间优化任务并行处理,使用无锁数据结构

空间换时间
ThreadLocal 线程共享的遍历,频繁的生成对象还是挺慢的,将一些要共享的东西放到ThreadLocal里面去做。

时间换空间
采用压缩算法压缩数据,更复杂的逻辑减少数据传输

代码优化层次

关注代码细节优化,代码实现是否合理,是否创建了过多的对象,循环遍历是否高效,cache使用的是否合理,是否重用计算结果等。

代码优化层次

1、循环遍历是否合理高效,不要在循环里调用RPC接口、查询分布式缓存、执行SQL等
比如一个列表100条记录需要用户信息,就调用100次RPC来获取用户
解决方案:先调用批量接口组装好数据,再循环处理。

2、代码逻辑避免生成过多对象或无效对象
解决方案:输出Log时候log级别判断,避免new 无效对象

if(LOG.isDebugEnabled()){
LOG.debug("debug log");
}
LOG.isDebugEnabled()会生成一个对象。
正确写法应该是:
LOG.debug("debug log");

3、ArrayList 、HashMap 初始容量设置是否合理
扩容的代价
如果知道数据的大小,初始化的时候最好赋值一下,免得触发扩容问题,这样就会有性能影响

4、对数据对象是否合理重用,比如通过RPC查到的数据能复用则必须复用

通过RPC调用查询到的对象,能不能缓存到本地缓存中。

5、根据数据访问特性选择合适数据结构,比如读多些少,考虑CopyOnWriteArrayList(写时Copy副本)

6、拼接字符串的时候是使用String相加还是使用StringBuilder进行append(在StringBuilder的容量预分配的情况下,StringBuilder的性能比String 相加性能高15倍左右)

7、是否正确初始化数据。有些全局共享的数据,饿汉式模式,在用户访问之前先初始化好。

比如京东 淘宝上 有很多 商品类目 包括一级类目、二级类目等。

数据库代码优化层次

1、数据库减表语句尽量小的数据结构
表示状态的字段,如果状态值在255以内使用unsigned tinyint,IP 使用int 而非varchar

2、使用enum的场景使用tinyint替代,enum扩展需要改表

3、避免使用select * 查询数据,只查询需要的字段,避免浪费数据IO、内存、CPU、网络传输

4、分析查询场景建立合适的索引,分析字段的可选择性,索引长度,对长的varchar使用前缀索引。

5、字段尽量为Not NULLL类型,MySQL手册说明允许NULL的字段需要额外的存储空间去处理NULL(见注解),并且很难查询优化

6、目的为了降低服务器CPU使用率、IO流量、内存占用、网络消耗,降低响应时间

局部性原理
哪个执行速度快?

long[][] a=new long[10000][10000];

第一段代码 按行赋值

for(int i=0;i<a.length;i++){
   for(int j=0;j<a[i].length;j++){
       a[i][j]=j;
   }
}

第二段代码 按列赋值

for(int i=0;i<a.length;i++){
   for(int j=0;j<a[i].length;j++){
     a[j][i]=j;
   }
}

第一段代码耗时140ms ,第二段代码耗时2700ms

CPU Cache结构
速度越来越高:内存->L3->L2->L1多级缓存
本质上内存是一个大的一维数组,二维数组在内存中按行排列,先存放a[0]行,再存放a[1]行。
第一种遍历方式,是行遍历,先遍历完一行再遍历第二行,符合局部性原理,Cache Hit(缓存命中率高)

第二种遍历方式,是列遍历,遍历完第一列遍历第二列,由于下一列和上一列的数组元素在内存中并不是连续的,很可能导致Cache Miss(缓存未命中)

第二种遍历方式,是列遍历,遍历完第一列遍历第二列,由于下一列和上一列的数组元素在内存中并不是连续的,很可能导致Cache Miss(缓存未命中),cPU 需要去内存载入数据,速度较CPU L1 Cache 的速度低很多(主存100ns,L1 cache 0.5ns)

image.png

其中 i-cache(instruction cache)是指令高速缓冲存储器。 Cache存储体:存放由主存调入的指令与数据块.
dcache(data cache):数据高速缓冲存储器

代码优化层次
扩大到一般场景,业务系统使用缓存降低响应时间提高性能,必须提高缓存命中率

很聚焦的高频访问,时效性要求不高很适合缓存提升性能,很聚焦的高频访问业务比如banner,广告位,时效性要求不是特别高,比如更新了可以不用实时体现,很适合使用缓存提升性能

如果对数据实时性要求很高,比如严格的时效性,需要慎重考虑更新缓存带来的一致性问题

时效性和缓存的冲突,比如商品服务队商品进行了缓存,由于更新缓存和更新商品不是同一个事物,则对数据时效性要求高的如交易,就只能直接从数据库查询商品信息。

算法逻辑优化层次

1、用更高效的算法替换现有算法,而不是改变其接口
2、增量式算法,复用之前的计算结果,比如一个报表服务,要从全量数据中生成报表数据量很大,但是每次增量的数据较少,则可以考虑只计算增量数据和之前计算结果合并,这样处理的数据量就小很多。
3、并发和锁的优化,读多写少的业务场景下,基于CAS的LockFree比mutex性能更好
4、当系统时间是瓶颈,采取空间换时间逻辑算法,分配更多空间节省系统时间,缓存复用计算结果,降低时间开销,CPU时间比较内存容量更加昂贵
5、当系统空间容量是瓶颈,采用时间换空间算法策略
网络传输是瓶颈,使用系统时间换取空间的压缩,HTTP的gzip压缩算法
APP的请求分类接口,使用版本号判断哪些数据更新,只下载更新的数据,使用更多的代码逻辑处理更细粒度的数据

6、并行执行,比如一段逻辑调用了多个RPC接口,而这些接口之间并没有数据依赖,则可以考虑并行调用,降低响应时间

7、异步执行,分析业务流程中的主次流程,把次要流程拆分出来异步执行,更进一步拆分到单独的模块去执行,比如使用消息队列,彻底和核心流程解耦,提高核心流程的稳定性以及降低响应时间。

架构设计优化层次

分布式系统微服务化
分库分表、读写分离、数据分片
无状态设计,动态水平弹性扩展
调用链路梳理,热点数据尽量靠近用户
分布式Cache、多级多类型缓存
容量规划
提前拒绝,保证柔性可用

电商秒杀系统

大量并发,在某一时刻99%的用户涌入;
有效请求数很低,可以认为有效请求和数据库库存数一致,可能99%以上的流量都是无效的。
库存数据一致性要求严格,不能超卖。

秒杀系统架构思路

数据分层次校验,上层尽量把无效请求过滤掉
上层可以是不精确的过滤
层层限流,最后一层做数据一致性校验,扣减库存。

秒杀系统架构设计

1、HTML 、JS、CSS等静态文件存放CDN,缓存到用户端(APP/浏览器)
2、非实时动态数据(秒杀期间如商品标题、商品描述、图片URL列表、店铺信息、秒杀活动信息等),这些数据缓存在用户访问链路中靠近用户的位置,粗过滤一部分流量,比如用户是否有秒杀资格、秒杀是否已经结束等,这些数据实时性要求不高
3、实时数据如用户营销数据(如红包、折扣)、商品库存等再过滤一批用户
4、经过多层过滤最终落到数据库的流量已经很小,最终在数据库层面使用事务保证扣减库存准确性。

Feed系统分级缓存

1、读多写少、冷热数据明显,热点数据缓存到调用链路更靠近用户的地方。
2、L1缓存容量小负责抗最热点的数据,L2 缓存考虑目标是容量,缓存更大范围的数据,比如一般用户的timeline,高热点数据单独缓存,比如设置白名单,大V的用户数据单独缓存。
3、feed(关注的feed、topic的feed,一些运营的feed)前几页的访问比例,像前三页占了97%,针对这种业务特性,把前面几页数据作为热点数据提到L1 cache

Feed 系统消息发布

1、基于写扩散消息统一推送通道
2、推送策略:拆分数据并行推,活跃用户先推,非活跃用户慢慢推
有1w个用户关注,发了一个feed,拆分成100分,每份100个并行推
1万个用户里活跃的可能有2000个,活跃用户先推,非活跃用户慢慢推,保证活跃用户体验,非活跃用户推了很大概率也不看

3、消息标准格式
4、统一数据数据流,职责明确。

微博都是pull 拉的方式,假如有1亿粉丝,活跃用户只有10%,微信朋友圈可以用推push的方式,因为微信的好友有限制最多5000;

数据类型特点存储解决方案存储产品
微博内容类型简单、海量访问关系型数据库、Key-Value存储 id-contentMySQL、TiDB、Pika
微博列表结构化列表数据、多维度查询关系型数据库MySQL、TiDB、Pika
关系类型简单、高速访问持久化Key-Value存储Redis、Pika
长微博(图片/短视频)对象数据(小文件等)对象存储Ceph图片服务器(小公司fstdfs就行)
计数(关注数、粉丝数)结构简单、数据及访问量大内存Key-Value 存储Redis
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值