Raft 论文摘要(一)

Raft 论文摘要(一)

D瓜哥
前一段时间,在一次开组会的时候,给小组成员简单介绍了一下 Raft 协议。大概四年前读过 Raft 的论文,这次分享的时候,好多好多细节都忘了。所以,再次把 《In Search of an Understandable Consensus Algorithm》 这篇论文找出来,重读一遍,做个笔记和摘要,方便后续学习和复习。 Abstract Raft is a consensus algorithm for managing a replicated log. 开篇摘要就点出了 Raft 的特点: Raft 是一种管理复制日志的共识算法。 In order to enhance understandability, Raft separates the key elements of consensus, such as leader election, log replication, and safety, and it enforcesa stronger degree of coherency to reduce the number of states that must be considered. 为了增强可理解性,Raft 将共识分解成几个关键元素,例如 Leader 选举,日志复制,以及安全性等;同时,为了降低需要考虑的状态的数量,还强制实施了更强的一致性。
从 Spring PR 中学习代码技巧

从 Spring PR 中学习代码技巧

D瓜哥
D瓜哥经常关注 Spring 的 PR 与 Issue。在众多 Contributor 中,除了 Spring 团队成员之外,我对 stsypanov (Сергей Цыпанов) 印象很深刻。这哥们给 Spring 提了非常多的 PR,请看列表 Pull requests · spring-projects/spring-framework,而且这个哥们的 PR 都非常有特点,绝大部分是性能提升方面的 PR,而且还会给出 JMH 的测试结果。不愧是毛熊人,做事细致严谨。 这周心血来潮,把这哥们的 PR 翻一翻,希望可以学习一些编码技巧。简单记录一下,以备以后回顾学习。 提高 Map 的遍历性能 请看: SPR-17074 Replace iteration over Map::keySet with Map::entrySet by stsypanov · Pull Request #1891 摘取一个示例如下: // --before update------------------------------------------------------ for (String attributeName : attributes.keySet()) { Object value = attributes.get(attributeName); // --after update------------------------------------------------------- for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) { String attributeName = attributeEntry.
在七夕“摘”情诗

在七夕“摘”情诗

D瓜哥
今天七夕情人节,选摘几首情诗做个纪念。 邶风 · 静女 静女其姝,俟我于城隅。爱而不见,搔首踟蹰。 静女其娈,贻我彤管。彤管有炜,说怿女美。 自牧归荑,洵美且异。匪女之为美,美人之贻。 郑风 · 子衿 青青子衿,悠悠我心。纵我不往,子宁不嗣音? 青青子佩,悠悠我思。纵我不往,子宁不来? 挑兮达兮,在城阙兮。一日不见,如三月兮! 舒婷 · 致橡树 我如果爱你—— 绝不像攀援的凌霄花, 借你的高枝炫耀自己; 我如果爱你—— 绝不学痴情的鸟儿, 为绿荫重复单调的歌曲; 也不止像泉源, 常年送来清凉的慰藉; 也不止像险峰, 增加你的高度,衬托你的威仪。 甚至日光。 甚至春雨。 不,这些都还不够! 我必须是你近旁的一株木棉, 作为树的形像和你站在一起。 根,紧握在地下, 叶,相触在云里。 每一阵风过, 我们都互相致意, 但没有人, 听懂我们的言语。 你有你的铜枝铁干, 像刀,像剑, 也像戟; 我有我红硕的花朵, 像沉重的叹息, 又像英勇的火炬。 我们分担寒潮、风雷、霹雳; 我们共享雾霭、流岚、虹霓。 仿佛永远分离, 却又终身相依。 这才是伟大的爱情, 坚贞就在这里: 爱—— 不仅爱你伟岸的身躯, 也爱你坚持的位置,足下的土地。 在 告别 2019,迎接 2020 中已经展示过这张照片了。但是,没有多做说明。这里就简要介绍一下。 2019 年端午自驾游时,在内蒙古的一座山上,无意间看到了上面照片中的这两棵树,形象神似《致橡树》中“站在一起的两棵树”。所以,就专门拍下了这张照片留作纪念。 席慕蓉 · 一棵开花的树 如何让你遇见我 在我最美丽的时刻为这 我已在佛前求了五百年 求它让我们结一段尘缘 佛于是把我化作一棵树 长在你必经的路旁 阳光下慎重地开满了花 朵朵都是我前世的盼望
《远见》之读书笔记

《远见》之读书笔记

