cassandra 写IO路径-阿里云开发者社区

开发者社区> 陈江@阿里> 正文

cassandra 写IO路径

简介: 从日志及外围工具了解大致流程 cassandra@cqlsh:ycsb> TRACING on; cassandra@cqlsh:ycsb> insert into usertable(y_id, field0, field1) values('1', 'f0', 'f1'); Tracing .
+关注继续查看

从日志及外围工具了解大致流程

cassandra@cqlsh:ycsb> TRACING on;
cassandra@cqlsh:ycsb> insert into usertable(y_id, field0, field1) values('1', 'f0', 'f1');

Tracing session: 9f327c10-db85-11e9-93d6-478d8c046f59

 activity                                                                                                   | timestamp                  | source       | source_elapsed | client
------------------------------------------------------------------------------------------------------------+----------------------------+--------------+----------------+--------------
                                                                                         Execute CQL3 query | 2019-09-20 17:04:15.953000 | 172.17.30.80 |              0 | 172.17.30.80
                     MUTATION message received from /172.17.30.80 [MessagingService-Incoming-/172.17.30.80] | 2019-09-20 17:04:15.953000 | 172.17.30.79 |             14 | 172.17.30.80
 Parsing insert into usertable(y_id, field0, field1) values('1', 'f0', 'f1'); [Native-Transport-Requests-1] | 2019-09-20 17:04:15.953000 | 172.17.30.80 |            125 | 172.17.30.80
                                                                   Appending to commitlog [MutationStage-1] | 2019-09-20 17:04:15.953000 | 172.17.30.79 |            152 | 172.17.30.80
                                                          Preparing statement [Native-Transport-Requests-1] | 2019-09-20 17:04:15.953000 | 172.17.30.80 |            339 | 172.17.30.80
                                            Determining replicas for mutation [Native-Transport-Requests-1] | 2019-09-20 17:04:15.953000 | 172.17.30.80 |            867 | 172.17.30.80
                                                                   Appending to commitlog [MutationStage-2] | 2019-09-20 17:04:15.954000 | 172.17.30.80 |           1137 | 172.17.30.80
                                                             Adding to usertable memtable [MutationStage-1] | 2019-09-20 17:04:15.954000 | 172.17.30.79 |            304 | 172.17.30.80
                  Sending MUTATION message to /172.17.30.79 [MessagingService-Outgoing-/172.17.30.79-Small] | 2019-09-20 17:04:15.954000 | 172.17.30.80 |           1155 | 172.17.30.80
                                                             Adding to usertable memtable [MutationStage-2] | 2019-09-20 17:04:15.954000 | 172.17.30.80 |           1248 | 172.17.30.80
                                                      Enqueuing response to /172.17.30.80 [MutationStage-1] | 2019-09-20 17:04:15.958000 | 172.17.30.79 |           5275 | 172.17.30.80
          Sending REQUEST_RESPONSE message to /172.17.30.80 [MessagingService-Outgoing-/172.17.30.80-Small] | 2019-09-20 17:04:15.959000 | 172.17.30.79 |           5469 | 172.17.30.80
             REQUEST_RESPONSE message received from /172.17.30.79 [MessagingService-Incoming-/172.17.30.79] | 2019-09-20 17:04:15.960000 | 172.17.30.80 |             11 | 172.17.30.80
                                            Processing response from /172.17.30.79 [RequestResponseStage-4] | 2019-09-20 17:04:15.960000 | 172.17.30.80 |             93 | 172.17.30.80
                                                                                           Request complete | 2019-09-20 17:04:15.959483 | 172.17.30.80 |           6483 | 172.17.30.80

上述执行过程如下:

因为大家ts都是一样的,所以我们分别看172.17.30.80, 172.17.30.79集群日志
172.17.30.80是cordinate,日志序:

  • 执行一个cql3 query
  • parse 这条insert cql
  • Preparing statement,转变为mutation
  • 判断mutation对应的副本分布
  • 追加到commitlog
  • 写入 cql指定表(usertable) 的memtable
  • 向172.17.30.79发送mutation request
  • 从 172.17.30.79 收到REQUEST_RESPONSE消息
  • 处理响应,给客户端ack

172.17.30.79 tracing日志流程

  • 从172.17.30.80收到mutation请求
  • 追加到本地commitlog
  • 写入 cql指定表(usertable) 的memtable
  • 给172.17.30.80的回复压入队列
  • 发送REQUEST_RESPONSE 消息给 172.17.30.80

图示流程

image

持久化后的数据格式

bin/nodetool flush
tools/bin/sstabledump /data/ycsb/usertable-07b25290d05711e9a6daafb876512a23/md-4-big-Data.db
WARN  17:09:09,147 Only 58.696GiB free across all data volumes. Consider adding more capacity to your cluster or removing obsolete snapshots
[
  {
    "partition" : {
      "key" : [ "1" ],
      "position" : 0
    },
    "rows" : [
      {
        "type" : "row",
        "position" : 27,
        "liveness_info" : { "tstamp" : "2019-09-20T09:04:15.952637Z" },
        "cells" : [
          { "name" : "field0", "value" : "f0" },
          { "name" : "field1", "value" : "f1" }
        ]
      }
    ]
  }
]

