在上一篇文章中,通过阅读 《In Search of an Understandable Consensus Algorithm》 前三节的内容,对论文的大致内容做了简介,简单说明了一下 Replicated state machines 的用途以及 Paxos 本身存在的问题。
4. Designing for understandability several goals in designing Raft:
it must providea complete and practical foundation for system building;
it must be safe under all conditions and available under typical operating conditions;
it must be efficient for common operations.
Our most important goal — and most difficult challenge — was understandability.
从这里可以看出,Raft 设计的初衷就是为了易于理解和便于构建。
There were numerous points in the design of Raft where we had to choose among alternative approaches. In these situations we evaluated the alternatives based on understandability.
前一段时间,在一次开组会的时候,给小组成员简单介绍了一下 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 选举,日志复制,以及安全性等;同时,为了降低需要考虑的状态的数量,还强制实施了更强的一致性。
1. Introduction Consensus algorithms allow a collection of machines to work as a coherent group that can survive the failures of some of its members.
在前面的文章 HikariCP 源码分析 — ConcurrentBag 中,D瓜哥分析了一下 HikariCP 中一个非常重要的数据结构 ConcurrentBag。
今天,继续再介绍 HikariCP 中另一个很关键的数据结构: FastList。
FastList 本身的实现非常简单,要理解它的奥秘,就需要结合 Java 原生集合类的 ArrayList 来比较性地看。
构造函数 先来对比一下两者的构造函数。先来看看 FastList:
FastList public final class FastList<T> implements List<T>, RandomAccess, Serializable { private static final long serialVersionUID = -4598088075242913858L; private final Class<?> clazz; private T[] elementData; private int size; /** * Construct a FastList with a default size of 32. * @param clazz the Class stored in the collection */ @SuppressWarnings("unchecked") public FastList(Class<?> clazz) { this.elementData = (T[]) Array.newInstance(clazz, 32); this.clazz = clazz; } /** * Construct a FastList with a specified size. * @param clazz the Class stored in the collection * @param capacity the initial size of the FastList */ @SuppressWarnings("unchecked") public FastList(Class<?> clazz, int capacity) { this.elementData = (T[]) Array.newInstance(clazz, capacity); this.clazz = clazz; }
以前无意间搜资料了解到 HikariCP,一下子就被它的简洁代码和卓越性能吸引住了。以前也有翻过它的代码,但是不是很系统,最近再次翻阅,正好做些笔记,方便以后学习。
D瓜哥最近在学习 Java 并发知识。那就从 HikariCP 自定义的并发集合 ConcurrentBag 开始学习。
在 HikariCP 的 Wiki 中,有 Down the Rabbit Hole · ConcurrentBag 的章节来专门介绍 ConcurrentBag:
ConcurrentBag 的灵感借鉴自 C# .NET 的 ConcurrentBag 类。但是实现却是完全不同的。这里的 ConcurrentBag 有如下特性:
A lock-free design
ThreadLocal caching
Queue-stealing
Direct hand-off optimizations
下面,通过代码来对此做个说明。
在 ConcurrentBag 类的定义中,声明了集合元素必须是 IConcurrentBagEntry 的子类。先来看看这个接口的定义:
public interface IConcurrentBagEntry { int STATE_NOT_IN_USE = 0; int STATE_IN_USE = 1; int STATE_REMOVED = -1; int STATE_RESERVED = -2; boolean compareAndSet(int expectState, int newState); void setState(int newState); int getState(); } 接下来,看一下成员变量:
// 存放共享元素 private final CopyOnWriteArrayList<T> sharedList; private final boolean weakThreadLocals; // 在 ThreadLocal 缓存线程本地元素,避免线程争用 private final ThreadLocal<List<Object>> threadList; private final IBagStateListener listener; // private final AtomicInteger waiters; private volatile boolean closed; // 接力队列 private final SynchronousQueue<T> handoffQueue; 在 ConcurrentBag 开头的 JavaDoc 中就做了明确说明:
Note that items that are "borrowed" from the bag are not actually removed from any collection, so garbage collection will not occur even if the reference is abandoned. Thus care must be taken to "requite" borrowed objects otherwise a memory leak will result. Only the "remove" method can completely remove an object from the bag.
曾经写给学弟学妹的一封信。我觉得还行,发出来,希望对刚学计算机专业的朋友有所帮助。当然,如果哪位朋友有更好的想法,也请留言,大家讨论讨论。原文如下:
致师弟师妹的一封信 各位朋友:
大家好!
从本周开始,我必须专心为我的前程奋斗了。很可惜不能和大家一起学习了。这封信就算是我和大家的一个告别吧。
首先,感谢史老师给我提供这个和大家一起学习和交流的机会,让我和大家一起度过了一段特殊而愉快的时光。
其次,我应该感谢大家。由于本人水平有限,也许我没能让大家从我这里学到太多知识,但是大家却让我学会了很多东西,锻炼了我很多方面的能力。单凭这一点,我就应该感谢大家。同时,很多人把我当朋友,更使我感激不尽。
再次,在这短暂而又宝贵的大学时光里,大家走的路应该和我的基本一样。我以一个过来人的身份,和大家分享一下我的学习经验吧,希望可以让大家少走甚至不走弯路。
先说一点我们所学科目的情况吧。
Linux:一定要动手敲指令。在我们一年半的学习时光里,我认为Linux是我们所学的所有实践性学科里面最简单的一科了!只要把指令记好用熟就行了!另外,指令不需要背,用多了自然就记住了。(相信95%的同学都知道cd是什么意思吧!为什么呢?因为用它的次数多!)多提一点,一定要多尝试!
Java或者C#或者PHP(由于个人比较喜欢Java,所以,一下描述Java的地方,你可以同样换成C#或在PHP等):这是我们大家必须要下苦功夫学好的课!而且一定一定要学精!它们在我们的课程体系结构中的作用,就像是地基对于这个房子的作用!根基不好,房子很难建高的!即使建好也是豆腐渣工程。毕竟“空中楼阁”只存在于我们的想象中。它们是学习JSP、ASP.NET、J2EE、“游戏开发”、网页开发等等的基础,Java或者C#或者PHP学不会,这些课很难学好!(我这里有Java的教学视频,感兴趣的同学可以来我寝室拷贝。也可以上网下载:http://www.verycd.com/topics/93279/(请下载J2SE的))
数据库:重点是关系模型、 SQL语句以及后面的数据库设计。做动态网站的技术、做桌面程序,甚至做手机应用等,都会用到数据库!以后工作中数据模型设计、数据查询等都要求有比较扎实的数据库基础才行。
数据结构:我个人认为学习数据结构就是学习一种解决问题的思想。其实,类库已经实现了我们所学的所有的数据结构,到时会用就行了!
现在NBA正在进行季后赛,就用乔丹的一句话,作为所有学科的一个共同的建议送给大家:
I can accept failure, but I can’t accept not trying.
— Michael Jordan 其实学习就是不断尝试,不断总结,不断进取的一个过程。我可以用我的尝试告你一个正确的结果,但是自己尝试出来的结果印象更加深刻!
再说一点我的个人的学习感触吧。我个人认为,这些比我们大家在学校学到知识更为重要!知识马上就会过时,但是学习的方法却可以带领我们走的更远。
一、享受学习。如果我们把学习当成像玩游戏、听音乐一样的娱乐活动时,我想这会给我们一种全新的感觉。Study hard,have fun,make history! By Jeff Bezos & Joy Lee (努力学习,乐在其中,并创造历史!—Jeff Bezos(Amazon.com的创办者兼CEO,Joy Lee就是我。(*__*) 嘻嘻…… 这句话是我从他的一句话里改编过来的!))
其实,学计算机学科非常有趣!Linux里面,几行指令,我们就可以顺利的让鼠标在两个操作系统自由转换!Java里面几行,几十行代码就有一个漂亮的窗口!C#里面随便一个拖拽,也是一个不错的窗口!“只要一部计算机,就可以创造出无限的世界。”(出自蔡学镛《写程序,好好玩》,《Java夜未眠》里面的一篇,本书是本很搞笑的编程感触散文集,推荐看看。)加油吧!相信你行!
二、坚持不懈。任何事情都不是可以一蹴而就的,都需要我们坚持!再送给大家一句话:失败只有一种,那就是半途而废!
三、舍我其谁的豪迈和霸气。“Horse’s,Gosling能创造出来Java,我就不信我学不会!一个破Java,我还不放到眼里呢!!”,“别人能创造出来,我就不相信我学不会?!”不过,也要给大家提醒一句:“战略上,藐视敌人;战术上,重视敌人”!一定要下功夫学习才行!
四、信心。一定要相信自己的能力!你是独一无二,无可替代的!信心能让你从一个更高的角度看待你的学习!能给你一种驾驭知识的成就感!这种感觉能让你从学习中找到乐趣!
五、行动!上面的大道理,我们大家都懂!但是,谁实际做到呢?伟大与平凡的区别也许就在于这一点吧。我以我自己的高中、大学对比来看,行动与否结果绝对是不一样的!只想不做,最多是个空想家!所以,大家一定要“坚持不懈的行动”!
最后,送给大家一句话:你充满了潜能,但你的努力还远远不够!再次怀念我们共同的学习时光!
祝大家学有所成!
D瓜哥