当前位置:首页 » 文件管理 » 电商缓存方案

电商缓存方案

发布时间: 2022-09-27 16:41:52

1. 网站哪些内容适合用CDN技术

网站哪些内容都可以使用CDN技术的。
CDN即内容分发网络,是构建在现有网络基础之上的智能虚拟网络,CDN加速原理是用户首次请求到CDN节点,CDN节点未命中向源站获取文件,源站根据请求响应内容给CDN节点,同时CDN节点缓存内容,CDN节点将内容响应给终端用户,当同一CDN节点内的用户再次访问时,CDN便会直接将缓存内容返回给用户,让用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN加速功能虽然用域广泛,但并不是任何互联网产品都适用,考虑到加速的效果和运营成本,整理出推荐适用CDN加速的七类网站内容。
一. 静态资源加速
着互联网开发和迭代速度越来越快,我们访问的网站也变得越来越庞大,一般的企业官网以及各类展示型网站的服务器上都存储了大量静态资源,当较多用户访问我们的网站请求JS、CSS、图片等静态资源时,高并发量增加源站了压力,造成访问网络拥堵,导致我们的网站变慢卡顿。若把我们的静态资源缓存到CDN节点上,访问网站的用户直接请求到就近CDN节点,CDN节点向用户分发传输相关库的静态资源文件,这样就可以降低网站自身服务器的请求压力,提高了网站的访问速度和用户体验。
二. 动态资源加速
如今我们的互联网产品需求功能化要求巨大,我们的动态产品越来越多,交互性的动态网页如用户注册、信息发布、产品展示、订单管理等网站,动态网站大大节省工作量,无须手动的自动更新,因时因人而变,不同时间、不同用户访问同一网址时会出现不同页面等需求功能。动态资源实时性,交互性需求量更大,CDN加速系统中的核心服务器与DNS技术相结合,实时监控网络环境变化,监控各地网络延迟,有效避开网络瓶颈及拥堵环节,提高数据在源站与互联网终端用户之间传输的稳定及高效性,保障各种动态数据能够及时传递到终端,提高页面加载速度及页面展现质量。
三. 音频/视频加速
这个时代音乐,直播,小视频,电影,电视,填满了我们的碎片时光,大部分人生活离不开音频/视频,高质的用户体验要求音频/视频要扛得起夜晚高峰期的百万高并发,呈现的依然是稳定高清音画质,并且保证隐私信号传输的全程加密,CDN的HTTP/HTTPS音/视频点播加速服务通过将音频/视频文件快速分层同步传输到加速节点上,当最终用户访问时将其对网站的请求定向到离用户最近的节点上,为用户提供稳定可靠高质的HTTP/HTTPS音频/视频听觉视觉服务。
四. 图片加速
普通人常用的图片站一般为素材图片网站,漫画壁纸图片站,图片拼图工具网站,图片在线交易平台等,为个人及企业提供所需图片素材搜索,图片观看,高清图片下载等服务,例如漫画和电商平台上每天都会有大量商品图片的查询更新请求,高峰情况下每天有千万级甚至亿级的图片,CDN系统使网络和客户源文件服务器形成良好的互动,即将源站的图片(jpg,jpeg,png,gif,bmp等各种格式)、flash动画、css/js、及各种文件类型的图片缓存到节点上,无需服务端改造,能够使整体图片流量带宽下降30%~40%,实现各地用户实时快速访问刷新获取网站图片。
五. 下载加速
工具APP下载是我们现代人最基础手机的使用习惯,网络软件、杀毒软件、聊天工具、系统工具、媒体播放、输入法、手机主题和驱动等丰富的绿色软件等软件的全网下载需求促使软件开发商们及软件下载站需要提供安全、绿色、快速,是国内专业的下载环境,CDN下载加速就能为用户创造高速加密的下载场景,CDN下载分发加速,针对安装包获取、手机ROM升级、应用程序包下载等业务场景,提供稳定、优质的下载加速,具备突发性超大流量承载能力。利用多级缓存收敛及资源预热,缓解源站压力,让用户获得极速的下载体验。
六. 海外加速
全球互联产生的跨境电商,海外游戏,国外网站,让文化物品跨越物理距离来到全人类面前。物理上的距离让数据传输在高并发时期速度缓慢,致使海外用户体验感较差,针对部分海外运营商存在国际出口投入大、业务成本高;基础设施不完善,网络稳定性低;缺乏技术人才,运营能力差;大量访问用户诉求难以解决等问题,CDN依托遍及全球加速节点资源丰富,500+中国大陆境外加速,利用底层服务商自研的智能全球调度体系和质量实时监控系统,精准调度境外用户请求,提供静态外文网站、跨境电商图片网站,游戏APP下载、音视频等多种加速业务及整体解决方案。CDN能有效降低跨境访问延迟,提升服务可用性,支持全球业务无缝出海。
七. 安全加速
我们使用的大多数网站APP的设计开发,只考虑到展示和正常用户稳定使用,对于看不见的网站安全并没有太多重视。互联网经济的兴起,出于恶性商业竞争、敲诈勒索等原因,1999年开始一些企业网站受到DDOS,CC攻击,雅虎是当时最着名的受害者,近年来随着攻击成本越来越低、效果特别明显等特点,DDOS,CC攻击已经演变成全球性网络安全威胁。攻击者借助代理服务器向受害主机发送大量的合法请求,导致受害网站数据库压力就越大,被访问的频率也越高,占用大量的系统资源导致网站打开缓慢或者无法访问。众所周知DDOS攻击主要针对的是IP,所以隐藏源站IP就显得十分重要,CDN 服务将网站访问流量分配到了各个节点中,这样一方面隐藏网站的真实IP,另一方面即使遭遇 DDOS攻击,也可以将流量分散到各个节点中,防止源站崩溃,从而起到防御的作用,为网站APP做好防护。

