在物理机B上,OVS会将包从VXLAN隧道里面解出来,发给Controller层所在的虚拟机。Controller层所在的虚拟机发现MAC地址匹配,目标IP地址匹配,就根据TCP端口,将包发给Controller层的进程,因为他是在监听这个TCP端口的。
在HAProxy和Controller层之间,维护一个TCP的连接。
Controller层收到包之后,他是关心HTTP里面是什么的,于是解开HTTP的包,发现是一个POST请求,内容是下单购买一个课程。
10.下单扣减库存优惠券,数据入库返回成功
下单是一个复杂的过程,因而往往在组合服务层会有一个专门管理下单的服务,Controller层会通过RPC调用这个组合服务层。
假设我们使用的是Dubbo,则Controller层需要读取注册中心,将下单服务的进程列表拿出来,选出一个来调用。
Dubbo中默认的RPC协议是Hessian2。Hessian2将下单的远程调用序列化为二进制进行传输。
Netty是一个非阻塞的基于事件的网络传输框架。Controller层和下单服务之间,使用了Netty的网络传输框架。有了Netty,就不用自己编写复杂的异步Socket程序了。Netty使用的方式,就是咱们讲Socket编程的时候,一个项目组支撑多个项目(IO多路复用,从派人盯着到有事通知)这种方式。
Netty还是工作在Socket这一层的,发送的网络包还是基于TCP的。在TCP的下层,还是需要封装上IP头和MAC头。如果跨物理机通信,还是需要封装的外层的VXLAN隧道里面。当然底层的这些封装,Netty都不感知,它只要做好它的异步通信即可。
在Netty的服务端,也即下单服务中,收到请求后,先用Hessian2的格式进行解压缩。然后将请求分发到线程中进行处理,在线程中,会调用下单的业务逻辑。
下单的业务逻辑比较复杂,往往要调用基础服务层里面的库存服务、优惠券服务等,将多个服务调用完毕,才算下单成功。下单服务调用库存服务和优惠券服务,也是通过Dubbo的框架,通过注册中心拿到库存服务和优惠券服务的列表,然后选一个调用。
调用的时候,统一使用Hessian2进行序列化,使用Netty进行传输,底层如果跨物理机,仍然需要通过VXLAN的封装和解封装。
咱们以库存为例子的时候,讲述过幂等的接口实现的问题。因为如果扣减库存,仅仅是谁调用谁减一。这样存在的问题是,如果扣减库存因为一次调用失败,而多次调用,这里指的不是TCP多次重试,而是应用层调用的多次重试,就会存在库存扣减多次的情况。
这里常用的方法是,使用乐观锁(Compare and Set,简称CAS)。CAS要考虑三个方面,当前的库存数、预期原来的库存数和版本,以及新的库存数。在操作之前,查询出原来的库存数和版本,真正扣减库存的时候,判断如果当前库存的值与预期原值和版本相匹配,则将库存值更新为新值,否则不做任何操作。
这是一种基于状态而非基于动作的设计,符合REST的架构设计原则。这样的设计有利于高并发场景。当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。
最终,当下单更新到分布式数据库中之后,整个下单过程才算真正告一段落。
好了,经过了十个过程,下单终于成功了,你是否对这个过程了如指掌了呢?如果发现对哪些细节比较模糊,可以回去看一下相应的章节,相信会有更加深入的理解。
网易云对象存储服务 NOS(Netease Object Storage)是高性能、高可用、高可靠的云端存储服务。点击可免费体验。