Cassandra运维之道 v0.2

46
运运运运 Version 0.2 for Cassandra 0.6.4 运运 运运 http://www.NinGoo.net http://twitter.com/NinGoo 2010.8.13

Transcript of Cassandra运维之道 v0.2

Page 1: Cassandra运维之道 v0.2

运维之道Version 0.2 for Cassandra 0.6.4

淘宝 江枫http://www.NinGoo.net

http://twitter.com/NinGoo 2010.8.13

Page 2: Cassandra运维之道 v0.2

Agenda

• 基本概念• 体系架构• 节点管理• 参数配置• 备份恢复• 限制• 监控• 参考

Page 3: Cassandra运维之道 v0.2

基本概念• Gossip• Bootstrap• Memtable/SSTable• Compaction• Commitlog• Consistency level• Hinted Handoff• Anti Entropy• Read Repair

Page 4: Cassandra运维之道 v0.2

Gossip

• 去中心化,一致性 hash , P2P 协议• Gossip 协议通过 endPointStateMap 的摘要 digest同步节点状态信息数据。一个节点自身的状态只能

由自己修改,其他节点的状态只能通过同步更新。• Map 中每一个 EndpointStat 包括:– HeartbeatStat : Generation( 节点重启后递

增 )/Version Number– ApplicationStat :应用状态(每个对象标识一种

状态) /Version Number

Page 5: Cassandra运维之道 v0.2

Gossip

• endPointStateMapEndPointState 10.0.0.1 HeartBeatState: generation 1259909635, version 325 ApplicationState "load-information": 5.2,

generation 1259909635, version 45 ApplicationState "bootstrapping": bxLpassF3XD8Kyks, generation 1259909635, version 56 EndPointState 10.0.0.2 HeartBeatState: generation 1259911052, version 61 ApplicationState "load-information": 2.7, generation 1259911052, version 2 ApplicationState "bootstrapping": AujDMftpyUvebtnn, generation 1259911052, version 31

Gossip Digest for endpoint 10.0.0.2:10.0.0.2:1259911052:61 (IP:Generation:Max Version)一般情况下 HeartbeatState 中的 Version 都会是 endpointstat 中最大 Max

Version ,但这不是一个“死规定”。

Page 6: Cassandra运维之道 v0.2

Gossip

Page 7: Cassandra运维之道 v0.2

Gossip

每秒运行一次( Gossiper.java 的 start 方法),按照以下规则向其他节点发送同步消息:•随机取一个当前活着的节点,并向它发送同步请求( doGossipToLiveMember )•向随机一台不可达的机器发送同步请求( doGossipToUnreachableMember )•如果第一步中所选择的节点不是 seed ,或者当前活着的节点数少于 seed 数,则向随意一台 seed 发送同步请求,以避免出现信息孤岛( doGossipToSeed )也就是说,一个节点发起一轮 Gossip ,最多请求三个节点。整个集群的信息达到同步的时间大概是 log(N) 。

Page 8: Cassandra运维之道 v0.2

Bootstrap• 往集群中加入新的节点称之为 Bootstrap ,需要在配置文件中设置 AutoBootstrap 为 TRUE 。• 系统会自动根据 InitialToken 来将对应的数据从较近的现有节点传输到新节点。• 当一个节点启动 Bootstrap 后,需要 Gossip 信息传递到其他所有节点后,才能启动另外一个新节点的Bootstrap ,一般情况下 2 分钟足够,此时日志中会记录Bootstrapping 信息。• 基于数据安全的考虑,原节点上的旧数据不会自动清理,需要执行 nodetool cleanup 。•Bootstrap 的过程可以通过 notetool streams 监控。

Page 9: Cassandra运维之道 v0.2

