CoreJava 底层架构 matlab typeScript powershell uitableview primefaces null webkit vue引入组件 在线考试系统代码 python查看数据类型 excel加减混合求和 mysql 导入数据 mysql临时表 python输出 pythonfor循环 python手册 python建站 java运算符 java开发教程 java删除文件 js四舍五入 corelpainter 思源黑体cn 流程图工具 古风头像女动漫 comsol下载 视频编辑专家下载 文明6万神殿 eagle软件 小米9截屏 mp4剪切合并大师 renderto 视频字幕制作软件 模拟邻居 战法装备 ppt背景音乐怎么关 mysql退出命令 shell数组遍历
当前位置: 首页 > 学习教程  > 编程语言

【电商架构设计】- 中台及问题剖析

2020/11/24 11:18:47 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

一、整体架构 1、概述 中台就是对”共享“ 理念系统化的归纳和总结;是一种企业架构而不是单纯的技术层面。重复功能建设和维护带来的重复投资 烟囱式建设造成系统壁垒,数据孤岛 业务沉淀促进可持续发展 大中台小前台快速响应市场的需要2、上层业务 即大…

 

一、整体架构

1、概述

中台就是对 共享 “ 理念系统化的归纳和总结; 是一种企业 架构而不是单纯的技术层面。
  • 重复功能建设和维护带来的重复投资
  • 烟囱式建设造成系统壁垒,数据孤岛
  • 业务沉淀促进可持续发展
  • 大中台小前台快速响应市场的需要

                

 

2、上层业务

即大中台,小前台的前台,电商中直面用户的B2B,B2C等各个业务线

3、业务中台

业务中台基于公共服务的沉淀,需要收敛一些基础的业务服务,如商品、订单、会员、库存、财务、结算等等。

4、数据中台

数据中台不是一个平台,也不是一个系统。数据仓库、数据平台和数据中台是有区别的。
简单的举例: 数据平台可以理解为数据库,数据仓库类比为报表,而数据中台更贴近上层业务,带着业务属性。

5、技术中台

业务无关的基础沉淀,中间件,系统框架,监控,日志,集成部署等等

6、运维中台

不一定存在,系统运维相关的内容,硬件,机房,包括企业云平台的建设等可以划分为单独的运维中台

二、架构挑战

1、考量维度

(视情况而定,如分布式与一致性是一对矛盾)

  • 高性能:提供快速的访问体验。
  • 高可用:网站服务7*24正常访问。
  • 可伸缩:硬件弹性增加/减少能力(快速扩容与释放)。
  • 扩展性:方便地增加/减少新的功能/模块(迭代与服务降级)。
  • 安全性:安全访问和数据加密、安全存储等策略。
  • 敏捷性:快速应对突发情况的能力(灾备等)。

