【session】Java电商平台开发技能图谱,探秘双十一百万PV

网友投稿 586 2022-05-30

您将学习

Java电商平台开发技能图谱,探秘双十一百万PV

分享内容

企业级Java开发技能图谱

从宏观到微观,Java到底怎么学

为了支撑双十一,我们对Java程序做了什么

你将认识

热爱分享的常乐君

开源组织javagrowing成员、CSDN博客专家、华为云专家

Thoughtworks咨询师,华东区Tech Lead

5年Java开发经验,1年培训新人经验

喜欢leetcode打野,偶尔出现在周赛前排

年少时兼职过主播和公益广告模特,可以靠颜值吃饭却非要拼技术

正文

Hi,小伙伴们,不知道大家是否经历过学习了一门新的语言,了解了基本的语法,可以写出能够运行的程序之后,却不知道下一步该做什么的窘境。

【session】Java电商平台开发技能图谱,探秘双十一百万PV

在工作生活中大多数同学还是有一定的Java开发基础,当然我们的小伙伴中也不乏具有丰富开发经验的同学,希望等下我在分享技能图谱的时候大家都能从中有所收获。

企业级Java开发技能图谱:

接下来我们就直入主题,给大家分享一下技能图谱。这里我推荐JGrowing技能图谱,这是一份由诸多一线大厂开发人员和技术负责人共同整理的技能图谱,也是我所在的JavaGrowing开源团体共同制作的。项目的地址在这里:https://github.com/javagrowing/JGrowing 因为临近双十一所以大部分贡献者都暂时没时间处理issue和pr,在双十一之后项目会陆续被维护起来。

可以看到这个技术图谱是以企业级Java开发人员为目标而不是单纯的面试准备,涵盖了Java基础,计算机基础,数据结构与算法,分布式,基础开发工具,常用框架,分析设计,服务端开发和一些面经。其中也包括了一些书籍。我推荐大家这样使用这个图谱(也是我的使用方式):首先选择一个近期打算强化的类型,比如Java基础中的Java并发编程工具,那么我们定位到需要掌握的技能是并发的核心工具,同时也应当掌握线程安全性分析基础和线程池的相关概念。然后就可以通过寻找适当的方式:比如阅读源码(j.u.c),阅读有关书籍(JCIP:Java并发编程实战),购买一些在线课程(如果觉得看书枯燥无味的话)或者是询问身边更有经验的人:)

宏观与微观,Java到底怎么学?

Java知识图谱为我们建立了宏观上的知识框架,这个框架是很有必要的,因为不知道大家是否经历过这样的场景:有一天听到自己的同学/同事/朋友在谈论一项技术,比如WebFlux。这时候机敏好学的你嗅到了新技术的味道,然后就随手打开了搜索引擎输入:“WebFlux是什么”,在琳琅满目的搜索结果中你对WebFlux有了一个初步的认识:“WebFlux是SpringFramework5.0中的新功能,是一个典型的非阻塞异步框架,它的核心是基于Reactor相关API实现的,可以运行在Netty,Undertow以及支持Servlet3.1的容器上…bla bla bla“。这时候你大概对WebFlux有了一个基本的认识,等下,你有没有觉得,似乎只是有了一个认识,具体WebFlux可以在什么场景下使用?还不知道。WebFlux框架下程序如何编写?还不知道。WebFlux的底层实现原理是什么?又不知道。自己进入了一种似懂非懂,听过名字,知道简介却还是一问三不知的状态。这时候就需要你的知识框架和思考体系出马了!

我们先从宏观上看,WebFlux是一个Web框架,我们在它的官网上找到了他和SpringMVC的对比:

那么到这里,我们大概知道WebFlux具有Controller的功能,同时又能提供响应式的client。这时候就可以在我们的知识框架中宏观上将它放入Spring技术体系下的和SpringMVC一样或类似的位置,然后就可以进入对他的微观学习。

接下来我们再尝试着从微观的角度去分析一下WebFlux和它的周边技术,我们可以深入某一个自己感兴趣的点,比如如何利用WebFlux写一个demo,WebFlux如何实现在有限的系统资源下提高伸缩性等。这里我们以图片右下角的Netty为例,深入下去,Netty是对Java NIO的封装,而Java NIO又涉及到计算机系统底层epoll相关的概念。这时候你就彻底的进入到了一个微观的领域,再从下到上,理解为什么epoll相较于poll和selector具有更好的性能,Netty是通过怎样的封装解决了Java NIO的一些潜在问题。进而达到微观宏观的融会贯通。

为了支撑双十一,我们做了什么?