Memtable/SSTable• 出自 Google Bigtable 设计的存储模型• 数据先写入内存中的 Memtable• 写入关键路径上不需要持有任何锁• Memtable 达到条件 ( 大小, key 的数量,时间间

隔等 ) 后刷新到磁盘,保存为 SSTable• SSTable 不可修改• 同一个 CF 的多个 SSTable 可以合并 (Compaction)

以优化读操作• 通过布隆过滤算法 (Bloom Filter) 减少对不可能包

含查询 key 的 SSTable 的读取。• 将随机写转变为顺序写,提升系统写性能。

Page 10: Cassandra运维之道 v0.2

Memtable/SSTable

• SSTable 包含对应的三种文件– Datafile按照 Key 排序顺序保存的数据文件– Indexfile保存每个 Key 在 Datafile 中的位置偏移– Filterfile保存 BloomFilter 的 Key 查找树

Page 11: Cassandra运维之道 v0.2

Compaction• 一个 CF 可能有很多 SSTable ,系统会将多个 SSTable 合并排

序后保存为一个新的 SSTable ,称之为 Compaction 。• 一次 compaction 最多请求合并 32 个 SSTable ,最少 4 个。超过 32 个则按时间排序分批进行(这两个阈值可以设置)。

• 如果空间不足,则尝试去掉最大的 SSTable再合并,如果连合并两个最小的 SSTable 的空间都不足,则告警。

• Major Comaction :合并 CF 的所有 SSTable 为一个新的SSTable ,同时执行垃圾数据 (已标记删除的数据 tombstone)清理。

• Minor Compaction :只合并大小差不多的 SSTable ,超过 4个需要合并的 SSTable 就会自动触发。

• 可通过 nodetool compact命令手动触发。• 数据目录最好保持 50% 以上的可用空间。

Page 12: Cassandra运维之道 v0.2

Compaction• Compaction 将旧的 SSTABLE 的记录按序写入到新的名字包含 tmp 的 SSTable ,完成后重命名去掉 tmp ,切换到新文件后,再将原 SSTable删除。

INFO [COMPACTION-POOL:1] 2010-08-12 16:50:58,106 CompactionManager.java (line 320) Compacted to /opt/cassandra/data/test/TEST_CF-4089-Data.db. 1169376522/1155469641 bytes for 31865 keys. Time: 82619ms.

INFO [SSTABLE-CLEANUP-TIMER] 2010-08-12 16:51:20,271 SSTableDeletingReference.java (line 104) Deleted /opt/cassandra/data/test/TEST_CF-4077-Data.db

Page 13: Cassandra运维之道 v0.2

Compaction

• Compaction 由于某些原因,可能导致一些孤儿文件没有及时清除。这些文件将在 JVM GC 的时候异步删除,可以通过 jconsole手动 GC 来删除这些文件。如果磁盘空间不足, Cassandra 也会自动触发 JVM来 GC 。或者重启 Cassandra 也可以清除。

INFO [main] 2010-08-12 17:08:20,421 ColumnFamilyStore.java (line 148) Removing orphan /opt/cassandra/data/test/TEST_CF-tmp-4071-Index.db

Page 14: Cassandra运维之道 v0.2

Compaction• 可以通过设置 Compaction 的 minthreshold(默认 4) 和

maxthreshold(默认 32) 来改变触发一次 Comaction 合并的最少 SSTable 数和最多 SSTable 数。

• 如果设置 minthreshold=0 或者 maxthreshold=0 ,则会禁止系统自动执行 Minor Compaction 。建议在业务高峰期禁止 Compaction ,定期到业务低峰期通过nodetool compact手工执行 Major Compaction 。

• 以上两个参数可以通过 nodetool 设置:Nodetool setcompactionthreshold [minthreshold]

([maxthreshold])

Page 15: Cassandra运维之道 v0.2

Commitlog• 数据写入 Memtable 前需要由

CommitLogExecutorService线程先写 Commitlog• CommitlogHeader 记录了 CF 的脏标志位和该 CF 的恢复