2. 不就是一个订票网站吗 12306 的核心模型设计思路究竟复杂在哪里

本文的重点不是在如何解决高并发的问题,而是希望从业务角度去分析,12306 的理想模型应该是怎么样的。网上目前谈 12306 的文章貌似都是千篇一律的只谈技术,不谈业务分析和如何建模的。所以我想写一下自己的设计和大家交流学习。

1、需求概述

12306 这个系统,核心要解决的问题是网上售票。涉及到 2 个角色使用该系统:用户、铁道部。用户的核心诉求是查询余票、购票;铁道部的核心诉求是售票。购票和售票其实是一个场景,对用户来说是购票,对铁道部来说是售票。因此,我们要设计一个在线的网站系统,解决用户的查询余票、购票,以及铁道部的售票这 3 个核心诉求。看起来,这 3 个场景都是围绕火车票展开的。

查询余票:用户输入出发地、目的地、出发日三个条件,查询可能存在的车次,用户可以看到每个车次经过的站点名称,以及每种座位的余票数量。

购票:购票分为订票和付款两个阶段,本文重点分析订票的模型设计和实现思路。

其实还有很多其他的需求,比如给不同的车次设定销售座位数配额,以及不同的区段设置不同的限额。但相比前面两个需求来说,我觉得这个需求相对次要一些。

2、需求分析

确实,12306 也是一个电商系统,而且看起来商品就是票了。因为如果把一张票看成是一个商品,那购票就类似于购买商品,然后每张票都有库存,商品也有库存的概念。但是如果我们仔细想想,会发现 12306 要复杂很多,因为我们无法预先确定好所有的票,如果非要确定,那只能通过穷举法了。

我们以北京西到深圳北的 G71 车次高铁为例(这里只考虑南下的方向,不考虑深圳北到北京西的,那是另外一个车次,叫 G72),它有 17 个站(北京西是 01号站,深圳北是 17号站),3 种座位(商务、一等、二等)。表面看起来,这不就是 3 个商品吗?G71 商务座、G71 一等座、G71 二等座。大部分轻易喷 12306 的技术人员(包括某些中等规模公司的专家、CTO)就是在这里栽第一个跟头的。实际上,G71 有 136*3=408 种商品(408 个 SKU),怎么算来的?如下:

如果卖北京西始发的,有 16 种卖法(因为后面有 16 个站),北京西到:保定、石家庄、郑州、武汉、长沙、广州、虎门、深圳。。。。都是一个独立的商品,同理,石家庄上车的,有 15 种下车的可能,以此类推,单以上下车的站来计算,有 136 种票:16+15+14....+2+1=136。每种票都有 3 种座位,一共是 408 个商品。

为了方便后面的讨论,我们先明确一下票是什么?

一张票的核心信息包括:出发时间、出发地、目的地、车次、座位号。持有票的人就拥有了一个凭证,该凭证表示持有它的人可以坐某个车次的某个座位号,从某地到某地。所以,一张票,对用户来说是一个凭证,对铁道部来说是一个承诺;那对系统来说是什么呢?不知道。这就是我们要分析业务,领域建模的原因,我们再继续思考吧。

明白了票的核心信息后,我们再看看 G71 这个车次的高铁,可以卖多少张票?

讨论前先说明一下,一辆火车的物理座位数(站票也可以看成是一种座位,因为站票也有数量配额)不等于可用的最大配合。所有的物理座位不可能都通过 12306 网站来销售,而是只会销售一部分,比如 40%。其余的还是会通过线下的方式销售。不仅如此,可能有些站点上车的人会比较多,有些比较少,所以我们还会给不同的区间配置不同的限额。

比如 D31 北京南至上海共有 765 张,北京南有 260 张,杨柳青有 80 张,泰安有 76 张。如果杨柳青的 80 张票售完就会显示无票,就算其他站有票也会显示无票的。每个车次肯定会有各种座位的配额和限额的配置的,这种配置我目前无法预料,但我已经把这些规则都封装近车次聚合根里了,所有的配置策略都是基于座位类型、站点、区间配置的。关于票的配置抽象出来,我觉得主要有 3 种:

某个区段最多允许出多少张;

