我在阿里的第一年

写在前面

  从2018年5月开始收到菜鸟offer实习到本科毕业,我不小心实习了一年。这一年get到了很多东西,也有一些想法,这篇文章本来早就该写了,因为自己“忙”,就一直没去把这篇总结落实下来。今天实在忍不住了,开始动身欲写在菜鸟实习一年的所思所得。

  在我实习的时候,我的老板就问过我实习了这么久觉得自己得到了哪些东西,自己还欠缺哪些东西,有没有认真去思考过。当时的我支支吾吾也没能对这位负责的老板说上个所以然。这篇文章主要就谈一谈我做了些什么,得到了些什么,还欠缺些什么。

做了什么

  说来惭愧,感觉自己实习的一年时间还是很松散的,这个松散不是说自己做的事情少,而是做的事没有去积极思考为什么去做,带来的价值是什么,不做可能会导致什么后果。更多时候自己只是一个任务的执行者,关注了太多如何去执行,视野比较窄。先来简单罗列下做了哪些项目(已脱敏处理):

  某项目1(脱敏)

  刚入职的时候,团队在做一个已经做了两年的to B项目,给我们的合作伙伴进行赋能,为了数据安全此处这个项目名称不表了。某次有幸能和团队年轻有为的大老板在一起沟通,问到这个项目到底作用是什么,我们这样做下去的意义的时候,大老板说了很多这个项目的重要意义。比较遗憾的是后来组织架构调整,我们这一块不再做to B业务,转向做to C业务,这个项目就转交给其他团队了。以自己的一点愚见,当时公司的方针一直都是尽可能好地去赋能我们的合作伙伴。然而我们做什么,合作伙伴抄什么。我们产出的很多东西合作伙伴也不去用,转而自己去开发一套自己的东西。当时我们和合作伙伴合作,他们的数据都不怎么想给我们。可以看出合作伙伴不想依托我们,我们也很难建立自己在行业的壁垒,更别提在这上面进行盈利了。现在团队开始做起了to C业务,也不知道之前那些东西咋样了。

  在这个项目中,我们的目标根本上是为了让合作伙伴提效降本,因此需要利用离线计算/实时计算产出大量的报表页面,供合作伙伴进行监控,同时提供这些数据的明细下载和汇总下载。

  自己作为一个实习生,是没有数据权限的,划了一段时间水之后,只能开始写一些react页面。当时团队有数据下载并且生成excel的需求,但是大家各用各的解决方案,比较不统一。另一方面,我大致算了一下,一个excel会在内存中占用几十M乃至上百M,而且这样的excel生成并且写入OSS云端磁盘之后就再也用不到了。《深入理解java虚拟机》中有一句话,大致意思是JVM不喜欢朝生夕拾的大对象。因为大对象会直接进入JVM的老年代,使得JVM的Full GC会很频繁,让应用性能变得很糟。之后我开始查找excel相关的文档,尝试解决这个问题。后来我把这个问题解决了,并且抽象了一套异步从离线表里多线程读取数据,然后在内存中生成excel,写入到OSS提供下载的组件。使得团队之前写异步生成excel的代码行从数百行降到了几十行,并且生成excel的过程中占用的内存大小从几十M上百M降为了固定的2M。

  某项目2(脱敏)

  大约在八月左右,我迎来了我参与的第一个双十一项目。没错,这个项目还是给合作伙伴赋能,一个偏监控的项目,感谢前端伙伴,这个项目看起来非常非常炫酷。最终这个项目出现在了上海国际进口博览会上,受到了国家领导人的参观。

  前面提到了,这是一个偏监控的项目,在双十一场景下,数据量必然会非常的大。数据量大怎么办?第一反应肯定是分库分表啊,按照一个列进行分库分表,把请求打散到不同库的不同表上。但是这种方案有一个问题,需要有一个合理的分库分表键,这个分库分表键一般是userId。很遗憾,我们没有合适的分库分表键,这种方案不适用,但是又必须保证查询的实时性。然而这个问题在阿里强大的技术生态面前不是问题,阿里云对外提供了一个支持海量数据实时高并发的在线分析型数据库ads(也叫garuda),能提供千亿数据规模的查询和亚秒级别的响应。像mysql这样的OLTP系统一般是行存储,同时加上了B-tree索引,在select多列的情况下很很好。而OLAP系统一般是列存储,在select列比较少的时候优势就体现出来了,因为基于列存会使得数据有更高的压缩比。ads则是将两者进行了混合,采用了行列混存,在列存的基础上,将关系比较紧密的列放在一起,构成了行组。我们最终采用了ads来进行这种场景的数据存储。

  这是我的第一个用Spring boot写的项目...之前没接触过这个东西,当时经常弄得自己一脸蒙圈。不过自己负责那部分逻辑比较简单,也算是按时完成了这个项目。

  自助取数工具

  前面提到了,我们经常在做一些产出数据/产出报表的事情,我们就在想能不能把这件事让运营去做,让开发去做一些对系统建设更重要的事情。于是这个项目产生了,让运营去自助取数据,自助去产出报表。

  这是我第一个从0开始使用阿里技术栈搭建前端+后端的一个项目,当时我负责的一块遇到了一个问题。我们既然要让运营去取数,我们不可能把我们的所有数据模型都暴露在运营面前。因此我们要先把数据模型进行一次封装,当时师兄是想提供使用sql去产出一层数据,然后让运营去基于这层数据取数的能力。那这样就出现了一个问题,比如我的sql是select a.c1, a.c2, a.c3, b.c4, b.c5 from ((select * from table1 where c6 > 1) as a join (select * from table2 where c7 > 2) as b),我该如何解析出我最外层select出来的数据来源于table1还是table2?这还只是一个基础的场景,如果这个sql还有多层join关系,带上错综复杂的where关系和group by操作,那将会更恶心。

  当时我调研了阿里链接池druid中的sql parser模块,理解了druid中将sql拆分出来的抽象语法树每一块的含义。有了druid的sql parser解析出了sql对应的抽象语法树,我就不用去涉及编译原理了(本科的编译原理简直是我的痛)。但是这里还有一个问题,druid的sql parser解析出来的是静态的抽象语法树,也就是对于sql:select c1, c2, c3, c4, c5 from ((select * from table1) as a join (select * from table2) as b) 我不知道c1、c2、c3、c4、c5各自来自于哪一张表,还需要通过元数据去看table1和table2有哪些列,然后通过动态规划去计算列和表之间的关系。

  很开心这个问题最终自己解决了,但是一方面当时那版代码写得很烂,师兄帮我review了一遍又一遍;另一方面,我当时为解决这个动态解析sql的问题花了挺大精力,师兄也在引导我如果开发成本比较高,应该反过来去思考,这样花大精力去做这件事是不是真的有价值,有没有一些替代方案,而不是低着头去把它硬搞完。

  规则引擎

  阿里有一个价值观叫做“拥抱变化”  ,是的,我体验到了。我们团队从to B业务调整到了to C业务,开始接手别人之前的一块老系统,当起了有缘人。为了系统稳定性和可维护性,我们开始进行了老系统重构。我们做的业务域偏平台方向,更多的是提供一个底层能力,给业务赋能好。这就涉及到一个问题,很多时候我们根据不同的业务场景需要调其他团队不同的接口来判断要不要执行一些逻辑、执行什么逻辑。这种判断逻辑不可能写在我们的平台系统里面,因为那样的话我们的平台系统会包含大量的临时代码,代码腐化速度会很快,又得等待下一位有缘人来重构我们的代码了。即使是写在业务团队的系统里,他们每有一个新逻辑就需要新写代码、部署系统,这是比较不合理的,对业务团队而言也是不易于去维护的。于是我们准备开放一个平台,让其他团队能可视化地配置要执行哪些逻辑,调用哪些其他团队的接口,这就是规则引擎。

  这里规则引擎的本质就是可视化拖拽式编程,将可视化拖拽式编程的结果生成一个groovy脚本,将groovy脚本动态编译为class字节码,在系统当前的JVM中进行执行。

  过期积分定时清理

  这个应该是我实习离职前做的最后一个事了。在所做的to C平台中,有一块积分相关的业务,这个积分对应了一个积分变更的明细表。这个域的积分是会过期的,如果这个积分明细中过期数据不删除的话后续库表数据量会越来越大,容易产生一些满sql,因此需要进行定时积分清理。

  我在清理前大概算了下需要清理的数据量,高达8亿行数据。要删除这些数据的第一个问题在于如何去找到哪些数据该删除;第二个问题在于删除的时候由于涉及到数据库磁盘IO的资源、数据库链接、行锁等的数据库资源的限制,需要给删除操作进行限速;第三个问题在于我们的系统都是分布式的,如何去进行任务拆分使得所有机器都能参与进这个删除任务,而不会出现单点问题。

  最后通过这个事利用公司的分布式定时任务框架沉淀了一套从离线数据里取数,进行任务拆分,分发给不同机器,然后按照一定逻辑在mysql中按照一定速率上限执行的逻辑框架。

  RPC

  是的,这个项目是离职后写的...在职的时候看到公司的微服务触动很大,对模块之间的RPC很感兴趣,很想知道他是如何实现的,于是一时冲动把撸一个简易的RPC框架作为了自己的毕设题目。

  当时抽空看了看公司低版本的RPC框架HSF(之所以是低版本,是因为我忘记从git主干拉最新代码了...),那个版本的HSF实现比较简单,自己又在那版HSF的基础上再进行了简化,但还是大致实现了数据接入、负载均衡、选址、序列化、协议编码、数据传输、协议解码、线程池调用、限流、反序列化、反射调用的一套RPC流程。

  当时简单用2核的mac测了一下这一套流程的TPS,大约在35K左右,公司最新的RPC框架我没记错的话TPS大约在120K左右。因为我看的是很老的代码,后面还得看一下最新的代码做了哪些优化。

  但是其实分析一下这一套RPC流程的耗时点就可以发现,其实耗时主要是发生在序列化和反序列化、网络IO上。对于序列化和反序列化,hessian2、protobuf、kryo等序列化和反序列化方式都已经做得很好了;对于网络IO,也有著名的异步的、事件驱动的网络IO框架netty。其实用堆积木的方法来写一个RPC也很简单,而且也能提供不错的TPS了。