D瓜哥
最近向一个朋友了解一家公司情况时,聊到职业发展的问题。就随手推荐了《远见:如何规划职业生涯3大阶段》这本书。正好利用这个机会,把以前的读书摘要发布出来。 这本书,D瓜哥在 告别 2019,迎接 2020:《远见》 中也提到过。这里把当时写的读书笔记直接拷贝过来: 本书讲人生的职业生涯分为三个阶段: 第一阶段是强势开局的时候。你在职业上的努力必须着重于为前方的漫长道路挖掘和装备自己。你的学习曲线要比职位、职称更加重要。在这一阶段,要为职业生涯打好基础并建立起良好的早期习惯。 第二阶段是聚焦长板的时候。该阶段的首要目标是寻找自己的甜蜜区,即你所擅长的、所热爱的和这个世界所需要的这三者之间的交集。这个时候你要展现自我,让自己鹤立鸡群,想方设法平稳地走在那条收获最大的职场路径上。你要专注于自己的长板,且大可忽略自己的短板。 第三阶段致力于实现持续的影响力,以及寻找一条可以稳定延续到60多岁甚至70多岁的新的可持续职业道路。你要在第三阶段完成三个关键任务:完成继任计划、保持关联性,以及为自己点燃一团新的职业之火。 用一句话来总结:第一阶段:加添燃料,强势开局; 第二阶段:聚焦长板,达到高点; 第三阶段:优化长尾,持续发挥影响力。 三大职场燃料来源:可迁移技能、有意义的经验和持久的关系。 5个数字,树立正确的职场思维 职业生涯的长度:用62减去你目前的年龄。 精通一项技能所需的时间:要花多少小时才能在某一方面达到“精通”? 40岁之后能赚到的个人财富百分比:在40岁之后,你赚到的钱会占你一生个人财富的百分之多少?大部分人的估计是60%。 社交货币:你有多少社交网络好友? 职场支持者的人数:你认为能在“职业生涯的天堂”里遇到多少人,也就是说有多少人能对你的职业生涯和人生带来真正的变化? 这本书强烈推荐给对未来职业有追求的小伙伴! 好戏开始,下面👇是读书摘要: PART 1 远见思维与工具箱 远见思维:多行动,少忧虑 职业生涯的持续时间长得惊人,包括了三个截然不同的阶段。 第一阶段是强势开局的时候。你在职业上的努力必须着重于为前方的漫长道路挖掘和装备自己。你的学习曲线要比职位、职称更加重要。 第二阶段是聚焦长板的时候。该阶段的首要目标是寻找自己的甜蜜区,即你所擅长的、所热爱的和这个世界所需要的这三者之间的交集。 第三阶段致力于实现持续的影响力,以及寻找一条可以稳定延续到 60多岁甚至 70多岁的新的可持续职业道路。 职场燃料很重要,因为职业生涯的基础决定结果。 这种燃料有三个主要来源:可迁移技能、有意义的经验和持久的关系。 职业生涯需要通过对时间的巧妙投资来构建。 职业生涯并不是以线性或者可预测的方式发展的。 职业生涯远不止于一份工作,而是生活的一大部分。 实现职业规划要做到的5件事 学习职场数学,树立正确的长期思维方式。 盘点职场清单,梳理你最有用处的技能、经验和关系。 进行“ 100小时测试”并完成一份“个人时间档案”,从而了解你目前的时间投资状况。 在尝试建立新的职场路径或者在多个选项中抉择时,运用“职场路径向导”( Career Path Navigator)。 时刻更新你的职业生涯 我如何避免被机器取代? 我能在哪里以什么方式找到工作? 未来我将如何分配时间? 我会把钱花光吗? 工作如何能让我更幸福? 三大阶段,聚焦 45 年职业生涯 第一阶段:加添燃料,强势开局; 第二阶段:聚焦长板,达到高点; 第三阶段:优化长尾,持续发挥影响力。 第一阶段:加添燃料,强势开局 职业生涯前 15年的唯一目标就是为接下来的两个阶段打好基础。 第一阶段是探索和弥补自身短板的时候。如果你是个糟糕的演讲者,那就去参加相关的培训课程。如果你对待团队成员过于强势或弱势,那就去参加领导力培训。学习要比纯粹的成功更重要。有时跌倒并不可怕,只要你能吸取教训,并将这些经验加以利用就行。 第二阶段:锚点甜蜜区,聚焦长板 第二阶段是在你的长板、你的爱好以及这个世界的需求之间寻找交集的时候。 坦率地承认自己的短板,针对它们招募盟友,你就可以把大多数时间放在核心长板上了。 第三阶段:优化长尾,持续发挥影响力 第三阶段的主要目的是确定接班人,即给继任计划画上完美的句号,从执行或领导的角色转变成顾问或辅助的角色。 保持关联性是你在第三阶段的工作之一。 储备三大职场燃料 你的领导力是由你的学习意愿助燃前行的。
Spring AOP 源码分析:创建代理(二)