某个区段最少允许出多少张;

某个站点上车的最多多少张。

当用户订票时,把用户指定的区段和这 3 种配置条件进行比较,3 个条件都满足,则可以出票。不满足,则认为无票了。下面举个例子:

ABCDEFG,这是所有站点。座位总配额是 100,假设 B 站点上车,E 站下车的人比较少,那我们就可以设定 BE 这个区段最多只能出 10 张票。所以,只要是用户的订票是在这个区段内的,就最多出 10 张。再比如,一列车次,总共 100 个座位配额,希望全程票最少满足 80 张,那我们只要给 AG 这个区段设定最少 80 张。那任何订票请求,如果是子区间的,就不能超过 100-80,即 20 张。这两种条件必须同时满足,才允许出票。

但是,不管如何做配额和限额,我们总是针对某个车次进行配置,这些配置只是车次内部售票时的一些额外的判断条件(业务规则),不影响车次模型的核心地位和对外暴露的功能。所以,为了本文讨论的清楚起见,我后续的讨论都不涉及配额和限额的问题,而是认为任何区段都可以享受火车最大的物理座位数。

并且,为了讨论问题方便,我们减少一些站点来讨论。假设某个车次有 A,B,C,D 四个站点。那 001 这个人购买了 A,B 这个区间,系统会分配给 001 一个座位 x;但是因为 001 坐到 B 站点后会下车,所以相当于 x 这个座位又空出来了,也就是说,从 B 站点开始,系统又可以认为 x 这个座位是可用的。所以,我们得出结论:同一个座位,其实可以同时出售 AB,BC 这两张票。通过这个简单的分析,我们知道,一列火车虽然只有有限的座位数,比如 1000 个座位。但可以卖出的票远远不止 1000 个。

还是以 A,B,C,D 四个站点为例,假如火车总共有 1000 个座位,那 AB 可以卖 1000 张,BC 也可以卖 1000 张,同样,CD 也可以卖 1000 张。也就是说,理论上最多可以卖出 3000 张票。但是如果换一种卖法,所有人都是买 ABCD 的票,也就是说所有的票都是经过所有站点的,那就是最多只能卖出 1000 张票了。而实际的场景,一定是介于 1000 到 3000 之间。然后实际的 G71 这个车次,有 17 个站,那到底可以卖出多少个票,大家应该可以算了吧。理论上这 17 个站中的任意两个站点之间所形成的线段,都可以出售为一张票。我数学不好,算不太清楚,麻烦有数学好的人帮我算算,呵呵。

通过上面的分析,我们知道一张票的本质是某个车次的某一段区间(一条线段),这个区间包含了若干个站点。然后我们还发现,只要区间不重叠,那座位就不会发生竞争,可以被回收利用,也就是说,可以同时预先出售。

另外,经过更深入的分析,我们还发现区间有 4 种关系:

不重叠;

部分重叠;

完全重叠;

覆盖。

不重叠的情况我们已经讨论过了,而覆盖也是重叠的一种。所以我们发现如果重叠,比如有两个区间发生重叠,那重叠部分的区间(可能夸一个或多个站点)是在争抢座位的。因为假设一列火车有 100 个座位,那每个原子区间(两个相邻站点的连线),最多允许重叠 99 次。

所以,经过上面的分析,我们知道了一个车次能够出售一张车票的核心业务规则是什么?就是:这张车票所包含的每个原子区间的重叠次数加 1 都不能超过车次的总座位数,实际上重叠次数 +1 也可以理解为线段的厚度。

3、模型设计

上面我分析了一下票的本质是什么。那接下来我们再来看看怎么设计模型,来快速实现购票的需求,重点是怎么设计商品聚合以及减库存的逻辑。

传统电商的思路

如果按照普通电商的思路,把票(站点区间)设计为商品(聚合根),然后为票设计库存数量。我个人觉得是很糟糕的。因为一方面这种聚合根非常多(上面的 G71 就有 408 个);另一方面,即便枚举出来了,一次购票也一定会影响非常多其他聚合根的库存数量(只要被部分或全部重叠的区间都受影响)。这样的一次订单处理的复杂度是难以评估的。而且这么多聚合根的更新要在一个事务里,这不是为难数据库吗?而且,这种设计必然带来大量的事务的并发冲突,很可能导致数据库死锁。

总之,我认为这种是典型的由于领域模型的设计错误,导致并发冲突高、数据持久化落地困难。或者如果要解决并发问题,只能排队单线程处理,但是仍然解决不了要在一个事务里修改大量聚合根的尴尬局面。

听说 12306 是采用了 Pivotal Gemfire 这种高大上的内存数据库,我对这个不太了解。我不可想象要是不使用内存数据库,他们要怎么实现车次内的票之间的数据强一致性(就是保证所有出售的票都是符合上面讨论的业务规则的)?所以,这种设计,我个人认为是思维定势了,把火车票看成是普通电商的商品来看待。所以,我们有时做设计又要依赖于经验,又要不能被以往经验所束缚,真的不容易,关键还是要根据具体的业务场景多多深入分析,尽量分析抽象出问题的本质出来,这样才能对症下药。那是否有其他的设计思路呢?