2、内部瓶颈

  • 木桶效应:水管最细的地方决定流量,水桶最低的地方决定容量(QPS压测调优为例
  • CPU:序列化和反序列化、高频日志输出、大量反射、大量线程的应用
  • 内存:使用内存的中间件或服务,如redismemcachejvm大量对象堆积内存的应用等
  • 网络带宽:大流量高并发环境下,双11用户访问量激增,造成网络拥堵
  • 磁盘IO:文件上传下载,数据库频繁读写,不合理或大批量的日志输出
  • 数据库连接数:应对双11,应用服务器连接池大批扩容,警惕底层数据库、Redis等连接数瓶颈

3、外部服务

  • 短信:外部短信延迟与送达率问题,可以搭建短信平台,多家渠道做路由和切换分流(短信平台架
  • 支付:银行支付与回调延迟,搭建支付中心,对接多支付渠道
  • 快递对接:快递服务对接(快递100
  • 外部云存储:云存储文件访问,流量扩容(大家所使用的存储  ---nfs的架构与事故
  • CDN:外部静态文件访问提速服务(使用过的项目?

三、业务中台

1.1 订单中心

  • 异步化

场景: 大促期间新增许多需要获取订单状态的服务,比如应对双11而临时增加的数据中台订单大屏展示等(数据统计,下单状态多少,付款成功状态多少...)
 

解决方案:因为订单状态需同步到其他服务去,同步进行需增加订单处理的速度,此时同步动作需为异步进行

潜在问题注意异步化引发的乱序问题,一是传输阶段,二是消费阶段  

                 传输阶段:因为异步传输了,所以有可能先创建的订单不能先传,后创建的订单可能先被传输。(传输路由、代码处理解决,问题也在这个身上)
                 消费阶段:因为异步传输了,有可能出现订单付款状态先被消费,订单创建后被消费。(单消费者消费一个队列,因为队列先进先出)

 

图例方案:(此处相对有序,因为订单与订单之间顺序没影响,且绝对有序会造成串行)

rabbitmq传输 :队列级别顺序保障,单消费者消费一个队列可以严格保障顺序性,需要扩充队列数提升性能
 
 

kafka传输分区级别顺序保障,只能保障投放和传输阶段的顺序性

consumer11消费存在性能问题,接收消息后key做二次分发,放入多个内存队列,开启多线程消费

 
  • 过期订单

场景:双11抢单是最常见的场景,抢单不支付会占据大批量资源,如商品库存。如何取消过期订单是架构师必须面对的问题。(消单解决库存)

①扫表实现

原理:通过定时任务轮询扫描订单表,超时的批量修改状态

优点:实现简单

缺点:

  • 大量数据集,对服务器内存消耗大
  • 数据库频繁查询,订单量大的情况下,IO是瓶颈
  • 存在延迟,间隔短则耗资源,间隔长则时效性差,两者是一对矛盾。
  • 不易控制,随着定时业务的增多和细化,每个业务都要对订单重复扫描,引发查询浪费

②被动取消

原理: 在每次用户查询订单的时候,判断订单时间,超时则同时完成订单取消业务。
 
优点:
  • 实现极其简单 不会有额外的性能付出
  • 不依赖任何外部中间件,只是应用逻辑的处理
缺点:
  • 延迟度不可控,如果用户一直没触发查询,则订单一直挂着,既不支付也未取消,库存也就被占

③java延迟队列实现

原理
 

通过DelayQueue,每下一单,放入一个订单元素并实现getDelay()方法,方法返回该元素距离失效还剩余的时间,

<=0时元素就失效,就可以从队列中获取到启用线程池对数据监听,一旦捕获失效订单,取出之后,调用取消逻辑进行处理。

优点 :   基于jvm 内存,效率高,任务触发时间延迟低。
 
缺点 :
  • 存在jvm内存中,服务器重启后,数据全部丢失
  • 依赖代码硬编码,集群扩展麻烦
  • 依赖jvm内存,如果订单量过大,无界队列内容扩充,容易出现OOM
  • 需要代码实现,多线程处理业务,复杂度较高
  • 多线程处理时,数据频繁触发等待和唤醒,多了无谓的竞争

④消息队列实现

原理: 设置两个队列,每下一单放一条进延迟队列,设定过期时间。消息一旦过期,获取并放入工作队列,由consumer获取,唤起超时处理逻辑。
 
 
如果采用的是 RabbitMQ ,其本身没有直接支持延迟队列功能。
 
可以针对 Queue Message 设置 x-message-ttl,用消息的生存时间,和死信队列来实现。
 
具体有两种手段;
 
A: 通过队列属性设置,队列中所有消息都有相同的过期时间,粗粒度,编码简单
 
B: 对消息进行单独设置,每条消息 TTL 可以不同, 细粒度,但编码稍微复杂。
 
优点:
  • 可以随时在队列移除,实现实时取消订单,及时恢复订单占用的资源(如商品)
  • 消息存储在mq中,不占用应用服务器资源
  • 异步化处理,一旦处理能力不足,consumer集群可以很方便的扩容
缺点:
  • 可能会导致消息大量堆积
  • mq服务器一旦故障重启后,持久化的队列过期时间会被重新计算,造成精度不足
  • 死信消息可能会导致监控系统频繁预警

⑤redis实现

原理: 利用redis notify-keyspace-events ,该选项默认为空,改为 Ex 开启过期事件,配置消息监听
            每下一单在redis 中放置一个 key (如订单 id ),并设置过期时间。
优点 :
  • 消息都存储在Redis中,不占用应用内存。
  • 外部redis存储,应用down机不会丢失数据。
  • 做集群扩展相当方便
  • 依赖redis超时,时间准确度高
缺点 :
  • 订单量大时,每一单都要存储redis内存,需要大量redis服务器资源
 

1.2 支付中心


   1)重复支付

原因: 在第一步发起的时候,用户进入支付方式选择页。选第一个支付方式并支付完后因为通知延迟,以为支
            付失败。在支付又选了第二种,再次支付。
 
应对方案
1)程序屏蔽,前端js 触发按钮置灰或者遮罩提示(支付成功?遇到问题?),或者在支付方式选择页直接跳转。
 
2)后端处理,发现不同通道下的支付成功回调,抛消息队列或记录日志
 
数据修复
 
首先查支付日志,确认针对同一笔订单收到了不同支付渠道的回调。
其次,在支付平台管理后端可以查到入账记录,人工介入。
最后对账阶段会发现对方多帐,我方补单时出现重复订单。
 
问题处理
调取退款接口或者在支付渠道的管理后台操作退款(一定要多次确认无误)。
 

 

  2)异常订单 

①支付但未开单
 
场景: 用户明明支付成功,但未开通订单
 
问题分析:
  • 一般支付渠道会间隔性多次回调开单链接,如果支付未开单,银行未回调的可能性比较小,着重排查开单接口是否可用。如果可用追查日志是否出现异常记录。
 
应对措施:
 
  • 对账阶段可以查漏,程序自动完成补单,但是处理相对延迟,取决于支付渠道的对账文件下发周期
2011-2013 年,支付测试数据与财务人工对账的历程
人工补单,人工查询支付渠道后台数据,确认已支付的情况下,介入补单流程人工处理
 
 
②未支付但已开单
 
场景: 用户未支付,或者财务中心未收到这笔款项,订单状态已开通。这种就问题比较严重了
 
应对措施: 首先排除人为操作因素。其次排查系统是否存在漏洞或者级联开单的情况

   3)回调延迟