起始偏移位置。• CommitlogSegment 记录了变更的 RowMutation 信息。• Commitlog 刷新有两种机制:

– Batch :当 CommitlogSegment 刷新到磁盘后,插入 Memtable操作才可继续。并且需要等待CommitLogSyncBatchWindowInMS毫秒内的其他写操作一起批量刷日志到磁盘。可以类比为 Oracle 的 batch/wait 模式。

– Periodic :每隔 CommitLogSyncPeriodInMS毫秒性刷新CommitlogSegment ,不阻塞数据写操作,可以类比为 Oracle的 batch/nowait 模式。

Page 16: Cassandra运维之道 v0.2

Commitlog

• SSTable 持久后不可变更,故 Commitlog 只用于Memtable 的恢复,相当于 Oracle 的 Instance Recovery 。 Cassandra 不需要做Media Recover

• 当节点异常重启后,将根据 SSTable 和 Commitlog进行实例恢复,在内存中重新恢复出宕机前的Memtable 。

• 当一个 Commitlog 文件对应的所有 CF 的 Memtable都刷新到磁盘后,该 Commitlog 就不再需要,系统会自动清除。

Page 17: Cassandra运维之道 v0.2

ConsistencyLevel

• WriteLevel Behavior

ZEROEnsure nothing. A write happens asynchronously in background. Until CASSANDRA-685 is fixed: If too many of these queue up, buffers will explode and bad things will happen.

ANY (Requires 0.6) Ensure that the write has been written to at least 1 node, including hinted recipients.

ONE Ensure that the write has been written to at least 1 node's commit log and memory table before responding to the client.

QUORUM Ensure that the write has been written to <ReplicationFactor> / 2 + 1 nodes before responding to the client.

ALL Ensure that the write is written to all <ReplicationFactor> nodes before responding to the client. Any unresponsive nodes will fail the operation.

Page 18: Cassandra运维之道 v0.2

ConsistencyLevel

• ReadLevel Behavior

ONE

Will return the record returned by the first node to respond. A consistency check is always done in a background thread to fix any consistency issues when ConsistencyLevel.ONE is used. This means subsequent calls will have correct data even if the initial read gets an older value. (This is called read repair.)

QUORUMWill query all nodes and return the record with the most recent timestamp once it has at least a majority of replicas reported. Again, the remaining replicas will be checked in the background.

ALLWill query all nodes and return the record with the most recent timestamp once all nodes have replied. Any unresponsive nodes will fail the operation.

Page 19: Cassandra运维之道 v0.2

Hinted Handoff

• Key A 按照规则首要写入节点为 N1 ,复制到 N2• 假如 N1宕机,如果写入 N2 能满足 ConsistencyLevel 要求,

则 Key A 对应的 RowMutation 将封装一个带 hint 信息的头部(包含了目标为 N1 的信息),然后随机写入一个节点N3 ,此副本不可读。同时正常复制一份数据到 N2 ,此副本可以提供读。如果写 N2 不满足写一致性要求,则写会失败。

• N1 恢复后,原本应该写入 N1 的带 hint头的信息将重新写回 N1 。

• HintedHandoff 是实现最终一致性的一个优化措施,可以减少最终一致的时间窗口。

Page 20: Cassandra运维之道 v0.2

Anti Entropy

• 数据的最终一致性由 AntiEntropy (逆熵)所生成的MerkleTrees 对比来发现数据复制的不一致,通过org.apache.cassandra.streaming 来进行完整的一致性修复。

• Merkle Tree 是一种 Hash Tree ,叶子节点是 Key 的 hash值,父节点是所有子节点值的 hash值,通过判断父节点的异同可以知道所有子节点的异同。

• 通过判断 root 的异同可以快速判断所有叶子节点数据的异同。

• 执行 nodetool repair 可以启动 Anti-Entropy ,此操作需要扫描所有数据,对系统的 IO 有较大压力,建议在业务低峰期定期执行。

Page 21: Cassandra运维之道 v0.2