我的思路

1、聚合设计

通过上面的分析我们知道,其实任何一次购票都是针对某个车次的,我认为车次是负责处理订票的聚合根。我们看看一个车次包含了哪些信息?一个车次包括了:

车次名称,如 G71;

座位数,实际座位数会分类型,比如商务座 20 个,一等座 200 个;二等座 500 个;我们这里为了简化问题,可以暂时忽略类型,我认为这个类型不影响核心的模型的设计决策。需要格外注意的是:这里的座位数不要理解为真实的物理座位数,很有可能比真实的座位数要少。因为我们不可能把一个车次的所有座位都在网上通过 12306 来出售,而是只出售一部分,具体出售多少,要由工作人员人工指定。

经过的站点信息(包括站点的 ID、站点名称等),注意:车次还会记录这些站点之间的顺序关系;

出发时间;看过 GRASP 九大模式中的信息专家模式的同学应该知道,将职责分配给拥有执行该职责所需信息的类。

我们这个场景,车次具有一次出票的所有信息,所以我们应该把出票的职责交给车次。另外学过 DDD 的同学应该知道,聚合设计有一个原则,就是:聚合内强一致性,聚合之间最终一致性。经过上面的分析,我们知道要产生一张票,其实要影响很多和这个票对应的线段相交的其他票的可用数量。因为所有的站点信息都在车次聚合内部,所以车次聚合内部自然可以维护所有的原子区间,以及每个原子区间的可用票数(相当于是库存数)。当一个原子区间的可用票数为 0 的时候,意味着火车针对这个区间的票已经卖完了。所以,我们完全可以让车次这个聚合根来保证出票时对所有原子区间的可用票数的更新的强一致性。对于车次聚合根来说,这很简单,因为只是几次简单的内存操作而已,耗时可以忽略。一列火车假如有 ABCD 四个站点,那原子区间就是 3 个。对于 G71,则是 16 个。

2、怎么判断是否能出票?

基于上面的聚合设计,出票时扣减库存的逻辑是:

根据订单信息,拿到出发地和目的地,然后获取这段区间里的所有的原子区间。然后尝试将每个原子区间的可用票数减 1,如果所有的原子区间都够减,则购票成功;否则购票失败,提示用户该票已经卖完了。是不是很简单呢?知道了出票的逻辑,那退票的逻辑也就很简单了,就是把这个票的所有原子区间的可用票数加 1 就 OK 了。如果我们从线段的厚度的角度去考虑,那出票时,每个原子区间的厚度就是 +1,退票时就是减一。就是相反的操作,但本质是一样的。

所以,通过这样的思路,我们将一次订票的处理控制在了一个聚合根里,用聚合根内的强一致性的特性保证了订票处理的强一致性,同时也保证了性能,免去了并发冲突的可能性。传统电商那种把票单做类似商品的核心聚合根的设计,我当时第一眼看到就觉得不妥。因为这违背了 DDD 强调的强一致性应该由聚合根来保证、聚合根之间的最终一致性通过 Saga 来保证的原则。

还有一个很重要的概念我想说一下我的看法,就是座位和区间的关系。因为有些朋友和我讲,考虑座位号的问题,虽然都能减 1,座位号也必须是同一个。我觉得座位是全局共享的,和区段无关(也许我的理解完全有误,请大家指正)。座位是一个物理概念,一个用户成功购买了一张票后,座位就会少一个,一张票唯一对应一个座位,但是一个座位有可能会对应多张票;而区间是一个逻辑上的概念,区间的作用有两个:1)表示票的出发地和目的地;2)记录票的可用数额。如果区间能连通(即该区间内的每个原子区间的可用数额都大于 0),则表示允许拥有一个座位。所以,我觉得座位和票(区间)是两个维度的概念。

3、如何为票分配座位?

我觉得车次聚合根内部应该维护所有该车次已经售出的票,已经出售的票的的本质是区间和座位的对应关系。系统处理订票时,用户提交过来的是一段区间。所以,系统应该做两个事情:

先根据区间去判断是否有可用的座位;

如果有可用座位,则再通过算法去选择一个可用的座位;

当得到一个可用座位后,就可以生成一张票了,然后保存这个票到车次聚合根内部即可。下面举个例子:

假设现在的情况是座位有 3 个,站点有 4 个:

座位:1,2,3

站点:abcd

票的卖法 1:

票 1:ab,1

票 2:bc,2

票 3:cd,3

票 4:ac,3

票 5:bd,1

这种选座位的方式应该比较高效,因为总是优先从座位池里去拿座位,只有在万不得已的时候才会去回收可重复利用的票。

上面的 4,5 两个票,就是考虑回收利用的结果。

票的卖法 2:

票 1:ab,1

票 2:bc,1

票 3:cd,1

票 4:ac,2

票 5:bd,3

