cassandra

两种方式:

Cassandra-ArchitectureCommitLog

Cassandra持久化-Durability

一种是配置commitlog_sync为periodic,定期模式;另外一种是batch,

默认(Cassandra1.2.19/3.0.0)为periodic,定期10000ms

#commitlog_sync: batch
#commitlog_sync_batch_window_in_ms: 50
commitlog_sync: periodic
commitlog_sync_period_in_ms: 10000

这里如果是periodic模式潜在丢数据的风险,来看看两种实现方式,大致调用顺序

StorageProxy. ->WritePerformer.apply()->counterWriteTask()/sendToHintedEndpoints()->((CounterMutation/mutation).apply()->Mutation.apply()->Keyspace.apply()->CommitLog.instance.add(mutation),主要看CommitLog.instance.add(mutation)

CommitLog.instance.add(mutation)

public ReplayPosition add(Mutation mutation)
{
assert mutation != null; long size = Mutation.serializer.serializedSize(mutation, MessagingService.current_version); long totalSize = size + ENTRY_OVERHEAD_SIZE;
if (totalSize > MAX_MUTATION_SIZE)
{
throw new IllegalArgumentException(String.format("Mutation of %s bytes is too large for the maxiumum size of %s",
totalSize, MAX_MUTATION_SIZE));
} Allocation alloc = allocator.allocate(mutation, (int) totalSize);
try
{
ICRC32 checksum = CRC32Factory.instance.create();
final ByteBuffer buffer = alloc.getBuffer();
BufferedDataOutputStreamPlus dos = new DataOutputBufferFixed(buffer); // checksummed length
dos.writeInt((int) size);
checksum.update(buffer, buffer.position() - 4, 4);
buffer.putInt(checksum.getCrc()); int start = buffer.position();
// checksummed mutation
Mutation.serializer.serialize(mutation, dos, MessagingService.current_version);
checksum.update(buffer, start, (int) size);
buffer.putInt(checksum.getCrc());
}
catch (IOException e)
{
throw new FSWriteError(e, alloc.getSegment().getPath());
}
finally
{
alloc.markWritten();
}
executor.finishWriteFor(alloc);
return alloc.getReplayPosition();
}

这里主要写buffer,没有刷盘,这时会有两种方式,就是之前说的periodic与batch,主要看 executor.finishWriteFor(alloc),起里边调用了maybeWaitForSync(),是一个抽像的,在BatchCommitLogService与PeriodicCommitLogService中实现

public void finishWriteFor(Allocation alloc)
{
maybeWaitForSync(alloc);
written.incrementAndGet();
}
protected abstract void maybeWaitForSync(Allocation alloc);

BatchCommitLogService中实现

protected void maybeWaitForSync(CommitLogSegment.Allocation alloc)
{
// wait until record has been safely persisted to disk
pending.incrementAndGet();
alloc.awaitDiskSync(commitLog.metrics.waitingOnCommit);
pending.decrementAndGet();
}
void waitForSync(int position, Timer waitingOnCommit)
{
while (lastSyncedOffset < position)
{
WaitQueue.Signal signal = waitingOnCommit != null ?
syncComplete.register(waitingOnCommit.time()) :
syncComplete.register();
if (lastSyncedOffset < position)
signal.awaitUninterruptibly();
else
signal.cancel();
}
}

这里面如果lastSyncedOffset < position是会一直等待的,知道lastSyncedOffset>=position,即当前alloc对应的buffer已被flush

PeriodicCommitLogService中实现,这里的关键是waitForSyncToCatchUp()

protected void maybeWaitForSync(CommitLogSegment.Allocation alloc)
{
if (waitForSyncToCatchUp(Long.MAX_VALUE))
{
// wait until periodic sync() catches up with its schedule
long started = System.currentTimeMillis();
pending.incrementAndGet();
while (waitForSyncToCatchUp(started))
{
WaitQueue.Signal signal = syncComplete.register(commitLog.metrics.waitingOnCommit.time());
if (waitForSyncToCatchUp(started))
signal.awaitUninterruptibly();
else
signal.cancel();
}
pending.decrementAndGet();
}
}

waitForSyncToCatchUp()

private boolean waitForSyncToCatchUp(long started)
{
return started > lastSyncedAt + blockWhenSyncLagsMillis;
}

这里的blockWhenSyncLagsMillis是1.5倍的commitlog_sync_period_in_ms

blockWhenSyncLagsMillis = (int) (DatabaseDescriptor.getCommitLogSyncPeriod() * 1.5);

为什么是1.5倍呢,我的理解是假设flush刷盘的时间是0.5个commitlog_sync_period,但是这个其实是不一定的,可能大于0.5,可能小于0.5,这里就潜在数据丢失了,假设这个确实flush一次不止0.5个commitlog_sync_period,那写完的数据其实是不确定一定刷盘了的。

具体的flush代码,位于AbstractCommitLogService中的start()方法中

long syncStarted = System.currentTimeMillis();
commitLog.sync(shutdown);
lastSyncedAt = syncStarted;
syncComplete.signalAll();

commitLog.sync()->segment.sync()->write(startMarker, sectionEnd),write在CompressedSegment与MemoryMappedSegment实现,最终都是调用的channel.force()

cassandra写数据CommitLog的更多相关文章

  1. cassandra 如何写数据以及放置副本

    application发送数据到server application 发送请求到server 根据设置的load balance 规则从cluster中挑选一个coordinator,一般使用轮询即可 ...

  2. Cassandra 的数据存储结构——本质是SortedMap<RowKey, SortedMap<ColumnKey, ColumnValue>>

    Cassandra 的数据存储结构 Cassandra 的数据模型是基于列族(Column Family)的四维或五维模型.它借鉴了 Amazon 的 Dynamo 和 Google's BigTab ...

  3. Android开发学习---如何写数据到外部存储设备(sd卡),Environment.getExternalStorageDirectory,怎么获取sd卡的大小?

    本文主要介绍如何写数据到sd卡,这里主要到的技术是Environment中的方法. 1. 2.实现代码: /datasave/src/com/amos/datasave/savePasswordSer ...

  4. python 使用openpyxl来写数据到excel表格

    使用openpyxl写execl确实很方便.我先介绍用到的相关模块与函数 Workbook:工作簿模块,在内存创建一个工作簿. ExcelWriter:使用它向exel中写数据. get_column ...

  5. 串行通讯之.NET SerialPort异步写数据

    目录 第1章说明    2 1 为什么需要异步写数据?    2 2 异步写数据的代码    2 3 源代码    4 第1章说明 1 为什么需要异步写数据? 如下图所示,以波特率300打开一个串口. ...

  6. mysql 写数据操作几次硬盘?

    mysql 写数据步骤: 1:写入操作事物日志,持久化操作日志到磁盘,并且只是写在磁盘上一小块区域内的顺序io,不需要像随机io一样 在磁盘多个地方移动磁头 2:内存中事物日志持久化以后  ,写入的数 ...

  7. Hbase写数据,存数据,读数据的详细过程

    Client写入 -> 存入MemStore,一直到MemStore满 -> Flush成一个StoreFile,直至增长到一定阈值 -> 出发Compact合并操作 -> 多 ...

  8. USB系列之四:向U盘上写数据

    在<USB系列之三>中,我们实现了一系列的SCSI命令,在这个系列中,我们要实现向U盘上写扇区的命令,所以,本文相对比较容易,更多地是给出一个实现的源程序. 在<USB系列之三> ...

  9. Linux启动kettle及linux和windows中kettle往hdfs中写数据(3)

    在xmanager中的xshell运行进入图形化界面 sh spoon.sh 新建一个job

随机推荐

  1. 前端工具HBuilder安装Sass插件

    HBuilder自带未安装的less插件,但是sass插件却没有,需要自己安装,步骤如下: 1.安装sass,参考: http://www.w3cplus.com/sassguide/install. ...

  2. git error: unable to rewind rpc post data - try increasing http.postBuffer

    error: unable to rewind rpc post data - try increasing http.postBuffererror: RPC failed; curl 56 Rec ...

  3. HTML5-本地存储与cookies

    一.H5的几种存储形式 1.本地存储(localstorage和sessionstorage) 存储形式:key-->value 过期策略:localstorage永久存储,不过期,除非手动删除 ...

  4. mysql 5.7 的安装配置与 navicat premium for mysql 11 的破解使用

    再安装mysql5.7 或以上的版本出现了一些问题,现在总结下,希望能给初入学习mysql的人一下帮助,大牛就不要来嘲笑小弟我了 首先准备如下: 1.下载mysql 5.7,下载地址:https:// ...

  5. 重视blog备份——兼记我与CSDN的爱恨情仇

    痛定思痛,终于决定--逐渐备份.迁移CSDN博客到"博客园". 缘起 前几年比较喜欢逛csdn的bbs,虽然之前在cnblogs也注册了账号,但一直用CSDN博客比较多.本来一直用 ...

  6. JSP页面JSTL提供的函数标签EL表达式操作字符串的方法

    首先在jsp页面导入标签<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions&quo ...

  7. iOS 局部变量 全局变量 成员变量

    一.成员变量 : 写在类声明的大括号中的变量叫成员变量 (也叫属性/实例变量) 成员变量不可离开类 离开了类就不是成员变量 成员变量不能再定义的同事初始化 成员量只能通过对象来访问 成员变量存储在堆中 ...

  8. 10.OC中retainCount返回值不准的原因

    翻看该方法的参考文档,苹果对retainCount方法的描述如下: retainCount Do not use this method. (required) - (NSUInteger)retai ...

  9. 采用cocos2d-x lua 的listview 实现pageview的翻页效果之上下翻页效果

    --翻页滚动效果local function fnScrollViewScrolling( sender,eventType)    -- body    if eventType == 10 the ...

  10. Android笔记:蓝牙

    if (!BTAdapter.isEnabled()) { //没有打开,就启动确认窗口询问用户是否打开 Intent i = new Intent(BluetoothAdapter.ACTION_R ...