Read Repair

• 读取 Key A 的数据时,系统会读取 Key A 的所有数据副本,如果发现有不一致,则进行一致性修复。

• 如果读一致性要求为 ONE ,会立即返回离客户端最近的一份数据副本。然后会在后台执行 Read Repair 。这意味着第一次读取到的数据可能不是最新的数据。

• 如果读一致性要求为 QUORUM ,则会在读取超过半数的一致性的副本后返回一份副本给客户端,剩余节点的一致性检查和修复则在后台执行。

• 如果读一致性要求高 (ALL) ,则只有 Read Repair完成后才能返回一致性的一份数据副本给客户端。

• 该机制有利于减少最终一致的时间窗口。

Page 22: Cassandra运维之道 v0.2

体系架构• 数据分布• 数据复制• 接口

Page 23: Cassandra运维之道 v0.2

数据分布• RandomPartitioner

基于 MD5 的随机 Hash 分布。 MD5 的 hash空间为 2^127-1 ,每个节点的 InitialToken 可以按节点数量 N进行平均分配,如第 i 个节点可以设置为i*(2^127-1)/N

• OrderPreservingPartitioner基于 Key 值 (UTF-8) 的范围分布

• CollatingOrderPreservingPartitioner基于 Key 值 ( 不同语言环境排序 ) 的范围分布

Page 24: Cassandra运维之道 v0.2

数据复制• DatacenterShardStategy

如果 replication factor 为 N ,则 (N-1)%2 的副本复制到不同数据中心。所有副本在两个数据中心均衡分布

• RackAwareStrategy一个副本复制到不同数据中心,其他副本复制到同数据中心的不同机架。异地机房只保有一个副本,主要用于容灾

• RackUnAwareStrategy不考虑复制节点的物理位置,一般是 hash环右边的N-1 个节点

Page 25: Cassandra运维之道 v0.2

接口• 两种编程接口– Thrift2007年由 Facebook开源给 Apache ,目前发展缓慢。需要生成不同语言的接口代码

– AvroHadoop 的一个子项, Cassandra正在往这个接口进行迁移。这是一个动态序列化库,无须生成静态接口代码

类似接口的还有 Google 的 Protocol Buffer

Page 26: Cassandra运维之道 v0.2

节点管理• 增加节点• 删除节点• 移动节点• 恢复节点

Page 27: Cassandra运维之道 v0.2

增加节点• 增加节点的操作非常简单,就是前面提到

的 Bootstrap• 只需要选择合适的 InitialToken ,加入到现

有集群即可。• 符合条件的数据会自动从现有节点流入到

新加入的节点。• 旧数据需要通过 nodetool cleanup手工清理。

Page 28: Cassandra运维之道 v0.2

删除节点• 删除节点就是将现有节点剔除出集群• 如果目标节点是正常的,在目标节点执行

nodetool decommission 。目标节点的数据会按照规则流入其他合适的节点

• 如果目标节点已经宕机,则在其他正常节点执行 nodetool removetoken 。目标节点的数据会按照规则从其他的副本流入到合适的节点。

Page 29: Cassandra运维之道 v0.2

移动节点• 移动节点指的是重新分布现有节点的数据。

可以简单的理解为先将节点剔除出节点,然后做为新的节点重新加入到集群。

• 设置好新的 InitialToken ,然后执行nodetool move即可完成一步完成节点移动。

Page 30: Cassandra运维之道 v0.2

恢复节点• 如果节点短时间宕机,则只需要节点机器

恢复后正常启动 Cassandra即可,系统会自动将宕机期间的 Hinted Handoff 数据写回该节点。

• 如果宕机时间较长,建议采用一台备用的机器作为新节点加入集群。

• 节点宕机超过 GCGraceSeconds ,则只能作为新节点加入,无法恢复。

Page 31: Cassandra运维之道 v0.2

参数配置• 主要配置文件 storage-conf.xml

