电商系统-技术中台

技术中台

数据库优化

数据库层的调优,一般发生在大促前的预备阶段,一旦大促开始,对数据库的优化已经来不及了。

  • 在大促开始前梳理耗时查询业务,对关键业务压测。

  • 开启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.91s (10s) Lock=0.00s (0s) Rows=1000.0 (1000),
    mysql[mysql]@[10.1.1.1]
    SELECT * FROM order_history
    
  • 借助explain查看sql执行计划,对sql调优,或其他优化工具

缓存优化

1) 策略

热点数据预热:常规缓存设计趋向于懒加载,大促期间的热点数据尽量做到预热加载。比如某个促销专题,不要等待活动开始的一瞬间再读库加缓存,搞不好引发击穿。

细粒度设计:集合与单体分开存储,缓存结构细粒度化。如某个橱窗的推荐商品列表,常规存储一个key,value为整个商品集合。优化为列表与每个商品详细信息设置两个独立缓存值,在查询环节组装,可以降低发生修改时对缓存的冲击。新增一个推荐则失效列表,修改商品则仅仅失效当前商品缓存。

可用性:

  • 只要缓存失效时间设置分散,雪崩的可能性不大
  • 防范恶意攻击引发穿透,前端做到防刷,业务层面要注意合法性校验,非法key的失效时间需要评
  • 击穿可能性升高,大促高并发下,修改时,如果采用key删除策略很可能触发击穿,修改少可以优
    化为双写

2)多级缓存

优化缓存体系,对关键业务请求,如商品详情页,采用多级缓存处理

浏览器缓存,一般浏览器缓存可分为两种手段,分别交给浏览器和服务端执行

  • 客户端判决:为请求Header设置Expires(http1.0) 和 Cache-Control(http1.1),客户端本地
    比较决定是否使用缓存
  • 服务端判决:借助Last-Modified/If-Modified-Since(http1.0)或ETag/If-None-Match,服务器
    端比较决定返回200带body还是304仅有head头
  • 优先级:Last-Modified < 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;
        # 针对返回状态码单独定义缓存时间
        proxy_cache_valid 200 304 10m;
        # url 上设置请求 nocache=true 时不走缓存。
        proxy_cache_bypass $arg_nocache $http_nocahe;
        proxy_pass http://localhost:8080;
   }
 }

分布式缓存:redis做应用层缓存,不多解释。但是要注意做好扩容预案和业务层优化

  • 依据预估量做相应的扩容或资源申请,纯做缓存时可以关闭持久化,内存超出60%将变得不稳定。

  • 频繁交互业务从java端下移到lua脚本实现,一方面可以实现原子性,另一方面有效减少网络延时
    和数据的冗余传输。以平台优惠券领取为例:

分流与限流

CDN的引入本身起到了按ip分流的作用,但是我们可以在下层做到更细粒度化的控制。根据业务情况将不同的请求分流到各自的服务器。

限流不同与分流,是对下层的保护,当系统超过一定流量后,超过的流量做直接拒绝处理,以便保护后端的服务,原则就是要么不进来,进来的都正常服务。常见的限流算法有三种:计数器、漏桶、令牌桶。

漏桶:

令牌桶:

1) 业务分流

根据不同的业务线分发请求,配备二级域名如b2b.xxx.com,b2c.xxx.com,或者在nginx软负载层针对不同虚拟主机名做upstream分发。

新上的双11活动页,或者促销专题页面,采用新访问入口和机器部署,与主站分离。活动结束后也利于机器资源的快速释放。

2) 终端分流

按不同的请求终端分流,在header头的user-agent中可以捕获用户的访问终端。android,ios,pc
根据不同终端设备,做流量分发,到不同的应用机器。同时方便对用户终端流量的监控和统计。

3)nginx限流

评估双11可能的流量,结合具体业务模块,配备对应限流措施。主要有流量限制和连接数限制两个维
度。

流量限制:限制访问频率,其目的是基于漏桶算法实现ip级别的防刷。Nginx中使用ngx_http_limit_req_module 模块来限制请求的访问频率,基于漏桶算法原理实现。

#$binary_remote_addr 表示通过remote_addr这个标识来做限制
#binary_的目的是缩写内存占用量,是限制同一客户端ip地址
#zone=one:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息
#rate=1r/s表示允许相同标识的客户端的访问频次
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