这种选座位的方式应该相对低效,因为总是优先会去扫描是否有可回收的座位,而扫描相对直接从座位池里去拿票总是成本相对要高的。

上面的 2,3 两个票,就是考虑回收利用的结果。

但是,优先从座位池里拿票的算法有缺陷,就是会出现虽然第一步判断认为有可用的座位,但是这个座位可能不是全程都是同一个座位。举例:

假设现在的情况是座位有 3 个,站点有 4 个:

座位:1,2,3

站点:abcd

票的卖法 3:

票 1:ab,1

票 2:bc,2

票 3:cd,3

现在如果有人要买 ad 的票,那可用的座位有 2,或者 3。但是无论是 2 还是 3,都要这个乘客中途换车位。比如卖给他座位 2,那他 ab 是坐的座位 2,但是 bc 的时候要坐座位 1 的。否则拿票 2 的那个人上车时,发现座位 2 已经有人了。而通过优先回收利用的算法,是没这个问题的。

所以,从上面的分析我们也知道选座位的算法该怎么写了,就是采用优先回收利用座位的算法。我认为不管我们这里怎么设计算法,都不影响大局,因为这一切都只发生在车次聚合根内部,这就是预先设计好聚合根,明确出票职责在哪个对象上的好处。

4、模型分析总结

我认为票不是核心聚合根,票只是一次出票的结果,一个凭证而已。

12306 真正的核心聚合根应该是车次,车次具有出票的职责,一次出票具体做的事情有:

判断是否可出票;

选择可用的座位;

更新一次出票时所有原子区间的可用票数,用于判断下次是否能出票;

维护所有已售出的票,用于为选择可用座位提供依据。

通过这样的模型设计,我们可以确保一次出票处理只会在一个车次聚合根内进行。这样的好处是:

不需要依赖数据库事务就能实现数据修改的强一致性,因为所有修改只在一个聚合根内发生;

在保证数据强一致性的同时还能提供很高的并发处理能力,具体设计见下面的架构设计。

4、架构设计

我觉得 12306 这样的业务场景,非常适合使用 CQRS 架构;因为首先它是一个查多写少、但是写的业务逻辑非常复杂的系统。所以,非常适合做架构层面的读写分离,即采用 CQRS 架构。而且应该使用数据存储也分离的 CQRS。这样 CQ 两端才可以完全不需要顾及对方的问题,各自优化自己的问题即可。我们可以在 C 端使用 DDD 领域模型的思路,用良好设计的领域模型实现复杂的业务规则和业务逻辑。而 Q 端则使用分布式缓存方案,实现可伸缩的查询能力。

1、订票的实现思路

同时借助像 ENode 这样的框架,我们可以实现 in-memory + Event Sourcing 的架构。Event Sourcing 技术,可以让领域模型的所有状态修改的持久化统一起来,本来要用 ORM 的方式保存聚合根最新状态的,现在只需要简单的通用的方式保存一个事件即可(一次订票只涉及一个车次聚合根的修改,修改只产生一个事件,只需要持久化一个事件(一个 JSON 串)即可,保证了高性能,无须依赖事务,而且通过 ENode 可以解决并发问题)。

我们只要保存了聚合根每次变化的事件(事件的结构怎么设计,本文不做多的介绍了,大家可以思考下),就相当于保存了聚合根的最新状态。而正是由于 Event Sourcing 技术的引入,让我们的模型可以一直存活在内存中,即可以使用 in-memory 技术。不要小看 in-memory 技术,in-memory 技术在某些方面对提高命令的处理性能非常有帮助。

比如就以我们车次聚合根处理出票的逻辑,假设某个车次有大量的命令发送到分布式消息队列,然后有一台机器订阅了这个队列的消息,然后这台机器处理这个车次的订票命令时,由于这个车次聚合根一直在内存,所以就省去了每次要去数据库取出聚合根的步骤,相当于少了一次数据库 IO。

这样的好处是,因为一个车次能够真正出售的票是有限的,因为座位就那么几个,比如就 1000 个座位,估计一般正常情况也就出个 2000 个左右的票吧(具体能出多少张票要取决于区间的相交程度,上面分析过)。也就是说,这个聚合根只会产生 2000 个事件,也就是说只会有 2000 个订票命令的处理是会产生事件,并持久化事件;而其余的大量命令,因为车次在内存计算后发现没有余票了,就不会做任何修改,也不会产生领域事件,这样就可以直接处理下一个订票命令了。这样就可以大大提高处理订票命令的性能。

另外一个问题我觉得还需要提一下,因为用户订票成功后,还需要付款。但用户有可能不去付款或者没有在规定的时间内完成付款。那这种情况下,系统会自动释放该用户之前订购的票。所以基于这样的需求,我们在业务上需要支持业务级别的 2pc。即先预扣库存,也就是先占住这张票一定时间(比如 15 分钟),然后付款成功后再真实给你这张票,系统做真正的库存修改。

通过这样的预扣处理,可以保证不会出现超卖的情况。这个思路其实和传统电商比如淘宝这样的系统类似,我就不多展开了,我之前写的 Conference 案例也是这样的思路,大家有兴趣的可以去看一下我之前录制的视频。

