大型网站架构实践

小明:我在一家电商公司上班,最近又要面临双11的大考了,每次都会紧张的要命。

小明:特别是大促开始的前5分钟,系统的压力非常大,比平时流量要翻上10几倍。这时候系统往往都会不可用几分钟,压力山大啊。

程序羊:那现在的架构是个什么样子的?

小明:我们做了系统拆分,用dubbo作了服务化,现在的架构是这个样子的:

大型网站架构实践_第1张图片
系统架构

程序羊:不错,主流的架构,一般的流量不会冲垮。

小明:是啊,平时运行很稳定,但大促的时候总会挂一会儿。比如说首页的商品展示,上一次是因为优惠券服务比较慢,导致首页平响标高,之后就无法提供服务了。

小明:由于商品详情页的流量比较大,导致下单确认页调用商品服务延时很高,用户不能下单了。

程序羊:由于某个服务不可用,导致某个重要的服务不可用,发生了雪崩。

小明:有什么方法可以解决这个问题呢?

程序羊:在整体部署架构需要做一些调整,如果想降低系统平响,提高系统质量,需要调整下系统架构。

程序羊:我们先看如何调整部署结构,核心思想就是按照重要程度和访问量进行隔离。

小明:部署层面进行隔离?

程序羊:大促期间将访问量大或者比较重要的服务单独部署,做到进程层面的隔离。一般来说我们的服务都读的量要不写的量大很多,部署一组从库专门负责读。来看下部署结构。

大型网站架构实践_第2张图片
服务分组.png

小明:这样的话我就不用担心首页量影响到其他模块,做了一次隔离。

小明:这样可以解决一些问题,但是如果这次优惠券服务又延时,首页还是有可能出不来。

程序羊:可以想象一下,优惠券在整个流程里不是主要流程,如果优惠券延时比较大,我们可以暂时不展示优惠券,这就涉及到非主要流程的降级。

小明: 跟首页相比,优惠券确实不是最主要的,可以舍车保帅。有没有什么工具可以方便的做降级,自己写太耗时了。

程序羊:可以使用 hytrix,比较成熟的一个工具,和spring-cloud结合使用比较简单。

    @HystrixCommand(groupKey = "activitySkuInfoBatch")
    @RequestMapping(value = "/activitySkuInfoBatch", method = RequestMethod.GET)
    public Map getActivitySkuInfoBatch(
            @RequestParam(value = "productIds") String productIds) {
        List productIdList = JacksonUtil.json2List(productIds, Long.class);
        return activityProductQueryService.currentActivityProduct(productIdList);
    }

小明:这还挺方便的,具体使用方法我找找资料看下。有了进程间隔离,有了降级,这下可以稳定一些了。

程序羊:hytrix 会帮咱们做线程间的隔离,又多了一层保障。

小明:如何能提高单个部署节点的平响呢,单个节点可以承受更多的请求后,就可以少部署一些机器,也为公司省点钱。O(∩_∩)O哈哈~

程序羊:看了你也是很有追求的。其实分析下,我们的平静可能是在存储上,比如说Redis,DB。我们一个请求往往要查询多次存储,也有可能会连表查询。

程序羊: 另外我们应用的特点是,读的量要远远大于写的量,特别是商品这一类的服务。

小明:是啊。

程序羊:给你介绍一种架构方式CQRS,原理看下图:

大型网站架构实践_第3张图片
CQRS

程序羊:CQRS具体的知识,你搜索下,这种架构可以让你每次请求尽量只查询一次存储。

程序羊:如果做的好一些,可以直接在反向代理层Nginx上使用LUA直接查询存储,流量都不会打到应用服务器上。

小明:这样应用服务器压力就小多了。

程序羊:是的,我们的架构可以演化成这样,如下:

大型网站架构实践_第4张图片
CQRS.png

小明:这样的话,一般的流量应该都可以抗住了。

程序羊: 开发的时候要注意,能异步去做一些事情的时候就要异步做。

程序羊: 比如说一个聚合服务,要同事查询商品和用户信息,两个流程上没有先后顺序,可以并发异步的去查询,最后将结果合并。

小明:按照这么改,大促以后就安枕无忧了。

你可能感兴趣的:(大型网站架构实践)