server {
  location /b2b/ {
  #zone=one 设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应
  #burst=5,设置一个大小为5的缓冲区,当有大量请求时,超过了访问频次限制的请求可以先放到这个缓
冲区内
  #nodelay,如果设置,超过访问频次而且缓冲区也满了的时候就会直接返回503,如果没有设置,则所
有请求会等待排队
  limit_req zone=one burst=5 nodelay;
 }
}

连接数限制:Nginx 的 ngx_http_limit_conn_module模块提供了对资源连接数进行限制的功能。

#$binary_remote_addr同上
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
  location /b2b/ {
    # 限制每个ip下最大只能有一个连接
    limit_conn addr 1;
 }
}

4)网关限流

从代理服务器放进来的流量,会进入应用服务器,第一道关卡是微服务的网关。应对大促,针对各个微服务具体业务具体分析,配备对应限流措施。zuul和gateway是团队中最常遇到的网关组件。

zuul.routes.userinfo.path=/user/**
zuul.routes.userinfo.serviceId=user-service
zuul.ratelimit.enabled=true
zuul.ratelimit.policies.userinfo.limit=3
zuul.ratelimit.policies.userinfo.refresh-interval=60
zuul.ratelimit.policies.userinfo.type=origin


routes:
   - id: user_route
    uri: http://localhost:8080
    predicates:
     - Path=/*
    filters:
     - name: RequestRateLimiter
      args:
       redis-rate-limiter.replenishRate: 1
       redis-rate-limiter.burstCapacity: 1
       key-resolver: "#{@ipKeyResolver}

服务降级

当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。是一种舍车保帅的策略。

比如平时客户来我的店铺购买衣服。平时可以试穿,给出建议,帮助搭配,最后下单支付,送用户祝福卡片等。双11大促则简单粗暴响应下单支付收钱发货。其他不太重要的服务关闭开关,腾出资源让位主交易流程。

服务降级可以从前端页面,后端微服务两个点着手。

1)页面降级

很好理解,针对页面元素处理,将不重要的操作入口置灰或屏蔽。平时调用后端接口实时呈现数据的地方替换为静态页也可以理解为一种降级操作。

2)微服务降级

配置接口开关,并通过配置中心可以灵活开闭。必要时关闭开关,屏蔽接口的实际查询,直接返回mock数据。例如,购买了本商品的用户还购买过哪些商品接口,在业务上需要调用数据中台订单统计
服务,访问量大时,关闭对外调用,直接返回设置好的一批相关商品,起到降级保护作用。

3)快速熔断

快速熔断可以认为是在应对突发情况时,对服务请求结果准确性的一种妥协。避免因单一服务垮台导致
整个调用链路崩溃。常用手段如下:

  • 抛异常:这种处理需要上层配备异常处理机制,在捕获异常时,导向错误页、等待页或稍后重试
    等。
  • 返回NULL:简单粗暴,可能会出现空白结果,并不友好。
  • 调用Fallback处理逻辑:更人性化的手段,也最常用。为每个业务配备一个备选方案。

举个例子:商品页或订单详情页面,一般都会有猜你喜欢这个模块,通过对用户的购买行为、浏览记
录、收藏记录等等进行大数据分析,然后给每一个用户推送自己可能喜欢的商品。在双11大促背景下,如果推荐服务压力过大,出现服务出错、网络延迟等等之类突发情况,导致最后调用服务失败,则可以配备一个fallback,直接返回当前商品同类别下的几款商品,作为备选方案,这比抛异常或者返回null空白页面体验要更优。

安全性

大促前做好安全防范。常见的DDos,Arp,脚本等攻击平时也会存在,日常防范已经配备。大促期间需要注意的可能更多的是业务层面的入侵,比如抢购或秒杀时的恶意刷接口。

  • 实名制,限制单用户,单ip等维度下的频次
  • 必要的地方添加验证码(图片复杂度升级,或滑块等新型方式)
  • 黑名单机制,一旦发现恶意行为,列入黑名单,并自动维护
posted @ 2021-09-16 23:49  请务必优秀  阅读(130)  评论(0编辑  收藏  举报