cassandra写数据CommitLog
cassandra
两种方式:
Cassandra-ArchitectureCommitLog
一种是配置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的更多相关文章
- cassandra 如何写数据以及放置副本
application发送数据到server application 发送请求到server 根据设置的load balance 规则从cluster中挑选一个coordinator,一般使用轮询即可 ...
- Cassandra 的数据存储结构——本质是SortedMap<RowKey, SortedMap<ColumnKey, ColumnValue>>
Cassandra 的数据存储结构 Cassandra 的数据模型是基于列族(Column Family)的四维或五维模型.它借鉴了 Amazon 的 Dynamo 和 Google's BigTab ...
- Android开发学习---如何写数据到外部存储设备(sd卡),Environment.getExternalStorageDirectory,怎么获取sd卡的大小?
本文主要介绍如何写数据到sd卡,这里主要到的技术是Environment中的方法. 1. 2.实现代码: /datasave/src/com/amos/datasave/savePasswordSer ...
- python 使用openpyxl来写数据到excel表格
使用openpyxl写execl确实很方便.我先介绍用到的相关模块与函数 Workbook:工作簿模块,在内存创建一个工作簿. ExcelWriter:使用它向exel中写数据. get_column ...
- 串行通讯之.NET SerialPort异步写数据
目录 第1章说明 2 1 为什么需要异步写数据? 2 2 异步写数据的代码 2 3 源代码 4 第1章说明 1 为什么需要异步写数据? 如下图所示,以波特率300打开一个串口. ...
- mysql 写数据操作几次硬盘?
mysql 写数据步骤: 1:写入操作事物日志,持久化操作日志到磁盘,并且只是写在磁盘上一小块区域内的顺序io,不需要像随机io一样 在磁盘多个地方移动磁头 2:内存中事物日志持久化以后 ,写入的数 ...
- Hbase写数据,存数据,读数据的详细过程
Client写入 -> 存入MemStore,一直到MemStore满 -> Flush成一个StoreFile,直至增长到一定阈值 -> 出发Compact合并操作 -> 多 ...
- USB系列之四:向U盘上写数据
在<USB系列之三>中,我们实现了一系列的SCSI命令,在这个系列中,我们要实现向U盘上写扇区的命令,所以,本文相对比较容易,更多地是给出一个实现的源程序. 在<USB系列之三> ...
- Linux启动kettle及linux和windows中kettle往hdfs中写数据(3)
在xmanager中的xshell运行进入图形化界面 sh spoon.sh 新建一个job
随机推荐
- Java基本数据类型总结
基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型.它们是我们编程中使用最频繁的类型.java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为变量的初始化. 1. Java ...
- grep 命令
简单介绍:grep命令是用于分析一行信息,若当中有我们所需要的信息,就将该行取出来. 语法结构:grep [-acinv] [--color=auto] '查找关键字' #{filename} -a: ...
- 微信公众帐号开发-消息创建时间long型与标准时间的互相转换
/** * */ package com.hd.admin.wxmeet.utils; /** * @author jymcpp * */ import java.text.DateFor ...
- BZOJ 2086: [Poi2010]Blocks
Description 每次可以将大于 \(k\) 的一个数 \(-1\), 在左边或右边的数 \(+1\) ,问最大能得到多长的序列每个数都大于等于 \(k\) . Sol 单调栈. 这道题好神啊q ...
- Okhttp3的简单使用
1.get请求: /** * *okhttp get请求 * */ public class MainActivity extends AppCompatActivity { private stat ...
- js中子页面父页面方法 变量相互调用
(1)子页面调用父页面的方法或者变量: window.parent.方法()或者变量名window.parent相当于定位到父页面 之后的操作和在父页面中写代码一样写 window.parent.a ...
- JTextField 限制指定字符不能输入
txtStartDate.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { int keyChar = e.ge ...
- $stateProvider
在你的应用中大多数状态都有与其相关联的 url,路由控制不是设计完成 state 之后的事后想法,而是开始开发时就应该考虑的问题. 这里是如何设置一个基本url. 12345 $stateProvid ...
- (转)Redis使用场景及使用经验
Redis is an open source (BSD licensed), in-memory data structure store! 刚刚结束一个游戏类的活动项目,由于预估的参与人数较多,产 ...
- js实例--飞机大战
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> ...