– ClusterName :集群名,所有节点统一– AutoBootstrap :作为新节点加入集群时,设置 true开始初始化– HintedHandoffEnabled :启用 Hinted Handoff特性– Keyspaces: 数据模型相关 keyspace 和 column family 设置– ReplicaPlacementStrategy: 数据副本复制策略(基于数据中心分布 /

机架分布)– ReplicationFactor: 数据副本复制份数,一般建议设置为 3 份– EndPointSnitch: 集群节点对应物理机器分布策略,据此路由不同的

数据副本。– Partitioner: 数据分布策略。随机分布 or 有序分布– InitialToken: 初始化 Token ,具体 key 的第一份副本分布到哪个节

Page 32: Cassandra运维之道 v0.2

参数配置• 主要配置文件 storage-conf.xml

– CommitLogDirectory: Commitlog 文件存放路径– DataFileDirectory : 数据文件存放路径,可以指定多个路径– Seeds: 种子节点列表,当初始化完成后可以设置为种子节点,新节

点加入集群时,需要从种子节点获取需要的信息。– RpcTimeoutInMillis: 等待远程节点返回消息的超时设置– CommitLogRotationThresholdInMB: commitlog 文件大小,超过则进行切换

– ListenAddress/ StoragePort: 集群内部通讯监听 IP和端口– ThriftAddress/ ThriftPort: Thrift 监听 IP和端口,用于响应客户端请求– DiskAccessMode: 磁盘访问模式。 64 位系统建议设置为 mmap ,或

者 auto(64 位时等效于 mmap , 32 位则为 standard)– RowWarningThresholdInMB: 对超长的行进行告警。如果 compact 时

行不能完全放入内存中, Cassandra 会崩溃,所以需要根据内存设置告警阀值。

Page 33: Cassandra运维之道 v0.2

参数配置• 主要配置文件 conf/storage-conf.xml

– SlicedBufferSizeInKB: 读取连续列的缓存大小– FlushDataBufferSizeInMB: 刷新 Memtable 到磁盘数据文件的缓存大小– FlushIndexBufferSizeInMB: 刷新 Memtable 到磁盘索引文件的缓存大小– ColumnIndexSizeInKB: 当一行长度超过该值时,添加一个列偏移索引– MemtableThroughputInMB: Memtable 大小– MemtableFlushAfterMinutes: N 分钟后强制刷新 Memtable 到磁盘– ConcurrentReads: 并发读请求,建议设置为 CPU核数的两倍– ConcurrentWrites: Cassandra 写性能更好,因此并发写请求可以设置更高,例如 CPU核数的 8倍

– CommitLogSync: Commitlog 刷新到磁盘的方式, batch or periodic– GCGraceSeconds: 清理带有删除标记的垃圾数据的间隔时间。如果节点宕机时间超过这个间隔,则节点会永久失效,只能重新进行初始化后才能加入到集群。默认为 10天。

Page 34: Cassandra运维之道 v0.2

参数配置• 日志配置文件 conf/log4j.properties

– log4j.appender.R.File=/var/log/cassandra/system.log 日志文件位置– log4j.appender.file.maxFileSize=20MB 日志文件大小

Page 35: Cassandra运维之道 v0.2

参数配置• jvm 配置 bin/cassandra.in.sh

JVM_OPTS=" \ -ea \ -Xms1536m \ -Xmx1536m \ -Xmn500m \ -XX:NewSize=320m \ -XX:MaxNewSize=320m \ -XX:PermSize=96m \ -XX:MaxPermSize=256m \ -XX:MaxTenuringThreshold=6 \ -verbose:gc \ -Xloggc:/opt/cassandra/gc.log \ -XX:+PrintGC \ -XX:+PrintGCTimeStamps \ -XX:MaxTenuringThreshold=1 \ -XX:+HeapDumpOnOutOfMemoryError \ -Dcom.sun.management.jmxremote.port=8080 \ -Dcom.sun.management.jmxremote.ssl=false \ -Dcom.sun.management.jmxremote.authenticate=false"