2、查询余票的实现思路

我觉得余票的查询的实现相对简单。虽然对于 12306 来说,查询的请求占了 80%,提交订单的请求只占 20%。但查询由于对数据没有修改,所以我们完全可以使用分布式缓存来实现。我们只需要精心设计好缓存的 key 即可;缓存 key 的多少要看成本,如果所有可能的查询都设计对应的 key,那时间复杂度为 1,查询性能自然高;但代价也大,因为 key 多了。如果想 key 少一点,那查询的复杂度自然要上去一点。所以缓存设计无非就是空间换时间的思路。然后,缓存的更新无非就是:自动失效、定时更新、主动通知 3 种。通过 CQRS 架构,由于 CQ 两端是事件驱动的,当 C 端有任何状态变化,都会产生对应的事件去通知 Q 端,所以我们几乎可以做到 Q 端的准实时更新。

同时由于 CQ 两端的完全解耦,Q 端我们可以设计多种存储,如数据库和缓存(Redis 等);数据库用于线下维护关系型数据,缓存用户实时查询。数据库和缓存的更新速度相互不受影响,因为是并行的。对同一个事件,可以 10 台机器负责更新缓存,100 台机器负责更新数据库。即便数据库的更新很慢,也不会影响缓存的更新进度。这就是 CQRS 架构的好处,CQ 的架构完全不同,且我们随时可以重建一种新的 Q 端存储。不知道大家体会到了没有?

关于缓存 key 的设计,我觉得主要从查询余票时传递的信息来考虑。12306 的关键查询是:出发地、目的地、出发日期三个信息。我觉得有两种 key 的设计思路:

直接设计了该查询条件的 key,然后快速拿到车次信息,直接返回;这种方式就是要求我们系统已经枚举了所有车次的所有可能出现的票(区间)的缓存 key,相信你一定知道这样的 key 是非常多的。

不是枚举所有区间,而是把每个车次的每个原子区间(相邻的两个站点所连成的直线)的可用票数作为 key。这样,key 就非常少了,因为车次假如有 10000 个,然后每个车次平均 15 个区间,那也就 15W 个 key 而已。当我们要查询时,只需要把用户输入的出发地和目的地之间的所有原子区间的可用票数都查出来,然后比较出最小可用票数的那个原子区间。则这个原子区间的可用票数就是用户输入的区间的可用票数了。当然,到这里我提到考虑出发日期。我认为出发日期是用来决定具体是哪个车次聚合根的。同一个车次,不同的日期,对应的聚合根实例是不同的,即便是同一天,也可能有多个车次聚合根,因为有些车次一天有几班的,比如上午 9 点发车的一班,下午 3 点发车的一般。所以,我们也只要把日期也作为缓存 key 的一部分即可。

总结

本文完全是凭自己对 12306 这个网站的核心业务的简单思考而得到的一些设计结果。如果真正的 DDD 领域建模,更多的是要和业务一线的工作人员、领域专家进行深入沟通,才能更深入的了解该领域内的业务知识,从而才能设计出更靠谱的领域模型和架构设计。

非常惭愧,我没有上 12306 买过火车票,家离的比较近,就算要买也是家人给我买:)所以,本文所分享的内容难免是纸上谈兵。但我觉得 12306 这个系统的业务确实比传统的电商系统要复杂,且并发又这么高。所以,我觉得这个系统真的很值得大家重视模型的设计,而不只是只关注技术层面的实现。

3. 假设自己是一名电商网站的负责人,请写出网站未来五年的发展规划

一、小型电商网站的架构

刚从传统软件行业进入到电商企业时,觉得电商网站没有什么技术含量,也没有什么门槛,都是一些现有的东西堆积木似的堆出来罢了。然而,真正进入到这个行业之后,才发现并非如此。有人说过,好的架构,是演化出来的,电商网站的架构也是如此。现在好的电商网站,看似很复杂,很牛逼,其实也是从很小的架构,也是从没什么技术含量开始的。所以,架构的演化过程,就是在技术团队不断追求极致的过程。

今天就来总结小型电商网站的架构演进。一套电商系统最初期的架构,往往会采用一个比较典型的LAMP架构,前端加上Apache/php,后端是MySQL。这个算是比较流行的。不过,目前还有一套.net的技术架构,可能大家很少提到。很不幸,我就是在一个.net平台为基础的电商公司。所以,今天也是要总结.net 平台的电商架构。

1技术架构

如何打造一个小而精的电商网站架构
一般初期的电商网站,基本就几个业务子系统:网站前台、商家前台、系统管理后台、App、M站等。业务量也不是很大。所以,MVC + 缓存 + 数据库基本就搞定了。

单就开发效率而言,.net MVC 的技术架构不会比LAMP开发速度慢。所以,一些企业,为了快速推出自己的电商平台,也会采用.net 架构。

2基础架构

如何打造一个小而精的电商网站架构
上图为基础架构层面。这是一个很简单的基础架构。