自从2009年双十一淘宝促销以来,各大电商,企业乃至线下商超都投入到了这场一年一度的全民购物狂欢。双十一期间纷纷出现的限量秒杀,限时支付,拼团拼购等玩法对线上服务系统提出了不小的挑战。作为国内最大的进口家居厂商,我所服务的公司也提出了多种线上玩法旨在招揽用户,提升销量。那么为了应对可能突如其来的流量,我们都做了什么呢?

如果我们要进行一段代码或一个架构的性能优化,我们如何知道自己性能优化的好坏呢?

首先需要测量。如果需要知道我们做了一件事的效果,我们首先就要能分清什么是好,什么是坏,也就是说要能够使我们做的事情是可衡量的。只有知道了代码修改之前的性能,对比代码修改之后的性能,我们才能知道自己对于代码的修改就是是否有影响,以及这个影响是正向的影响还是负向的影响。

这里就给大家带来另一个互动小问题,请问有多少人知道TDD?以及有多少人在实际的开发过程中是遵从TDD原则来进行开发的呢?

正如TDD中所要求的任何对于代码的改动都需要测试先行作为安全网的原则一样,对于代码逻辑或者架构的性能优化也需要保证可测试性。

这里我们团队选用Gatling(https://gatling.io/)作为负载测试,作为一款支持Scala语言编写测试定义的as code的开源测试工具,Gatling易于编写维护,所有配置参数均通过代码定义,从最大程度上减少了测试人员的手工操作成本,通过编写良好的测试程序,只需要修改极少数参数信息就可以快速测试不同用户负载下的机器性能数据,并生成详细的性能分析报告和错误统计报告。这里我不打算详细的向大家介绍Gatling的用法,感兴趣的同学可以在官网自行查看文档和demo。

利用Gatling我们对加购,结算,支付,退款,订单生成以及限量秒杀,红包卡券等功能进行了详尽的性能测试,生成了服务SLA的同时利用Arthas对热点代码进行监控,结合业务逻辑提出了很多优化方案,这里简要分享几个:

架构

1.在架构上,我们分别在网关层(Nginx,API Gateway),容器层(Tomcat)和服务层进行了限流配置和流量监控,使用了诸如令牌桶,流速控制以及最大连接数控制等方案保证服务稳定性。

使用消息队列服务实现对大流量的削峰填谷,使用Servless改写部分逻辑使其能够在高访问场景下自行动态扩容。

代码

2.代码层面,我们结合业务逻辑减少了锁粒度并适当对锁进行了降级来减少锁争用情况。A.比如过去的结算流程用伪代码大概是:

function checkout() { lock() { checkPrice() checkDelivery() checkItemAvailable() lockCoupon() sendToDownStreamSystem() reduceItemAmount() } }

经过修改之后的逻辑是

function checkout() { checkPrice() checkDelivery() checkItemAvailable() lockCoupon() lock() { checkoutItemAvailable() reduceItemAmount() } sendToDownStreamSystem() }

B.同样是扣减场景,如果是不敏感的情况我们降低了锁的方式,改使用乐观锁CAS的方式完成用户唯一可领取一张的优惠券的校验过程。

fucntion retrieveCoupon(user) { lock(user){ someThingBeforeAssign() ifNotExistTargetCoupon(user) { assignCoupon(user) someThingAfterAssign() }}

经过修改过后是:

fucntion retrieveCoupon(user) { someThingBeforeAssign() boolean flag = assignCoupon(user) if(flag) { someThingAfterAssign() } } @Transactional function assignCoupon(user) { ifNotExistTargetCoupon(user) { assignCoupon(user) } }

C.通过异步事件处理机制减少单一逻辑阻塞:比如发送通知邮件短信等,受限于第三方服务响应效率,可能第三方服务在高负载情况下响应速度较慢,对于时效性不长的场景,可以通过异步事件进行优化

function placeOrder() { redeemCoupon() sendToOrderHub() sendEmail() sendSMS() }

经过优化后

function placeOrder() { redeemCoupon() sendToOrderHub() sendEvent(SendEmailEvent) sendEvent(SendSMSEvent) } class EventHandler() { handleEmailSendEvent(SendEmailEvent) { sendEmail() } handleSMSSendEvent(SendSMSEvent) { sendSMS() } }

基础设施

3.在基础设施层面,我们配置了动态扩容规则,并且准备了备用机器以防单点故障。增加备用数据库配置,对数据库等服务进行了适当实例增强准备。同时进行了详细的基础设施故障演练,应对突发状况制定响应规则和响应策略

Ruby 缓存 Java Spring Cloud 分布式

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:敏捷史话(十六):我对《敏捷宣言》没有半点贡献—— Brian Marick
下一篇:Dubbo入门 - 分布式系统开发技术
相关文章