cassandra读源码---Streaming
前言
cassandra的很多过程需要网络传输模块,需要在各个节点直接发送文件。包括加入节点,删除节点引起的不同节点的负责ring环的key值发生了变化,导致sstable需要在各个节点中移动。
整体过程
两个节点会创建一个相似的对称的StreamSession。主要是下面四个阶段。一个stream会话包含了多个文件,每个节点既有发送task,也会有接收task.涉及到的可参看的java知识有
1. 如何进行数据文件的串行化,使得在网络中传输。然后反串行化,重新写入到SSTable中
2. 一次会话中的读写需要分离吗?
3. 传输文件需要占用网络带宽,和节点的I/O资源,如何控制stream的速率?
4. 一次会话中包含多个文件的传输,某个文件失败了,如果处理?
5. 多个table之间的streaming应该是分离的,这之间如何管理
详细解释
1. 连接初始化
a. 节点会创建一个新的StreamSesssion。init,然后start。会创建一个ConnectionHandler,去创建两个connections,一个incoming,一个outgoing。
然后发送一条StreamInit 消息。
/**
* Bind this session to report to specific {@link StreamResultFuture} and
* perform pre-streaming initialization.
*
* @param streamResult result to report to
*/
public void init(StreamResultFuture streamResult)
{
this.streamResult = streamResult;
StreamHook.instance.reportStreamFuture(this, streamResult);
}
public void start()
{
if (requests.isEmpty() && transfers.isEmpty())
{
logger.info("[Stream #{}] Session does not have any tasks.", planId());
closeSession(State.COMPLETE);
return;
}
try
{
logger.info("[Stream #{}] Starting streaming to {}{}", planId(),
peer,
peer.equals(connecting) ? "" : " through " + connecting);
handler.initiate();
onInitializationComplete();
}
catch (Exception e)
{
JVMStabilityInspector.inspectThrowable(e);
onError(e);
}
}
(b)一旦收到了StreamInit message,follower就会创建自己的StreamSession,如果不存在的的话就创建,
然后将它附到自己的ConnectionHandler的socket。
(c)当incoming和outgoing connections都建立起来了,StreamSession 调用onInitializationComplete 方法去
进行下一个阶段。Streaming 准备阶段。
2. Streaming 准备阶段
(a)当调用onInitializatioinComplete()方法时,这个方法发送一个PrepareMessage包含将要发送的文件/sections,
(包装在StreamTransferTask,每个cf分离的)以及需要对方返回的task。如果没有从对方那边收到任何东西,就直接进入Streaming 阶段,否则等待对方prepareMessage。
(b)一旦收到PrepareMessage,接收者会记录下将会接收到的files/sections。并返回一个摘要给发送者。发送完消息后,接收者就进入到Streaming 阶段了。
(c)当发送者收到接收者PrepareMessage,记录下接收到的files/sections。然后进入到Streaming 阶段。
/**
* Call back when connection initialization is complete to start the prepare phase.
*/
public void onInitializationComplete()
{
// send prepare message
state(State.PREPARING);
PrepareMessage prepare = new PrepareMessage();
prepare.requests.addAll(requests);
for (StreamTransferTask task : transfers.values())
prepare.summaries.add(task.getSummary());
handler.sendMessage(prepare);
// if we don't need to prepare for receiving stream, start sending files immediately
if (requests.isEmpty())
startStreamingFiles();
}
3. Streaming发送阶段
(a)这个阶段的是有每一个调用startStreamingFiles()方法的节点开启的(发送者,但是注意一个StreamSession的每一端都有可能是某些文件的发送者),然后发送一个FileMassage为每个StreamTransferTask中的每一个文件。每一条FileMessage包含一个FileMessageHeader,代表哪个文件要进来,然后开始streaming那个文件的内容。(StreamWriter 在FlieMessage.serialize())当一个文件完全被发送了,会调用那个文件的fileSent()方法。当一个StreamTransferTask所有的文件都完成了,调用StreamTransforTask.complete()。任务标记为完成。
(b)接收这端,一个SSTable会为进来的文件写SSTable(StreamReader 在FileMessage.deserialize())一旦FileMessage完全被接收了,文件会被标记为完成(received())。当所有的文件都接收了,sstables被加到了文件系统中(2nd index也已经建立了,StreamReceiveTask.complete()),任务被标记为完成(taskCompleted())
(c) 如果在某个特定的文件的streaming过程中,在接收过程中发生了I/O错误。(FileMessage.deserialize)。节点会重新retry这个文件,(retry次数取决于DatabaseDescriptor.getMaxStreamingRetries())通过发送一个RetryMessage给发送者。一旦接收到RetryMessage,发送者会为那个文件创建一个新的FileMessage
(d)当一个会话中所有的transfer和receive task都完成了,就进行到完成阶段
4. 完成阶段
当一个节点完成了所有的transfer 和receive task,就进入到了completion 阶段(maybeCompleted())。如果它已经从另外一边接收到一个CompleteMessage,这个会话就关闭了,否则这个节点切换到WAIT_COMPLETE 状态,并且发送一个CompleteMessage给另外一端。
cassandra读源码---Streaming的更多相关文章
- [一起读源码]走进C#并发队列ConcurrentQueue的内部世界
决定从这篇文章开始,开一个读源码系列,不限制平台语言或工具,任何自己感兴趣的都会写.前几天碰到一个小问题又读了一遍ConcurrentQueue的源码,那就拿C#中比较常用的并发队列Concurren ...
- Java读源码之ReentrantLock
前言 ReentrantLock 可重入锁,应该是除了 synchronized 关键字外用的最多的线程同步手段了,虽然JVM维护者疯狂优化 synchronized 使其已经拥有了很好的性能.但 R ...
- Java读源码之ReentrantLock(2)
前言 本文是 ReentrantLock 源码的第二篇,第一篇主要介绍了公平锁非公平锁正常的加锁解锁流程,虽然表达能力有限不知道有没有讲清楚,本着不太监的原则,本文填补下第一篇中挖的坑. Java读源 ...
- Java读源码之CountDownLatch
前言 相信大家都挺熟悉 CountDownLatch 的,顾名思义就是一个栅栏,其主要作用是多线程环境下,让多个线程在栅栏门口等待,所有线程到齐后,栅栏打开程序继续执行. 案例 用一个最简单的案例引出 ...
- 阅读源码很重要,以logback为例,分享一个小白都能学会的读源码方法
作为一个程序员,经常需要读一些开源项目的源码.同时呢,读源码对我们也有很多好处: 1.提升自己 阅读优秀的代码,第一可以提升我们自身的编码水平,第二可以开拓我们写代码的思路,第三还可能让我们拿到大厂 ...
- 读源码【读mybatis的源码的思路】
✿ 需要掌握的编译器知识 ★ 编译器为eclipse为例子 调试准备工作(步骤:Window -> Show View ->...): □ 打开调试断点Breakpoint: □ 打开变量 ...
- 跟大佬一起读源码:CurrentHashMap的扩容机制
并发编程——ConcurrentHashMap#transfer() 扩容逐行分析 前言 ConcurrentHashMap 是并发中的重中之重,也是最常用的数据结构,之前的文章中,我们介绍了 put ...
- 跟着大彬读源码 - Redis 1 - 启动服务,程序都干了什么?
一直很羡慕那些能读 Redis 源码的童鞋,也一直想自己解读一遍,但迫于 C 大魔王的压力,解读日期遥遥无期. 相信很多小伙伴应该也都对或曾对源码感兴趣,但一来觉得自己不会 C 语言,二来也不知从何入 ...
- 跟着大彬读源码 - Redis 3 - 服务器如何响应客户端请求?(下)
继续我们上一节的讨论.服务器启动了,客户端也发送命令了.接下来,就要到服务器"表演"的时刻了. 1 服务器处理 服务器读取到命令请求后,会进行一系列的处理. 1.1 读取命令请求 ...
随机推荐
- 理解Flexbox弹性盒子
http://www.w3cplus.com/css3/understanding-flexbox-everything-you-need-to-know.html参考文档 1:要开始使用Flexbo ...
- Java 读书笔记 (五) 目标数据类型转换
数据类型转换必须满足如下规则: 不能对boolean类型进行类型转换 不能把对象类型转换成不相关类的对象 //那不同类的对象可以用同一个名字命名吗?根据作用域原则,可以吧? 把容量大的转换为容量小的 ...
- Dubbo中服务消费者和服务提供者之间的请求和响应过程
服务提供者初始化完成之后,对外暴露Exporter.服务消费者初始化完成之后,得到的是Proxy代理,方法调用的时候就是调用代理. 服务消费者经过初始化之后,得到的是一个动态代理类,InvokerIn ...
- bzoj4904 [Ctsc2017]最长上升子序列
我们发现他让求的东西很奇怪,于是通过某D开头定理,我们转化为前m位的序列用k个不上升子序列最多能覆盖多少.数据范围小的时候可以网络流做,但是这道题显然不支持网络流的复杂度.然后有一个奇怪的东西叫杨氏矩 ...
- Java集合--TreeSet详细解析
目录 1.构造函数 2.增 3.删 4.比较器 总结 谈到TreeSet的特点,估计大家脑海里想到的都是:有序,不可重复,红黑树,基于Treemap实现,自定义排序等特点.这篇博客帮助大家从源码梳理下 ...
- 【公告】MIP组件审核平台故障-影响说明
故障通报 2017年8月8日 下午14:11,由于机器故障原因,MIP组件审核平台无法提供服务. 2017年8月8日 下午16:46,服务恢复. 故障影响 2017年8月8日下午13:00-14:00 ...
- JAVA基础第二章-java三大特性:封装、继承、多态
业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...
- 阿里开源分布式事务解决方案 Fescar
微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,系统微服务化后,一个看似简单的功能,内部可能需要调用多个服务并 ...
- 一名合格的Web安全工程师之成长路径
最近经常听到公司的招聘专员反馈应聘者简历“水分”太大,尤其是技术岗位,例如Web安全工程师,明明是初级阶段的菜鸟,就敢写资深Web安全工程师:在几个项目做一些基础打杂的工作,就敢写带过团队,项目经验丰 ...
- Python调用ansible API系列(五)综合使用
如何把动态生成资产信息.执行playbook以及自定义结果结合起来用呢? #!/usr/bin/env python # -*- coding: utf-8 -*- """ ...