前端网站和M站,考虑到访问量和系统的可用性,基本会采用分布式部署。通过代理服务器进行请求分发。
其它的业务子系统,像商家前台和管理系统,基本上都是单机或是主从部署。
各个DB ,Redis 服务和文件和图片服务,搜索引擎Solr服务等,采用主从部署。
3详细架构

如何打造一个小而精的电商网站架构
整个系统架构里面,还有一个比较重要的组成部分,那就是监控系统。例如:流量监控、硬件监控、系统性能监控等, 还有就是对某个页面进行监控,设置页面的其中一块进行监控等。它是提高整个平台可用性的一个重要手段。多平台、多个维度的监控,能够确保系统的可用性。一旦出现异常,特别在硬件或者性能方面出现异常,监控系统也能立刻发出警告,这样也好防范于未然。

总而言之,一个好的系统架构应该从扩展性、安全性、性能和可靠性来考虑。罗马不是一天建成的,架构适合就行,可以先行之而后优。通过渐进演化的过程,逐步让系统越来越完善。

二、日志与监控系统的解决方案

监控系统主要用于服务器集群的资源和性能监控,以及应用异常、性能监控、日志管理等多维度的性能监控分析。一个完善的监控系统和日志系统对于一个系统的重要性不必多说。总之,只有实时了解各系统的状态,才能保证各系统的稳定。

如何打造一个小而精的电商网站架构
如上图所示,监控平台监控的范围很广,从服务器性能及资源,到应用系统的监控。每个公司都有特定的平台统一监控的需求及解决方案,但监控平台的任务和作用基本是一致的。

1日志

日志是监视程序运行的一种重要的方式,主要有两个目的:1.bug的及时发现和定位;2.显示程序运行状态。

正确详细的日志记录能够快速的定位问题。同样,通过查看日志,可以看出程序正在做什么,是不是按预期的设计在执行,所以记录下程序的运行状态是必要的。这里将日志分为两种:1.异常日志;2.运行日志。

我们主要是使用log4net,将各个系统的日志,持久化记录到数据库或者文件中,以方便后续的系统异常监控和性能分析。如何集成log4net,这里不多说。

日志记录的几个原则:

日志级别一定要区分清楚,哪些属于error、warning、info等。
记录错误的位置。如果是分层系统,一定要在某个层统一处理,例如我们的MVC架构,都是在各个Action中Catch异常并处理,而业务层和数据库层这些地方的异常,都是Catch到异常后,往上一层抛。
日志信息清晰准确有意义,日志尽量详细点,以方便处理。应该记录相关系统、模块、时间、操作人、堆栈信息等。方便后续处理。

4. 电商网站商品列表页用的是搜索引擎还是数据库+缓存的方式

大的电商网站页面一般都是从缓存里面读取过来的,页面更新快的缓存时间比较短。
搜索页面建议是不加缓存,或者缓存时间极短。因为用户关键词很难确定,或许高频词会缓存一些,这些就得看网站的部署策略了,缓存策略只是解决了数据库访问的压力
除了页面缓存之外,数据库还需要定时更新索引,索引的更新才是决定页面最终命中效果的关键,大的电商网站索引创建会很耗时,所以需要相对较长的时间才会更新一下索引系统

5. java 电商缓存用什么好,在线等

需要持久化就redis,否则mem,单进程guava cache,

6. 一个五年架构师为什么基本年薪酬可以达到50万

架构师,我想很多人都知道,其实该职位头衔在最早的IT领域是没有的,它是近些年来由互联网的发展所引发的需求,因为现阶段的数据量及高并发的活跃好动,引起了不少传统的技术人员的力不从心,企业愈发关注到了系统架构的重要性,所以不同行业开始招募架构技术人员,架构师就诞生了。

架构设计的条件

以下三个条件不适合做架构设计

对架构不感兴趣,但又迫于需求;

入IT行业,年限小于4年的;

主观能动性弱,又安于现状的;

架构设计的优势

更好的梳理业务的结构体系;

更好的拓展、维护及性能优化;

更好的适应企业业务灵活的推进;

更好的适应大数据的冲洗和应对;

更好的稳定性、低成本及快速迭代;

架构设计时候需要注意的地方

架构设计需要注意的地方,不是怎么把架构搭建起来,而是必须根据业务需求,严格分析,实现该需求需要什么技术会更好及更长远发展的考虑;

另外,构建好的架构虽然可以运行,但是性能需要跟起来,否则架构设计会适得其反,增加不必要的工作量,那么下面就详细介绍下架构设计的策略。

平台的需求

客户需求

在线购物、在线支付或货到付款;

购买商品后,客户可以与客服沟通;

购买商品过程,物流的管理及跟踪;

收取到商品后,商品、物流评价打分;

客户的需求为最高,也代表了企业的核心需求,当然,企业需求还包括其它很多非功能性需求,具体请查看需求梳理部分。

平台的业务架构