Spring AOP 源码分析:创建代理(二)

D瓜哥
Spring AOP 源码分析:入门 中,梳理出来了 Spring AOP 的入口。 Spring AOP 源码分析:获得通知 中着重介绍了如何获取通知。上一篇文章 Spring AOP 源码分析:创建代理(一) 重点介绍了一下切面链的组装和基于 JDK 动态代理的 AOP 的实现,这篇文章介绍一下基于 cglib 的代理类是生成。 cglib 简介 CGLIB(Code Generator Library)是一个高性能的代码生成库,被广泛应用于 AOP 框架(Spring)中以提供方法拦截功能,主要以继承目标类的方式来进行拦截实现,因此 CGLIB 可以对无接口的类进行代理。 CGLIB代理主要通过操作字节码的方式为对象引入方法调用时访问操作,底层使用了ASM来操作字节码生成新的类,ASM是一个短小精悍的字节码操作框架。CGLIB的应用栈如下: 最新版的 Hibernate 已经把字节码库从 cglib 切换为 Byte Buddy。 JDK 动态代理是通过实现 InvocationHandler 接口,在其 invoke 方法中添加切面逻辑。而 cglib 则是通过实现 MethodInterceptor 接口,在其 invoke 方法中添加切面逻辑。 下面看一下在 Spring 中,是如何实现利用 cglib 来实现 AOP 编程的? CglibAopProxy 先看一下创建代理对象的方法: CglibAopProxy#getProxy(ClassLoader) @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.
Spring AOP 源码分析:创建代理(一)

Spring AOP 源码分析:创建代理(一)

D瓜哥
Spring AOP 源码分析:入门 中,梳理出来了 Spring AOP 的入口。上一篇文章 Spring AOP 源码分析:获得通知 中着重介绍了如何获取通知。接着上一篇文章,这篇文章介绍一下如何创建代理。 AbstractAutoProxyCreator#createProxy protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 创建代理工厂对象 ProxyFactory proxyFactory = new ProxyFactory(); // 获取当前类的属性 proxyFactory.copyFrom(this); //如果没有使用CGLib代理 if (!proxyFactory.isProxyTargetClass()) { // 是否可能使用CGLib代理 // 决定对于给定的 Bean 是否应该使用 targetClass 而不是他的接口代理 if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 查看beanClass对应的类是否含有InitializingBean.class/DisposableBean.class/Aware.class接口 // 无则采用JDK动态代理,有则采用CGLib动态代理 evaluateProxyInterfaces(beanClass, proxyFactory); } } // 获得所有关联的Advisor集合(该分支待补充) Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.
Spring AOP 源码分析:获得通知

Spring AOP 源码分析:获得通知

D瓜哥
在文章 Spring AOP 处理流程概述 中,对 Spring AOP 有了一个整体认识。在文章 Spring AOP 源码分析:入门 中,对 Spring AOP 的相关入口做了分析。这篇文章就带大家看一看,Spring AOP 是如何获取通知的? 示例代码 在 如何阅读 Spring 源码?: 示例代码 中,已经给出了一个完整的 AOP 示例代码。为了节省篇幅,请直接参考那篇文章的示例代码,这里就不在赘述。 注册 Advice(通知/增强) 请根据 Spring AOP 源码分析:入门 中提到的关键方法入口处,打上断点,开始调试。 首先,需要明确一点的是:对于切面(使用 @Aspect 注解标注过的类)在 Spring 容器中,也是被统一f封装为 BeanDefinition 实例的,也需要通过一个方式,将其注册到 Spring 容器中。比如,就像 示例代码 那样,通过 ImportSelector 方式,使用类名,将其注册到容器中。这样,就可以利用 Spring 容器对 Bean 的 API 来统一处理了。 Advice(通知/增强)几乎是在意想不到的地方完成注册的:在第一次调用 AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法时,通过 AspectJAwareAdvisorAutoProxyCreator#shouldSkip 方法,完成了切面的注册。下面,我们对这个过程抽丝剥茧,逐步分析。 先来看看 findCandidateAdvisors 方法: AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors @Override protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules.
如何阅读 Spring 源码?

如何阅读 Spring 源码?

