2020年上半年,差点全栈与重新开始爆肝| 掘金征文

简短回顾

2019年末到2020年年中,算是活了20多年来,境况最差的一段时间了,这里的差是指大环境(经济、实业,就业等等)。广州珠江新城花城汇恰饭和逛街的人少了很多,不少区的餐馆倒闭了,甚至找不到下一个接盘的商家,就闲置在那里。所以大概明白了为什么面试或者贩卖焦虑类型的文章会在很多知识分享平台火起来,因为大家都很焦虑,大家都想突围,我也是焦虑众人之一。

2019年底我离开了自2016年以实习生加入的某广州某科技金融公司,去了一家小的创业公司担任架构和打杂工程师。如果是同一个领域的伙伴就知道,当时圈内很多巨头都暴雷了,考虑到风险、可持续发展性以及刚好遇到赏识我的前Boss出来创业,我很短时间内做完了交接工作就到另一个全新的领域上岗。没想到的是刚入职不久,新冠肺炎就爆发了,接下来遭遇到业务收缩、远程办公(一个月)等等。回想起来,这半年时间过得比较快,大概是因为远程办公和996占比比较高。

直男手抖拍照

Life

品城记探店之鹭江滨江东路丘大6仔记餐厅

前提

有时候做事就是心血来潮想去做一件事,然后就行动了。

端午假期一天突然觉得太无聊,中午睡醒(已经是下午2点)没什么食欲,突然想起之前品城记的某一期提到的丘大6仔记餐厅,加上本来就比较喜欢港式茶餐厅或者粤式早茶,于是起床洗漱上地铁出发。看了一下大致行程要1个多小时(文冲-> 鹭江,出了地铁口还要走一公里),于是在地铁上看了一下大众点评里面的菜品推荐。

Life

冷饭新炒:理解Snowflake算法的实现原理

前提

Snowflake(雪花)是Twitter开源的高性能ID生成算法(服务)。

上图是SnowflakeGithub仓库,master分支中的REAEMDE文件中提示:初始版本于2010年发布,基于Apache Thrift,早于Finagle(这里的FinagleTwitter上用于RPC服务的构建模块)发布,而Twitter内部使用的Snowflake是一个完全重写的程序,在很大程度上依靠Twitter上的现有基础架构来运行。

2010年发布的初版Snowflake源码是使用Scala语言编写的,归档于scala_28分支。换言之,大家目前使用的Snowflake算法原版或者改良版已经是十年前(当前是2020年)的产物,不得不说这个算法确实比较厉害scala_28分支中有介绍该算法的动机和要求,这里简单摘录一下:

动机:

  • Cassandra中没有生成顺序ID的工具,Twitter由使用MySQL转向使用Cassandra的时候需要一种新的方式来生成ID(印证了架构不是设计出来,而是基于业务场景迭代出来)。

要求:

  • 高性能:每秒每个进程至少产生10KID,加上网络延迟响应速度要在2ms内。
  • 顺序性:具备按照时间的自增趋势,可以直接排序。
  • 紧凑性:保持生成的ID的长度在64 bit或更短。
  • 高可用:ID生成方案需要和存储服务一样高可用。

下面就Snowflake的源码分析一下他的实现原理。

Canal v1.1.4版本避坑指南

前提

在忍耐了很久之后,忍不住爆发了,在掘金发了条沸点(下班时发的):

这是一个令人悲伤的故事,这条情感爆发的沸点好像被屏蔽了,另外小水渠(Canal意为水道、管道)上线一段时间,不出坑的时候风平浪静,一旦出坑令人想屎。重点吐槽几点:

  • 目前最新的RELEASE版本为v1.1.4,发布于2019-9-2,快一年没更新了。
  • Issue里面堆积了十分多未处理或者没有回应的问题,有不少问题的年纪比较大。
  • master分支经常提交异常的代码,构建不友好,因为v1.1.4比较多问题,也曾经想过用master代码手动构建,导入项目之后决定放弃,谁试试谁知道,可以尝试对比导入和构建MyBatis的源码。

这些都只是表象,下面聊聊踩过的坑。

MyBatis版本升级导致OffsetDateTime入参解析异常问题复盘

背景

最近有一个数据统计服务需要升级SpringBoot的版本,由1.5.x.RELEASE直接升级到2.3.0.RELEASE,考虑到没有用到SpringBoot的内建SPI,升级过程算是顺利。但是出于代码洁癖和版本洁癖,看到项目中依赖的MyBatis的版本是3.4.5,相比当时的最新版本3.5.5大有落后,于是顺便把它升级到3.5.5。升级完毕之后,执行所有现存的集成测试,发现有部分OffsetDateTime类型入参的查询方法出现异常,于是进行源码层面的DEBUG找到最终的问题并且解决。

Java线程生命周期与状态切换

前提

最近有点懒散,没什么比较有深度的产出。刚好想重新研读一下JUC线程池的源码实现,在此之前先深入了解一下Java中的线程实现,包括线程的生命周期、状态切换以及线程的上下文切换等等。编写本文的时候,使用的JDK版本是11。

通过Nginx、Consul、Upsync实现动态负载均衡和服务平滑发布

前提

前段时间顺利地把整个服务集群和中间件全部从UCloud迁移到阿里云,笔者担任了架构和半个运维的角色。这里详细记录一下通过NginxConsulUpsync实现动态负载均衡和服务平滑发布的核心知识点和操作步骤,整个体系已经在生产环境中平稳运行。编写本文使用的虚拟机系统为CentOS7.x,虚拟机的内网IP192.168.56.200

深入理解Java的动态编译

前提

笔者很久之前就有个想法:参考现有的主流ORM框架的设计,造一个ORM轮子,在基本不改变使用体验的前提下把框架依赖的大量的反射设计去掉,这些反射API构筑的组件使用动态编译加载的实例去替代,从而可以得到接近于直接使用原生JDBC的性能。于是带着这样的想法,深入学习Java的动态编译。编写本文的时候使用的是JDK11

Java

SonarQube搭建手记

前提

这篇文章记录的是SonarQube服务搭建的详细过程,应用于云迁移后的PipleLine的代码扫描环节。

笔者有软件版本升级强迫症,一般喜欢使用软件的最新版本,编写此文的时候(2020-05-17SonarQube的最新版本为8.3.1

通过transmittable-thread-local源码理解线程池线程本地变量传递的原理

前提

最近一两个月花了很大的功夫做UCloud服务和中间件迁移到阿里云的工作,没什么空闲时间撸文。想起很早之前写过ThreadLocal的源码分析相关文章,里面提到了ThreadLocal存在一个不能向预先创建的线程中进行变量传递的局限性,刚好有一位HSBC的技术大牛前同事提到了团队引入了transmittable-thread-local解决了此问题。借着这个契机,顺便clonetransmittable-thread-local源码进行分析,这篇文章会把ThreadLocalInheritableThreadLocal的局限性分析完毕,并且从一些基本原理以及设计模式的运用分析transmittable-thread-local(下文简称为TTL)整套框架的实现。

如果对线程池和ThreadLocal不熟悉的话,可以先参看一下前置文章:

这篇文章前后花了两周时间编写,行文比价干硬,文字比较多(接近5W字),希望带着耐心阅读。