重构购物车的过程

背景


公司目前所有的核心业务都在一个应用中,属于单体应用,随着业务的快速发展和开发人员的不断增加,单体应用的开发模式就开始暴露出各种各样的问题。经历过这个过程的开发人员,想必深有体会。

我举个最近才遇到的一个例子。今年的八月份,有5个大需求要在同一天上线,由于只有一个单体应用,5个需求又都不同,因此拉了5个开发分支,对应5个需求。好了,在八月的某个相同时间段,各个测试人员都要开始测试自己负责的模块了,测试环境不够用(部分创业公司里,测试环境经常不够用,也没有用docker),开发人员只能临时用了一个分支,叫xxxxx_all分支,将需要测试的所有分支都合并到这个分支里,这是没有办法中的办法了,但是会出现各种问题:

开发人员在自己的分支里改完代码后,每次都需要合并到xxxxx_all分支,经常出现冲突,因为大家都往all分支合并代码。解决冲突的过程非常消耗时间,因为冲突的代码不是自己写的,不敢随便合并,只能叫其他开发人员过来协助。另外,合并代码的时候,很容易一不小心就将别人代码覆盖掉,导致测试人员经常发飙,刚刚还好好的功能,又不行了。

可能有网友会问,干嘛不直接在xxxxx_all分支上开发呢?这样做有个风险,因为在创业公司里,老板经常会突然叫停某个功能的,不想上了。这个时候,如果都在xxxxx_all分支上开发,就得把部分需求的代码剥离出来,也很麻烦的。万一剥离不干净,上线了,那就悲催了。

那么在这次的购物车重构项目,也是八月份上,但是由于购物车抽取成微服务了,是单独的应用了,使用单独的分支,没有跟原来的单体应用的代码混合在一起,算是幸免于难了,爽爽的在自己分支上不断提交即可。

随着业务不断发展和开发人员不断增多,单体应用的问题不只是上面提到的开发模式问题,更为要命的是,这个单体应用某个模块的某一点代码有问题,会拖垮和影响其他的核心模块。另外,整个单体应用中的某个不重要的模块的代码修改了,就得上线,但是其实很多核心模块并没有改动代码的。比如说,我们最近遇到的一个慢SQL查询的,由于商品分类导航的SQL语句写的非常差,稍微流量大一些,数据库服务器CPU就hold 不住了,直接影响了下单这个核心模块了。


关于购物车表的迁移


从单体应用到应用服务化,其中最难搞的便是数据库。就拿购物车来说,熟悉电商购物车的都应该知道,购物车通常都有如下功能:

  • 失效列表商品:可能有部分商品下架了或者库存为0了,在购物车里被列为失效商品了;
  • 购物车列表按照营销活动聚合,比如说,满xx减yy这种活动,只要是这种活动的商品,都聚合在独立的卡片里;
  • 展示商品的基本信息;
  • 调整购物车商品数量;

从上面的业务可以看到,购物车至少要依赖如下几个模块:

  • 商品模块
  • 库存模块
  • 营销模块

如果我们把购物车相关的数据库表单独挪动出来,成为一个单独的购物车数据库,那么购物车依赖的模块,也必须已经抽取成微服务了,然后购物车服务通过调用接口的方式来读取其他模块的数据。但是,我们并没有用这种细粒度的方式,原因有三个:

  • 购物车服务是公司的第一个微服务,在购物车之前,没任何微服务接口的;
  • 购物车原先是PHP写的,从维护成本和独立性考虑,优先重构购物车;
  • 商品、库存和营销模块太复杂了,改造成本极其大,且其他模块对它们的依赖太多了,牵一动全身;

因此只能采用如下的折中方案:

购物车的数据库表暂时不迁移出来,至于购物车依赖的商品、库存等模块,在购物车服务里实现一遍。等到后续依赖的模块抽取成微服务后,再改造一次,从本地调用改成远程调用。

有网友可能会说,好烂的重构方案哦,确实,这是个折中的方案。但是你要知道,在老板只给2、3个星期的期限,同时还要继续支持其他业务开发的情况下,想要有阶段性的里程碑,只能这么干了。不太可能有专门的重构部门和团队,让你好好重构个一两年,这在创业公司里,是不可能做到的。

另外根据我们现在公司的情况,这种方案是可行的,因为购物车虽然依赖的商品、库存等模块,相关的依赖的那部分逻辑不复杂,同时,购物车流量也不是很大,暂时无需将购物车数据库表迁移出来并分库。


购物车数据的存储方案


在PHP版本里的购物车中,购物车列表是从Redis读取的,然后用户对购物车数据进行修改的时候,刷新购物车列表的缓存数据。当时我看到这种设计后,直接就无语了。因为在我的认知里,购物车数据要么纯用Redis,要么纯用数据库。像京东的购物车,全部数据都存储在Redis里,读写操作也全部基于Redis,这种方案挺好的,用Redis比用数据库快非常多。而唯品会则是采用数据库的,并用一百多个分库,缓解写的压力。

因此我当时做的第一个决定,就是直接用数据库即可,量大的时候,采用分库。避免即用Redis又用数据库这种鸡肋无用的设计,同时购物车写接口也无需维护缓存了,变得简单了一些。


微服务框架的选择


当时我跟老板建议,先服务化,再微服务化。但是老板不答应,说一步到位,直接微服务化。
我本来的想法是,先垂直拆分购物车服务,然后对外暴露http接口供调用方调用,先别用服务发现、注册中心那套,因为学习成本高,也不知道有啥坑。但是被否掉了,只能直接微服务化。

市面上最火的是Dubbo和Spring Cloud,Dubbo我们团队没人会用,而Spring Cloud团队里有几个人用过,加上我们公司原本的应用就是基于Spring Boot的,因此直接采用Spring Cloud。另外,Spring Cloud的社区非常活跃,出了问题,也比较好定位。


需要一次把Spring Cloud全家桶全用上吗


Spring Cloud还有网关、调用链跟踪、监控等等组件,这些都是好东西,时间允许的情况下,当然都要用,但是如果时间太紧了,就只能先把注册中心、服务发现、路由等必须要的组件先用上,后续再找时间补充上其他组件。另外一下子用太多,出问题了,也加大了定位问题的难度。


Spring Cloud架构部分场景验收


当功能测试通过后,最好搞一个预发布的环境,验证一下Spring Cloud新架构是否能正常工作。下面是一些验收的Case:

  • 路由功能:有多台机器和多个微服务后,请求必须能路由到不同的机器,避免所有请求只路由到某台机器上;
  • 注册中心重启;
  • 手动kill掉其中一个微服务,看看客户端的请求会不会继续路由到坏掉的服务上;

线上观察


上线后的第一个星期,要经常盯着微服务,看看有没有请求慢的、机器的CPU、内存、数据库的负载等。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值