D瓜哥
昨晚原计划给几个朋友简单介绍一下阅读 Spring 源码的方法。结果,大家因为各种原因没能及时参加。后来,就取消分享了。干脆写一篇文章出来,感兴趣欢迎自取。 代码准备 Spring Framework 是开源的,代码托管在 GitHub 上: Spring Framework。任何人都可以方便地获得它的源代码。所以,如果想阅读 Spring 的源代码,当然是直接把代码克隆到本地,然后直接在 IDE(推荐 IDEA)中进行调试了。另外,还需要存放自己写一些测试和文档。所以,最好把代码 fork 到自己的账户下,从 master 上切出一个新分支并 push 到自己的 Repo 中,这样自己就可以随意更新了。具体步骤如下: 克隆代码 # 直接克隆原始仓库为 origin git clone git@github.com:spring-projects/spring-framework.git fork 代码,D瓜哥直接 fork 到自己账户下了: diguage/spring-framework。 添加原创仓库地址: # 添加自己仓库为 diguage # 这样就能在所有项目中保持命名的一致性,方便标识 git remote add diguage git@github.com:diguage/spring-framework.git 创建新分支 # 创建新分支 git switch -c analysis # 将新分支 push 到自己的 Repo 中 git push diguage analysis 这样,在这个新分支上,就可以随意折腾了。 下载依赖 # Mac or Linux .
Spring AOP 源码分析:入门

Spring AOP 源码分析:入门

D瓜哥
在上一篇文章 Spring AOP 处理流程概述 中,对 Spring AOP 有了一个整体认识。这篇文章就带大家做一个细致的源码分析。 登堂入室 使用 Spring AOP 也很简单,只需要在配置类上加上 @EnableAspectJAutoProxy 注解即可。这个注解处理过程与 Spring 扩展点实践:整合 MyBATIS 中 “@MapperScan 处理” 类似,不同的是,Spring AOP 注册了 AnnotationAwareAspectJAutoProxyCreator,它是一个 InstantiationAwareBeanPostProcessor。具体的类图如下: Figure 1. AnnotationAwareAspectJAutoProxyCreator 的继承体系 在正式开始源码分析之前,有一点必须强调一下:Spring AOP 只是借用了 AspectJ 的一些注解和个别关键 API,而整体实现是 Spring 自己完成的,并不是基于 AspectJ 实现的。这一点跟很多人的认识是不一样的,需要特别指出。 D瓜哥在 Spring Bean 生命周期概述 中指出:创建 AOP 代理对象,有两个时机: 调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 时,通过调用 AnnotationAwareAspectJAutoProxyCreator 对象的 postProcessBeforeInstantiation 方法来创建对象; 调用 BeanPostProcessor#postProcessAfterInitialization 时,通过调用 AnnotationAwareAspectJAutoProxyCreator 对象的 postProcessAfterInitialization 方法来创建对象; 下面分别对这两个方法做更详细的介绍。 AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation AnnotationAwareAspectJAutoProxyCreator 的 postProcessBeforeInstantiation 方法是从 AbstractAutoProxyCreator 继承过来的。代码如下:
TCP 三次握手和四次挥手

TCP 三次握手和四次挥手

D瓜哥
传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC 793 定义。在简化的计算机网络 OSI 模型中,它完成第四层传输层所指定的功能。 毫不夸张地说,TCP 协议是目前整个互联网的基础。它解决了一系列的网络问题。带来的结果,就是协议本身非常复杂。考虑到文章篇幅问题,本文着重说明 TCP 建立连接时的三次握手过程和关闭连接时的四次挥手过程。 三次握手 Figure 1. TCP 三次握手 第一次握手(SYN=1, seq=x): 客户端发送一个 TCP 的 SYN 标志位置 1 的包,指明客户端打算连接的服务器的端口,以及初始序号 x,保存在包头的序列号(Sequence Number)字段里。 发送完毕后,客户端进入 SYN_SEND 状态。 第二次握手(SYN=1、seq=y;ACK=1、ACKnum=x+1): 服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为 1。服务器端选择自己 ISN 序列号,放到包头的序列号(Sequence Number)字段里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加 1,即 x+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。 第三次握手(ACK=1,ACKnum=y+1) 客户端再次发送确认包(ACK),SYN 标志位为 0,ACK 标志位为 1,并且把服务器发来 ISN 的序号字段+1,放在确定字段中发送给对方,即数据段放写 y+1。 发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。 SYN Flood 攻击 在三次握手过程中,服务器发送 SYN-ACK 之后,收到客户端的 ACK 之前的 TCP 连接称为半连接(half-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK 后,服务器才能转入 ESTABLISHED 状态.