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. 转载:Centos7 从零编译Nginx+PHP+MySql 序言 一

    这次玩次狠得.除了编译器使用yum安装,其他全部手动编译.哼~ 看似就Nginx.PHP.MySql三个东东,但是它们太尼玛依赖别人了. 没办法,想用它们就得老老实实给它们提供想要的东西. 首先的一些 ...

  2. This is US 我们的生活

    温情暖心剧 看点在于真实,能让人找到不少共鸣像极了平淡而操蛋的生活,不断交织着苦涩和甘甜,柴米油盐.酸甜苦辣.嬉笑打闹.悲欢离合.温情又不尽如人意 this is us,our life 生活有如柠檬 ...

  3. Sicily 1151: 简单的马周游问题(DFS)

    这道题嘛,直接使用DFS搜索,然后莫名其妙地AC了.后来看了题解,说是move的顺序不同的话可能会导致超时,这时便需要剪枝,真是有趣.原来自己是误打误撞AC了,hhh.题解还有另一种解法是先把一条完整 ...

  4. Maven的POM.xml配置大全

    <?xml version="1.0" encoding="utf-8"?> <project xmlns="http://mave ...

  5. paintEvent(QPaintEvent*)是系统自动调用的

    qt中函数paintEvent(QPaintEvent*)是被系统自动调用. paintEvent(QPaintEvent *)函数是QWidget类中的虚函数,用于ui的绘制,会在多种情况下被其他函 ...

  6. 一些有趣的Javascript技巧

    整理一些刷题时学会的小技巧…… 目录: 即大于0又小于0的变量 String.split() 与 正则表达式 缓存的几种方法 初始化一个数组 即大于0又小于0的变量 问题: 设计一个变量val,使得以 ...

  7. python3的编码问题

    Python3对文本(str)和二进制数据(bytes)作了更为清晰的区分. 文本默认是以Unicode编码(python2默认是ascii),由str类型表示,二进制数据则由bytes类型表示. s ...

  8. JavaBean的用法

    JavaBean是一个可重复使用的软件组件,是用Java语言编写的.遵循一定标准的类. JavaBean是Java Web的重要组件,它封装了数据和操作的功能类,供JSP和Servlet调用,完成数据 ...

  9. ArcGIS 10.1 BUG记录

    声明:笔者使用ARCGIS 10.1 XXX版,YYY版可能没有此处描写的问题 1. 关于注册数据库 发布启用FA的服务,需要为数据库进行ArcGIS Server注册,若通过ArcMap执行注册,会 ...

  10. Linux+PHP+MySql网站迁移配置

    LINUX下MYSQL数据库默认数据库文件位置: 数据库文件默认在:cd /usr/share/mysql 配置文件默认在:/etc/my.cnf ———————————– 数据库目录:/var/li ...