Page 36: Cassandra运维之道 v0.2

参数配置• jvm 配置 bin/cassandra.in.sh

如果是 64 位系统,建议打开 JVM 的指针压缩选项-XX:+UseCompressedOops

Page 37: Cassandra运维之道 v0.2

备份恢复• Snapshot

–利用 nodetool 的 snapshot命令可以生成 SSTable 的一个快照。–在生成 snapshot 前,先会执行一次 Memtable切换,将最新的数据保存为 SSTable 。–复制 snapshot即可对节点的数据进行物理备份。–Snapshot实际上是 SSTable 文件的一个 Hard link 。

Page 38: Cassandra运维之道 v0.2

备份恢复• Export/Import通过 sstable2json 可以将数据导出为 json格式的文件,相当于逻辑备份。

通过 json2sstable 则可以将 json格式的文件导入为 SSTable 。

Page 39: Cassandra运维之道 v0.2

限制• Keyspace/CF无法动态增删, 0.7 以后的版本有计划支持动

态增删。• 由于 Compaction 时对整行数据反序列化,所以一行数据必须要能够全部存放进内存中。 https://issues.apache.org/jira/browse/CASSANDRA-16

• 一行数据的长度不能超过 2^31-1字节,因为行数据序列化时用一个整数表示其长度同时序列化到磁盘中。

• Super columnfamilies 中的 sub column没有索引,因此在反序列化一个 sub column 时需要反序列化 super column 中的所有 sub column 。 因此需要避免设计使用大量的 sub column 。 https://issues.apache.org/jira/browse/CASSANDRA-598

Page 40: Cassandra运维之道 v0.2

限制• Thrift 不支持流( streaming) ,读写请求的数据都需要存放

在内存中,因此大对象可能需要切分后存取。http://issues.apache.org/jira/browse/CASSANDRA-265

• Thrift端口收到非协议标准的随机数据可能导致 Cassandra崩溃。因此对 Thrift 的探测如 telnet 等操作可能导致节点挂掉 http://issues.apache.org/jira/browse/CASSANDRA-475 http://issues.apache.org/jira/browse/THRIFT-601

• 建议在 64 位系统中使用 Cassandra 。 32 位系统 JVM 由于地址空间限制,只能使用不到 2G 的内存,而 Cassandra 大量操作依赖内存处理,容易因为内存不足产生 OOM ,导致java进程退出。

Page 41: Cassandra运维之道 v0.2

监控• Nodetoolnodetool –h localhost –p 8080 tpstats

Page 42: Cassandra运维之道 v0.2

监控• Nodetoolnodetool –h localhost –p 8080 cfstats

Page 43: Cassandra运维之道 v0.2

监控• jconsole jmx地址: service:jmx:rmi:///jndi/rmi://localhost:8080/jmxrmi

Page 44: Cassandra运维之道 v0.2

监控• Nagioshttp://www.mahalo.com/how-to-monitor-cassandra-with-nagios

Page 45: Cassandra运维之道 v0.2

监控• Cassandra web consolehttp://github.com/suguru/cassandra-webconsole/downloads

Page 46: Cassandra运维之道 v0.2

参考• http://wiki.apache.org/cassandra• http://io.typepad.com/glossary.html • http://spyced.blogspot.com/• http://perspectives.mvdirona.com/2009/02/07/

FacebookCassandraArchitectureAndDesign.aspx• http://nosql.mypopescu.com/tagged/cassandra• http://www.cs.cornell.edu/home/rvr/papers/flowgossip.pdf • http://www.ruohai.org/?p=13• http://www.ningoo.net/html/2010/cassandra_token.html • http://www.dbthink.com/?tag=cassandra• http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html• http://cassandra.apache.org/

*部分链接需要翻墙访问