根据业务的需求进行子系统模块划分,可以划分为商品子系统、购物子系统、支付子系统、物流子系统、客服子系统、评论子系统;而非核心需求可拆分出客服子系统、评论子系统及接口子系统。另外,根据各个子系统的核心等级,可拆分出核心子系统和非核心子系统,前者包括商品子系统、购物子系统、支付子系统及物流子系统;后者,则包括评论子系统、客服子系统及接口子系统。需要注意的是一般大型电商平台的物流系统是单独分离出来的系统(入库、出库、库存管理、配送管理及货品管理),而这里划分为子系统的主要目的是为演示核心架构,本架构中物流子系统一般作为对接和管理独立子系统的对接模块哦。

1、业务拆分目的

为了解决各个模块子系统间的耦合、维护及拓展性;

方便单独部署子系统,避免集中部署导致一个出问题,全部不能用;

分配专门的团队,负责具体的子系统,最大化工作效率安排;

应对大数据,高压力时,保护核心子系统正常使用;

2、业务的架构图

在上面的业务架构图中,将核心和非核心业务进行拆分,同时每个系统都要独立部署实现,做到大数据量压下,各个系统独立运作,提高可用性,必要时可以暂停掉非核心系统的资源开销,保证核心业务正常为用户服务。

平台的技术架构

在上面业务架构图基础上,我们需要一个技术架构的演变过程,一切只为满足用户的体验和支撑为前提,所以技术架构的搭建不是一蹴而就的,而是随着业务的不断衍变,系统的架构会逐渐完善更新,以实现应对业务数据量的冲击。

1、基本的架构设计

记得很早的时候,很多中小企业所采用的架构设计十分简单,基本使用一台服务器来满足一切需求部署,比如:一台服务器同时用作应用部署、数据库存储以及图片存储等,不料的是待用户数据达到50万以上,系统出现很多性能问题,尽管对数据库和程序做个各种性能优化,结果仍无明显改善,架构如下:

后来,IT程序猿发现图片的读写严重影响了系统性能,并将图片单独存放在独立服务器中,并且在架构中引入了Cache中间件,比如:Memcache,这种做法是可取的,而且比原来性能提高了1-2个性能级别,架构设计如下:

2、初级的架构设计

前几年,一般的电商网站的做法是选用三台服务器,一台部署应用,一台部署数据库,一台部署NFS文件系统,做到将各个规模庞大并耗用性能的部分剥离到不同服务器设备,再配备必要的缓存中间件,基本可以满足近1000万的数据量,具体的架构图如下:

但是,目前主流使用的网站架构已经不同,大多采用集群的方式来实现负载均衡和高可用性,架构可以是下面的样子:

注意:

如果涉及到多台网站服务器的话,就会存在Session如何同步的问题,一般也是最为常用的做法,就是使用Cache中间件来存储和管理Session信息。

3、优化的架构设计

这里为解决高并发,高可用的大型电商网站的架构设计方案,主要采用了分布式、集群、负载均衡、反向代理、消息队列及多级缓存技术。该架构设计方案,是现今比较流程的大型电商网站采用的架构模式,比如:淘宝、京东等,也许会有细微不同的地方,但大同小异哦!具体的架构图方案如下:

平台架构的总结

这里主要总结的是优化架构,架构按层次结构罗列组织,共分为四层,层次分工明确,高拓展,低耦合,负载均衡、集群、分布式及缓存等技术的使用,架构如下:

好了,电商平台的架构设计就介绍到这里,本篇主要是介绍架构设计的思路及应用的核心技术,供在架构设计的同学参考借鉴哦!有想了解更多的可以关注我

7. php在实际电商项目开发中 一般哪些逻辑可以写缓存

不需要及时更新的都可以缓存

8. 移动云云数据库Redis有什么产品功能缓存应用怎么样

首先云数据库Redis是一款内存型数据库,云数据库Redis应用场景还挺多的,可用于游戏缓存、互联网缓存、电商高并发,所以缓存应用是redis最为普遍的用途,各行各业都适用!

9. redis缓存商品分类,什么时候缓存合适

写在那里都可以,个人感觉最好还是写在业务层,用的时候直接取redis数据,没有值得话查询数据库,然后重新add redis数据。但是在更新数据库数据的时候,记得同步更新redis数据。

热点内容
日本溥仪访问 发布:2025-07-03 04:24:27 浏览:672
java文件遍历 发布:2025-07-03 04:22:22 浏览:140
android画虚线 发布:2025-07-03 04:11:04 浏览:384
系统启动密码怎么取消 发布:2025-07-03 04:08:06 浏览:746
python程序设计第三版课后答案 发布:2025-07-03 03:58:08 浏览:213
socket上传文件 发布:2025-07-03 03:57:24 浏览:895
安卓cleo脚本 发布:2025-07-03 03:41:26 浏览:245
编程器解读 发布:2025-07-03 03:22:49 浏览:24
中国电信加密通信业务 发布:2025-07-03 03:06:00 浏览:521
脚本家的台词 发布:2025-07-03 03:05:50 浏览:710