鱼皮的打工日记

by 程序员鱼皮 知识星球open in new window

持续记录鱼皮的工作日常、心得感悟,分享鱼皮在工作中的思考和学到的知识,大家一起加油~

日历

节选试读(更多内容仅在星球可见):

20220616

做了快一个月的大数据开发了,我也积累了一些经验。比如开发前一定要和产品仔细确认好字段的逻辑和含义,多一个 0 少一个 0 都是致命的,不然后面他们发现是自己的错误了,还是得来找你改,就可能严重影响你当前的进度。

下午主要是在开发新需求,用 Python + Spark 来开发一张大数据的维度表。其实这段逻辑我昨天都已经写的差不多的,本来想着今天简单调试一下就提前上线了,美滋滋嘞。结果我特么直接从下午 2 点调试到晚上 10 点!之所以调试花了这么多时间,主要是因为以下几个原因:

  1. 每次执行计算任务都要花时间和计算资源,不是像本地那么简单
  2. Python 的语法比较灵活(比如类型推断)、语法又和我的主语言不一样,很多语法细节不注意就导致程序执行失败了。相比之下,我觉得 Java 真的太香了。
  3. 线上环境的计算资源是动态分配的,可能你的程序第一次能正确执行,第二次因为资源不足就执行失败了。结果我还以为是自己代码哪里写错了才导致的失败,就只有不断地重试,多试几次,持续保持懵逼的状态。

不过还好同事给我分享了公司里一个动态调试 Python 大数据程序的神器(类似 Jupyter Notebook 的交互式笔记本),帮我提升了不少效率,估计顺利的话明天上午就能调试完了(又立 Flag)。

不得不感叹,做了大数据开发后,压力真是变大了不少。同事下班前还说:鱼皮自从做了大数据开发后,下班越来越晚了。唉,活能顺利干完的话,谁不想早点下班呢?

除了工作外,今天午休时间写了一篇文章、晚上下班后写了两篇文章,都是学习方向和目标选择相关的,是鱼皮持续完善的编程学习指南系列文章,加起来也快 5000 字了,希望能消除一些同学心中的疑虑。已经更新到星球语雀知识库了~ 大家感兴趣自行阅读。

20220617

今天是居家办公,整体的工作还是比较轻松愉快的~

上午 9 : 30 起床干活,先查了个小 Bug,一会儿就顺利解决了;然后就是接着调试我的 Python Spark 脚本。由于每次运行都要等个 10 分钟左右,所以我只能利用这个调试时间去做一些相对简单的工作,比如处理一下用户的反馈、确认一下之前的脚本是否有误等。

结果调了 2 个小时之后,这个脚本还是不能顺利运行。于是我只能把脚本中的几条 SQL 语句拆分出来,然后一条一条地去执行验证。然后又出现了经典问题:每句 SQL 单独运行都能成功,但是放在一起就报错!而且因为脚本是提交到远程集群上去跑嘛,不能实时得到清楚的报错信息,从报错信息中也无法看出我的代码哪里有问题,又给我整不会了!

下午周会的时候,我抛出了这个问题,结果有同学表示他也遇到过类似问题,发给我几个解决方案。然后我就按照解决方案改了两个和代码无关的线上配置,没想到就能成功运行了!!!当时真的是太激动了,因为像这种 Bug 是由环境而不是具体代码导致的,所以哪怕对着代码查一辈子,估计也解决不了问题。这也让我明白了两个道理:

解决 Bug 的时候,要学会跳出固有的思维,除了代码外,还要考虑到代码的运行环境。像大公司有很多自研项目和环境,可能稍有不慎就会踩坑。

要相信团队的力量,一个人无解时可以问问其他同事,说不定有些坑就是要靠口口相传才能解决。

顺利解决这个问题后,我顿时有种春风拂面的感觉,压力一下降低了不少。毕竟开发只花了半天,结果调试花了一天半。。。而且奇怪的是,明明自己一直在这个辣鸡 Bug 里徘徊,解决了 Bug 之后,为什么还是会有一种莫名奇妙的成就感?

晚上下班之后,继续更新星球内原创的编程学习体系,没想到这一篇直接写了近 5000 字!直到我要睡觉前还没写完。所以只能明天再发了。

👉🏻 点此加入星球

20220627

今天是全面复工第一天,首先是之前反反复复改了两周的需求终于验证 OK 了。这个需求虽然早都做完了,但因为种种原因,总是有一点小 Bug 需要调来调去,一直卡在我的待完成需求中。工作之后最怕这种验证周期比较长的需求,当你以为完成的时候产品突然发现了问题,那你又要边做新需求边处理这些历史包袱。

其次是在产品的帮助下,口遁掉了一个新需求。本来我都排好时间准备去开发新需求了,但是今天跟产品讨论过后,发现其实不用开发新功能,让用户使用系统的现有功能也能满足需求(就是对用户来说稍微麻烦一点),于是我就省事儿了。因为最近产品同事也很忙,所以现在产品和我终于站到了同一艘船上,轻松了很多~

于是,我今天也终于有空去落实一下我之前想到的系统优化方案了,花了几个小时,把几个接口的平均响应时间缩短了 2 - 4 倍。这里简单分享几种我用到的后端接口的优化方式:

  1. 减少重复的数据库查询。比如接口处理过程中调用了方法 A 和方法 B,在方法 A 中已经查出用户 1 了,那么在方法 B 中就不用再查一遍用户 1,而是可以把已经查询出的用户 1 作为参数传递给方法 B,或者在 ThreadLocal 中临时缓存一下。
  2. 并发处理。比如有 2 个数据库查询 A 和 B,分别耗时 3 秒。如果同步执行,先查完 A 再查 B,要花 6 秒;但如果让两个查询并发执行,3 秒钟就能处理完。
  3. 非核心操作异步化。比如接口处理结束前需要往数据库中插入一条操作记录,这个步骤是非核心操作(少了这步会影响系统使用),因此可以开一个子线程异步执行(或者用消息队列等中间件实现异步),不用等待它结束就能立即响应了。
  4. 减少数据量。无论是最后返回给前端的数据、还是对缓存进行读写的数据,一般都是越小越好,可以减少网络传输、数据处理的耗时。举个例子,原本我是用 JDK 自带的序列化库来对从数据库中查询出的数据进行序列化、并塞到缓存中,数据大小大概 5 M,700 ms 左右读写完成;但今天我尝试用专业的、开源的序列化库 Kryo 来替换掉 JDK 的序列化库,Kryo 的性能更高、数据压缩能力更强,实测同样的数据条数大概只用了 2 M 多的空间(缩小了 1 倍多),并且只用了 200 多 ms 就读写完成了。但是要注意替换序列化库后,要把原本缓存中的老序列化数据清理掉,否则会冲突。
  5. 合并查询。比如要查询 id 为 1、2、3 的用户,你可以执行 3 次根据 id 查询用户,但这样查询时间会随着要查询的 id 数线性增长;所以可以直接合并为批量查询:id in (1, 2, 3),可以减少对数据库的请求次数,减少全表扫描的次数等,更快地查出数据。

有的时候,就是一些简单的操作和想法,就能提高应用的性能,大家也可以用上面提到的这些方法去优化自己的后端程序(前端也可以借鉴,比如合并请求),简历上能写的内容这不就来了么~

这两天加入星球的小伙伴比较多,写完今天的打工日记也快 1 点了,大家晚安,继续加油!

加入星球

更多内容加入星球可见,目前鱼皮的打工日记将在每个工作日持续更新~

👉🏻 点此加入星球

微信扫码领券加入