得到了什么

  技术

  说出来不怕笑话,自己一年前是一个连git、maven都不会用的人,也没有一点安全生产的概念。当时git只会add、commit、push三连,要是什么时候出现问题就开始犯懵。师兄第一次给我一个小需求的时候,我拿着git一顿操作,把远程库分支搞得一团乱。当时也不知道本地项目怎么去启动,好不容易push成功了,就开始往线上发代码,想在线上搞测试。还好当时没编译通过,线上不让发,不然完蛋了...后来自己针对性地学习了一下这些基本的工具,才慢慢开始真正上手。

  入职前自己可能计算机基础理论体系还可以,对java也比较熟悉,分布式理论也能说一点,但是感觉自己是开始工作挺长时间之后才把这些东西串起来,构建成一个体系:

  比如为什么使用缓存、为什么分库分表、如何保证分布式事务、为什么要用消息、为什么消息会出现重复、使用消息和RPC的区别等等这种问题都是在工作中才慢慢深入理解的。

  心态

  在入职菜鸟前,我以为阿里系的都是在做纯技术,挑战很大。之后发现这的确是一家业务驱动的公司,大部分时候都是在写业务代码,会有种用技术做业务,都是CRUD,随便cover的错觉。后来自己的心态开始有了一些变化,发现想做好业务也很复杂,业务代码面对的场景会更加多变、复杂性也会更高。软件工程领域的六字真言,“低耦合,高内聚”,真的能做好吗?进行领域划分的时候真的能想清楚边界吗?设计数据库字段的时候能做到考虑到所有场景的同时又不会让数据库字段看起来很臃肿吗?写业务代码和写技术代码可能只是面对的问题不一样,他们都需要学会分解问题、抽象问题、多维度思考问题。可能大多数时候只是自己把业务问题想的太简单了。