可以看到数据组织格式,一个sstable有很多partiion,一个partition有很多行,一个行有很多cells,内存的memtable也大体是这种格式,只不过重度依赖btree格式。

deep diving

让我们深入了解单机的写io路径,我们会花些篇幅深入了解单机引擎,如果不是开发者,可以跳过下面这些内容,不了解也没关系

io写流程

单机因为是一个标准的lsm引擎,所以可分为append wal,及append memtable,而memtable使用跳表及内部的btree描述整个memtable数据结构。

OpOrder写栅栏(Barrier)

有个细节挺有意思,写开始会通过writeOrder.start()会给当前Group计数器+1, 当写结束通过try语法糖自动close,close时候计数器会减一,如果计数器最后状态是finish状态,当前group无引用语义,会将自己unlink掉,唤醒该group waitQueue堵塞着的所有线程。如memtable已满,我们都知道要开始flush到本地,flush时候不能堵塞前端写,会switch一下memtable,把当前current memtable变成old,但是是一定要确保前端线程都对old memtable写完才开始flush sstable到本地,flush线程通过以下几个函数调用
writeOrder.newBarrier():
writeBarrier.issue():新创建了一个Group,新的写入会关联到这个Group上,旧grop不再接受新写入,相当于封箱了
writeBarrier.await():flush线程会堵塞,不再执行,等待前端线程写完,通过waitQueue唤醒,类似条件变量

image

如果读者觉得理解有难度,可以想象成flush线程跟前端写线程对于memtable的锁操作,以达到线程安全。上面的OpOrder就是lock-free的一种实现方式。

append mutation to commitLog

segment是由AbstractCommitLogSegmentManager一段段create出来的,这一段段segment就组成了连续不断的日志流。segment被创建时,会使用memoryMapped做内存映射,memoryMapped可以减少一次内存拷贝,非常适合大量小IO。往commitLog追加mutation时候,先向segmentManager alloc一段文件空间,代码里Allocation标记,相当于预先申请room,然后再把mutation序列化成bytes,写入Allocation底层的buffer,写入过程会写入相应的checksum。这个时候还没结束,只是写到了pagecache,掉电会丢数据,还需要周期性的做fsync。cassandra提供两种fsync策略

  • BatchCommitLogService: sync线程会周期性默认每2ms,fsync一次,此时前端线程需要同步等待,直到收到fsync结束条件变量。一个sync间隔内其余线程可搭顺风车,只需同步等待,groupcommit思路。
  • PeriodicCommitLogService:后台sync线程默认10s刷一次,前端写线程可以立即返回

append memtable

通过写时opGroup遭到对应的mt, mt内部主要数据结构ConcurrentSkipListMap partitions
AtomicBTreePartition 有个比较重要的属性Holder ref,表示一个Partition的数据结构,展开Holder:

protected static final class Holder
    {
        final PartitionColumns columns; //列定义
        final DeletionInfo deletionInfo;//partition级别deletion info
        // the btree of rows
        final Object[] tree; //所有行,btree格式排好序
        final Row staticRow; //静态行,仅一行
        final EncodingStats stats;
    }

一个partition有很多行,每一个有很多cell,这个cell集合也是使用btree格式组织的。
写mt主要流程就是
1.写之前一直携带了opGroup,mutation指定了要往哪个table写,但内存中table/cfs有很多memtable,有新有旧,这时候就通过opGroup找到要往哪个memtable写入。

  1. 通过memtable的跳表找到AtomicBTreePartition数据结构,对要更新的mutation每行进行如下操作,对Holder.tree进行二分查找,如果找到了说明要做rowMerge,没找到的话说明直接insert到全局序对应的位置就好。c*规定每个partition可以上数G,但那是磁盘整体数据量,当前memtable中的partition只存放了一个时间窗口内的,所以不会很大,大了直接就通过flush线程刷成sstable了。
  2. memtable操作有大量的cas操作,避免加锁,减少上下文切换。

结语

通过上述内容介绍,我们大致了解了cassandra的写流程,后续还会有系列文章介绍cassandra如何flush memtable,以及cassandra的读流程,尽情期待,可入群拿到最新资讯。

入群邀约

为了营造一个开放的 Cassandra 技术交流环境,社区建立了微信群公众号和钉钉群,为广大用户提供专业的技术分享及问答,定期开展专家技术直播,欢迎大家加入。
另外阿里云为广大开发者提供云上Cassandra资源,可用于动手实践:9.9元可使用三月(限首购)。
直达链接:https://www.aliyun.com/product/cds

8a55f5a99463a7276265074b1079d74f4ab3d164.png

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
使用NAT网关轻松为单台云服务器设置多个公网IP
在应用中,有时会遇到用户询问如何使单台云服务器具备多个公网IP的问题。 具体如何操作呢,有了NAT网关这个也不是难题。
22640 0
怎么设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程
7355 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4593 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
8201 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
9500 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
4209 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
3599 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
1160 0
+关注
陈江@阿里
从业于BAT等公有云部门,分布式存储领域专家
21
文章
0
问答
来源圈子
更多
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载