场景: 用户是期望支付完成的同时立马看到结果。但是中间多层远程的调用,可能发生订单状态更新延迟问 题。
 
解决 主动查询 。在用户查看订单的时候,如果是类似“ 支付中 的中间态时,触发远程订单状态查询接口。
大家看到的点击 支付完成 跳转的过程,触发远程支付结果查询
 
 

   4)支付路由

 
背景: 保障支付可用性及支付分流,支付中心对接多家渠道
方案
  • 支付中心对接多个支付渠道,支付宝,微信,各银行或第三方支付供应商。
  • 对不同用户,进入支付方式选择页时,做支付分流。
  • 做好监控统计,一旦某个支付渠道不可用或者延迟较大,切掉,下线,或者降权。
 
 

五、技术中台

2.1  数据库优化

数据库层的调优,一般发生在大促前的预备阶段,一旦大促开始,对数据库的优化已经来不及了。
  • 在大促开始前梳理耗时查询业务,对关键业务压测。
  • 开启mysql的慢查询日志(两种方式)
# 配置文件方式,需要重启 mysql
# 日志文件位置
log-slow-queries = /opt/data/slowquery.log
 
# 超时时间,默认 10s
long_query_time = 2
 
# 临时开启,不需要重启
set global slow_query_log = on;
set global long_query_time = 10;
set global slow_query_log_file = ‘/opt/data/slow_query.log’
  • 使用mysqldumpslow命令解析mysql慢查询日志
-- 慢查询日志以文本打开,可读性很高
-- 查询次数,耗时,锁时间,返回结果集条数(扫描行数),执行者
 
Count : 1 Time = 10.91 s ( 10 s) Lock= 0.00 s ( 0 s) Rows= 1000.0 ( 1000 ),
mysql[mysql]@[ 10.1 . 1.1 ]
 
SELECT * FROM order_history
  • 借助explain查看sql执行计划,对sql调优,或其他优化工具。

 

2.2  缓存优化

1) 策略

 
热点数据预热
 
常规缓存设计趋向于懒加载,大促期间的热点数据尽量做到预热加载。
比如某个促销专题,不要等待活动开始的一瞬间再读库加缓存,搞不好引发击穿。
 
细粒度设计
 
集合与单体分开存储,缓存结构细粒度化。
 
如某个橱窗的推荐商品列表,常规存储一个 key value 为整个商品集合。
优化为列表与每个商品详细信息设置两个独立缓存值,在查询环节组装,可以降低发生修改时对缓存的冲击。
新增一个推荐则失效列表,修改商品则仅仅失效当前商品缓存。
 
可用性
 
雪崩:只要缓存失效时间设置分散,雪崩的可能性不大
穿透:防范恶意攻击引发穿透,前端做到防刷,业务层面要注意合法性校验,非法 key 的失效时间需要评估。
击穿: 大促高并发下,修改时,如果采用 key 删除策略很可能触发击穿,修改少可以优 化为双写。
 
 

2)多级缓存

 
优化缓存体系,对关键业务请求,如商品详情页,采用多级缓存处理
 
 
浏览器缓存 :    可分为两种手段,分别交给浏览器和服务端执行客户端判决
 
 
  • 客户端判决:为请求Header设置Expireshttp1.0) 和 Cache-Controlhttp1.1),客户端本地比较决定是否使用缓存
  • 服务端判决:借助Last-Modifified/If-Modifified-Sincehttp1.0)或ETag/If-None-Match,服务器端比较决定返回200body还是304仅有head 
ps:   Last-Modifified < ETag < Expires < Cache-Control
 
 
CDN :借助 CDN dns解析,对用户做ip 分流 CDN 作为应用服务器的代理,抵挡前端的流量洪峰。
               同样,前面提到的http 缓存策略对 CDN 依然有效。
 
nginx 缓存 nginx 除了作为负载均衡,也可以作为请求级别的缓存,一段典型配置如下:
 
# 定义缓存路径、过期时间、空间大小等
proxy_cache_path /tmp/nginx/ cache levels =2:2: 2 use_temp_path = off
keys_zone =my_cache: 10m inactive = 1h max_size =1g;
server {
listen 80;
server_name xxx.xxx.com;
# 添加 header 头,缓存状态信息
add_header X-Cache-Status $upstream_cache_status;
location / {
# 定义缓存名
proxy_cache my_cache;
# 定义缓存 key
proxy_cache_key $host$uri$is_args$args;
分布式缓存 redis做应用层缓存,不多解释,但是要注意做好扩容预案和业务层优化
  • 依据预估量做相应的扩容或资源申请,纯做缓存时可以关闭持久化,内存超出60%将变得不稳定。
  • 频繁交互业务从java端下移到lua脚本实现,一方面可以实现原子性,另一方面有效减少网络延时
  • 和数据的冗余传输。以平台优惠券领取为例:(画图对照redis指令

2.3 分流与限流

2.4 服务降级

2.5 安全性

 

 

 

 

 

 

 

 

 

 

 

 

 


本文链接: http://www.dtmao.cc/news_show_400446.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?