欠缺些什么

  技术深度

  感觉自己目前的技术深度还是欠缺很多,比如自己经常用的spring boot怎么跑的,pandora boot怎么利用不同类加载器来解决包冲突的,mybatis怎么把接口映射为对象的,保证数据强一致性的paxos是怎么工作怎么工程化的等等之类的问题,连着追问可能能问出很多相关的问题。

  作为一个应届生可能首先技术需要有一定的广度,能够解决需求,之后便是技术深度,能够解决问题。

  业务思考

  自己实习的一年期间,大部分时候都只是一个执行者,去执行一件事情,大多数时候没有想为什么要做这件事,不做这件事会怎么样。开发是宝贵的资源,不应该浪费在无意义的需求上,做的东西一定要有价值,不是为了写代码而写代码。记得行易老师说过一句话,业务方想要给你提需求的时候一定要问他们,我晚上线一个月会怎样,或者我不做这件事会怎样。是的,应该推动业务方去思考业务的价值,同时自己也要明白一件事的价值,把有限的资源和精力进行最大化投资。

  看待问题的多面性

  某些时候自己拿到一个问题,需要去解决。可能自己没有想清楚就直接上手做了,这就是没想清楚这件事情,或者说没有看清这件事的多面性。一个问题通常会有一个出现原因、一个解决之后的预期、以及一个外部环境。可能我强行把这个问题转化为解决后的预期,这个问题之后还是会出现。

  比如现在服务器磁盘满了,我把老日志删掉,但是过个几天服务器磁盘又满了。这个时候就需要去看到这个问题出现的原因,是不是打印了一些不应该打印的东西,如果是,我把这些不应该打印的日志去掉;如果不是,日志没有出现问题,那说明我预期的磁盘占用增长速度不对,我的服务器磁盘太小的,光删日志解决不了问题,应该申请更大的了。又或者说,磁盘大小和日志打印都没问题,只是运营突然推了一个push消息,太多用户突然涌进来了,把我们机器打满了。这就是外部环境的问题,应该让他下次推push和我们说一声,我们好准备。

  这一点不只是一个方法论,更多的还需要靠积累的知识来进行实践,了解得越多,看问题越透彻。

  做事的条理性

  在阿里很有很多事情同时在push你,有时候需要一件一件去close,有时候被其他人block住了,需要切换到去做其他事情。但无论如何,做这些事都一定要有条理性,有时需要列一个list,哪些事情close了,哪些还没有,哪些被block住了,我可以去做一些其他的事。

  沟通能力

  首先,能不能把这件事情和别人说清楚直接取决于你对这件事到底理解得透彻不透彻,如果自己都理解不透彻,那就更不用谈沟通了。第二,尝试用一些结构化的语言,因果关系、递进关系、承接关系等要用好。第三,和别人沟通的心态要放端正,我是来沟通的,不是来吵架的,不是来卖萌的,应该把自己的位置放得和对面一样,哪怕自己被怼,也应该把自己的思路清晰地说出来。

  在大学的时候感觉自己做presentation也好,和别人扯淡也好,觉得自己还是可以讲清楚一些事的。入职之后可能感觉周围人title也好,年龄也好都完全碾压我,沟通以及presentation都变得不那么自信,生怕被怼。但是其实把自己的理念想清楚,讲清楚,哪怕被怼了也不应该慌,努力好好沟通。当然,问题的关键在于把自己想表达的理念想清楚,将清楚。

2018/5/7 - 2019/5/10

发布了106 篇原创文章 · 获赞 285 · 访问量 59万+

猜你喜欢

转载自blog.csdn.net/qq_35580883/article/details/100055890