Pegasus ReadOnly集群调研

2022-02-10

RocksDB参数

  参数 说明 默认值 建议 原因
DBOptions create_if_missing 如果dababase丢失了,将会自动创建 false 保持默认值  
  create_missing_column_families 如果column families丢失,将会自动创建 false 保持默认值  
  error_if_exists 如果数据库已存在,抛出错误 false 保持默认值  
  paranoid_checks 每次取key的前N位,根据key的前N位来构造bloom filter,用于提高范围查询效率 true 保持默认值  
  rate_limiter 控制flush和compaction速度 nullptr 保持默认值  
  sst_file_manager 跟踪sst files并控制文件删除速率 nullptr 保持默认值  
  info_log db error信息写入该log文件   保持默认值  
  info_log_level log level INFO_LEVEL/ DEBUG_LEVEL 保持默认值  
  max_open_files 该DB可打开的最大文件数 -1 保持默认值  
  max_file_opening_threads 用于打开文件的最大线程数量 16 保持默认值  
  max_total_wal_size wal超过该大小时,强制flush 0 保持默认值  
  statistics 统计metrics nullptr 保持默认值  
  use_fsync 写入时是否使用fsync,默认使用fdatasync(fdatasync更快) false 保持默认值  
  db_paths sst文件可以存放的路径 保持默认值  
  db_log_dir log路径 ”” 保持默认值  
  wal_dir wal绝对路径地址 ”” 保持默认值  
  delete_obsolete_files_period_micros 删除废弃文件的时间 6h 保持默认值  
  max_background_jobs compaction和flush的最大线程数 2 -1 通过配置 max_background_compactions和 max_background_flushes来决定线程数
  max_background_compactions 最大compaction线程数 -1 4  
  max_background_flushes 最大flush线程数 -1 0  
  max_subcompactions 将一个compaction任务切分成多个sub任务,每个线程执行一个sub任务 1 保持默认值  
  max_log_file_size log文件的最大size 0 保持默认值  
  log_file_time_to_roll Time for the info log file to roll 0 保持默认值  
  keep_log_file_num 最大保存的log文件数量 1000 保持默认值  
  recycle_log_file_num 如果配置不为0,reuse老的log文件,覆盖老数据 0 保持默认值  
  max_manifest_file_size 当达到指定值时,roll over manifest文件 0 保持默认值  
  table_cache_numshardbits Number of shards used for table cache,RocksDB中的cache可以分成多个shard,以减少竞争 6 保持默认值  
  WAL_ttl_seconds 用于删除已归档的WAL文件 0 保持默认值  
  WAL_size_limit_MB   0 保持默认值  
  manifest_preallocation_size 为manifest文件预分配的字节数 4MB 保持默认值  
  allow_mmap_reads 使用mmap读取sst文件: 什么是mmap? false 保持默认值  
  use_direct_reads 对read/write操作使用direct IO模式 false true Pegasus目前配置 使用RocksDB的缓存,不用操作系统内核的page cache。RocksDB比操作系统更懂自己的数据应该如何缓存
  use_direct_io_for_flush_and_compaction 对flush和compaction的写入使用direct IO false true 维持Pegasus中的值
  allow_fallocate 是否允许fallocate true 保持默认值 什么是fallocate  
  is_fd_close_on_exec Disable child process inherit open files true 保持默认值  
  stats_dump_period_sec 将rocksdb.stats dump到log文件的周期时间 600 保持默认值  
  stats_persist_period_sec 将rocksdb.stats dump到rocksdb的周期时间 600 保持默认值  
  persist_stats_to_disk true- 将rocksdb.stats dump到隐藏的cf中 false- 将rocksdb.stats写入到内存结构中 false false  
  stats_history_buffer_size 用于存储rocksdb.stats的内存大小 1MB 保持默认值  
  advise_random_on_open sst文件打开时,告诉文件系统其访问模式是random true 保持默认值  
  db_write_buffer_size 整个db所有cf的memtable总大小 0 保持默认值 只读集群没有写入,无需write buffer
  write_buffer_manager 通过write_buffer_manager,所有实例可共享write buffer nullptr 保持默认值 只读集群没有写入,无需write buffer
  access_hint_on_compaction_start compaction开始时的文件访问模式,作用于imput文件 NORMAL 保持默认值  
  new_table_reader_for_compaction_inputs 对compaction imput文件,时钟会创建新的fd和table reader。 后续不再维护 false 保持默认值  
  compaction_readahead_size compaction时预读,改善随机读 0 2MB 维护Pegasus中设置值
  random_access_max_buffer_size WinMmapReadableFile使用的buffer size最大值 仅在windows平台有效 1MB 保持默认值  
  writable_file_max_buffer_size 可写文件的最大写缓存 1MB 0 readonly集群没有写入
  use_adaptive_mutex 是否使用adaptive mutex。当锁竞争不激烈时,可以减少context切换;反之会浪费一些spin时间 关于adaptive mutex false 保持默认值  
  bytes_per_sync OS递增地sync file,每次sync的字节数 0 保持默认值  
  wal_bytes_per_sync 类似于bytes_per_sync,作用于WAL文件 0 保持默认值  
  strict_bytes_per_sync 搭配bytes_per_sync和wal_bytes_per_sync使用,决定是否控制写入的速度,防止写入过多导致flush堆积 false 保持默认值  
  listeners 当rocksdb的一些时间触发时,调用这些callback      
  enable_thread_tracking 跟踪DB内的线程状态 false 保持默认值  
  delayed_write_rate 对DB的写入限速,当下列三个条件之一发生时: soft_pending_compaction_bytes_limit被触发 level0_slowdown_writes_trigger被触发 当允许超过3个以上的memtable时,正在写入允许的最后一个memtable 0 保持默认值  
  enable_pipelined_write 如果enable_pipelined_write为true,则为WAL写和memtable写保持单独的写线程队列。写线程首先进入WAL写入队列,然后进入memtable写入队列。因此,WAL写入队列上的pending线程只需要等待之前的写入者完成WAL写入,而不需要等待memtable写入。 启用该特性可以提高写吞吐量,减少两阶段提交准备阶段的延迟。 false 保持默认值  
  unordered_write 将unordered_write设置为true可以通过放松snapshot的不变性保证,换取更高的写吞吐量。 这违背了Get从snapshot中所期望的可重复性 false 保持默认值  
  allow_concurrent_memtable_write 允许multi-writers同时更新memtables 如果设置为true,强烈建议打开enable_write_thread_adaptive_yield true 保持默认值  
  enable_write_thread_adaptive_yield 如果设置为true,写入线程将会和当前write batch group leader同步,等待write_thread_max_yield_usec时间后进入mutex阻塞 true 保持默认值  
  max_write_batch_group_size_bytes 一个WAL或memtable写的单个批处理中写入的最大字节数限制 1MB 保持默认值  
  write_thread_max_yield_usec 在mutex阻塞之前,一个写操作将使用spin loop与其他写线程协调的最大微秒数。 100 保持默认值  
  write_thread_slow_yield_usec std::this_thread::yield调用(微秒)代表其他进程或线程想要使用当前内核。 增加这一点会使写线程更有可能通过spinning占用CPU,这将表现为上下文切换数量的增加 3 保持默认值  
  skip_stats_update_on_db_open 如果为true,那么DB::Open()将不会更新用于优化compaction的statistics 设置成false有利于减少DBopen时间 false 保持默认值  
  wal_recovery_mode WAL的recovery mode,用以控制replaying WAL时的一致性 WALRecoveryMode::kPointInTimeRecovery 保持默认值  
  allow_2pc   false 保持默认值  
  row_cache global cache for table-level rows nullptr 使用LRUCache  
  wal_filter 在recovery处理WAL时的filter。 该filter提供了一种检查日志记录、忽略特定记录或跳过replay的方法。 nullptr 保持默认值  
  fail_if_options_file_error 如果找不到options文件, DB::Open/CreateColumnFamily/DropColumnFamily/SetOptions将会失败 false 保持默认值  
  dump_malloc_stats 如果设置成true,将会随着rocksdb.stats一起打印malloc相关的stats false 保持默认值  
  avoid_flush_during_recovery 默认情况下,DB在open时会replay WAL,并进行flush,这样会导致产生很多小的sst文件。设置成true可以避免这种情况,并不会带来数据丢失的风险 false 保持默认值  
  avoid_flush_during_shutdown 默认情况下,DB在close时会刷新memtable中所有未持久化的数据。 设置成false可以提高close速度,但是数据会丢失 false 保持默认值  
  allow_ingest_behind 设置成true的话,会有以下影响: 会disable一些内部关于SST文件compression的优化 保留最底层作为ingest的文件使用 num_levels必须>=3 false 保持默认值 只读集群没有写,使用ingest_behind是用于在ingest文件时,保存写请求写入的数据
  preserve_deletes 如果设置成true,只有LSN小于 SetPreserveDeletesSequenceNumber(uint64_t ts)的delete数据才会被删掉,此时客户端需要周期性的调用该函数,否则这些delete数据永远无法删除 false 保持默认值  
  two_write_queues 双写入队列 false 保持默认值  
  manual_wal_flush 如果设置成true,那么每次写入时,WAL将不会自动刷新 false 保持默认值  
  atomic_flush atomic flush所有的cf false true 维持Pegasus中设置的值
  avoid_unnecessary_blocking_io 如果设置成true,working thread将会避免做unnecessary和耗时的工作(例如:删除无用文件、删除memtable),并调度一个background线程来做 false true 对延迟敏感的话可以打开
  write_dbid_to_manifest DB ID存入DB folder中的特定文件,设置成true的话,DB ID将存入manifest文件 false 保持默认值  
  log_readahead_size 读取log文件时,预读取的大小,通常用于log文件在远端存储时,用于减少IO往返 0 保持默认值  
ColumnFamilyOptions comparator 用于定义表中key的顺序 BytewiseComparator 字典序  
  merge_operator 当客户端需要使用Merge操作时,必须提供一个merge_operator nullptr 保持默认值 Pegasus没有使用Merge接口  
  compaction_filter 当compaction进行时会调用,用于删除或者修改数据。 通过compaction_filter_factory进行配置,可以使每次compaction运行时都创建一个新的compaction filter nullptr 保持默认值  
  compaction_filter_factory 每次compaction运行时都创建一个compaction filter nullptr KeyWithTTLCompactionFilterFactory 维持Pegasus中的设置
  write_buffer_size write buffer大小 64M 参见上表  
  compression 使用指定的压缩算法对block压缩 kSnappyCompression    
  bottommost_compression 用于最底层的压缩算法 kDisableCompressionOption    
  bottommost_compression_opts 可用于bottommost_compression的压缩算法配置      
  compression_opts 压缩算法的配置      
  compression_per_level 每层所采用的压缩算法   level 0和level 1不压缩  
  level0_file_num_compaction_trigger L0层文件达到该数量,触发compaction 4 data: 4 meta: 10 维持Pegasus设置值
  prefix_extractor 每次取key的前N位,根据key的前N位来构造bloom filter,用于提高范围查询效率 nullptr HashkeyTransform 维持Pegasus设置值
  max_bytes_for_level_base L1层总大小 256M 640M 维持Pegasus设置值
  disable_auto_compactions 即使关闭,manual compaction仍然可以执行 false 保持默认值  
  table_factory table factory block-based table factory NewBlockBasedTableFactory 维持Pegasus设置值
  cf_paths 该column family的SST文件的存放路径列表 保持默认值  
  compaction_thread_limiter 同时执行compaction的thread limiter,泳衣控制最大执行compaction任务的线程数量 nullptr 保持默认值  
BlockBasedTableOptions flush_block_policy_factory 用于创建flush block policy,而flush block policy用于决定什么时候flush block FlushBlockBySizePolicy 保持默认值  
  cache_index_and_filter_blocks 是否将index和filter放入block cache,如果不放入block cache,则每次在open表的时候预加载index和filter false 保持默认值  
  cache_index_and_filter_blocks_with_high_priority 在block cache中,将index和filter设置为高优先级 搭配cache_index_and_filter_blocks使用 true 保持默认值  
  pin_l0_filter_and_index_blocks_in_cache 将L0层的index和filter一直放置在block cache中 false 保持默认值  
  pin_top_level_index_and_filter 搭配cache_index_and_filter_blocks使用,当两者都是true时,将top level的index和filter一直放在block cache中,不止包括L0层 true 保持默认值  
  index_type 索引类型,用于索引Data Block/Meta Block,支持: kBinarySearch kHashSearch kTwoLevelIndexSearch kBinarySearchWithFirstKey kBinarySearch 保持默认值  
  data_block_index_type 索引类型,用于索引Data Block kDataBlockBinarySearch 保持默认值  
  data_block_hash_table_util_ratio entries/buckets比率。当data_block_hash_index_type= kDataBlockBinaryAndHash时才有效 0.75 保持默认值  
  checksum 新创建的表会使用该checksum,老表仍旧用以前的checksum kCRC32c 保持默认值  
  no_block_cache 是否关闭block cache false 保持默认值  
  block_cache block cache,可选:lru cache、clock cache   LRU Cache capacity: 10G shards: -1 (auto) 保持Pegasus中的设置
  persistent_cache 读取硬盘page所用的cache nullptr 保持默认值  
  block_cache_compressed 存放压缩block的cache nullptr 保持默认值  
  block_size data block size(非精确值),这里定义的是非压缩数据的大小,如果开启了压缩,实际大小会小于block_size 4K 保持默认值  
  block_size_deviation 创建新block的两个条件: 当前block的free space比率小于block_size_deviation 添加一条新的数据,导致当前block大小大于block_size 10 保持默认值  
  block_restart_interval BlockBuilder对key的存储是前缀压缩的,对于有序的字符串来讲,这能极大的减少存储空间。但是却增加了查找的时间复杂度,为了兼顾查找效率,每隔K个key,leveldb就不使用前缀压缩,而是存储整个key,这就是重启点(restartpoint)。 在构建Block时,block_restart_interval指定每隔几个key就直接存储一个重启点key。 16 保持默认值  
  index_block_restart_interval 同block_restart_interval 1 保持默认值  
  row_cachemetadata_block_size metadata block size,主要作用于: 使用kTwoLevelIndexSearch时的index 使用partition_filters时的filters 4K 保持默认值  
  partition_filters 需要搭配kTwoLevelIndexSearch使用 false 保持默认值  
  use_delta_encoding 在压缩block中的key时,使用delta encoding true 保持默认值  
  filter_policy bloom filter policy   bits_per_key: 10 保持Pegasus中的设置
  whole_key_filtering 使用整个key作为filter true 保持默认值  
  verify_compression 对压缩块进行解压缩以进行验证。这是一种验证模式,我们用它来检测压缩算法中的漏洞。 false 保持默认值  
  read_amp_bytes_per_bit 对于load到内存中的data block,创建一个bitmap,用于统计该block实际读取的比例 bitmap size: block_size/read_amp_bytes_per_bit/8 0 保持默认值  
  format_version table data format version 2 2或者5,根据rocksdb版本决定  
  enable_index_compression 使用压缩的方式来存储index block true 保持默认值  
  block_align 当data block大小小于page size和block size时,对齐 false 保持默认值  
  index_shortening 提高index size以交换获取更高的seek性能。 详见:https://www.bookstack.cn/read/rocksdb-6.14-en/d4af078604e06f12.md kShortenSeparators 保持默认值  

ReadOnly集群调优

RocksDB参数调优

  参数 说明 原有值 建议值 原因
DBOptions compaction_readahead_size compaction时预读,改善随机读 2MB 0 readonly集群不需要compaction
  max_background_flushes 执行flush的最大线程数 4 0 readonly集群不需要flush
  max_background_compactions 执行compaction的最大线程数 12 4 readonly集群不需要compaction
  num_levels lsm-tree层数 6 1 减少读放大 readonly集群不需要compaction,无需划分多层来优化compaction Q: 只有一层,那这一层是不是L0,查找性能是否有问题?
  write_buffer_size write buffer大小 64M 0 readonly集群没有写入,不需要write buffer
  max_write_buffer_number write buffer最大数量 3 0 readonly集群没有写入,不需要write buffer
  writable_file_max_buffer_size 可写文件的最大写缓存 1MB 0 readonly集群没有写入
  row_cache A global cache for table-level rows nullptr (disabled) LRUCache Row Cache来应付单行查询,Block Cache负责Row Cache miss的漏网之鱼,也用来应付scan 由于LSM的compaction操作会一次大批量更新大量的Data Block,导致Block Cache中大量数据短时间内失效,Row Cache可以适当弥补这种情况 经与百度kvRocks团队沟通,优化效果不理想
data ColumnFamilyOptions memtable_prefix_bloom_size_ratio 为memtable创建prefix bloom,其大小为: write_buffer_size * memtable_prefix_bloom_size_ratio 最大不超过0.25 0.1 0.1 readonly集群没有写入,不需要write buffer,更不需要为其创建prefix bloom
BlockBasedTableOptions data_block_index_type 索引类型,用于索引Data Block kDataBlockBinarySearch kDataBlockBinaryAndHash 在 Data Block 上使用 Hash 索引来提升点查询的效率。 目前Pegasus 在查找 Data Block 时使用二分查找,二分查找会导致 CPU Cache Miss,增加 CPU 使用率。如果在 Data Block 上使用 Hash 索引,可以避免二分查找,在点查询场景下降低 CPU 利用率。官方的测试数据显示:该特性可降低 21.8% CPU 利用率,提升 10% 吞吐,但会增加 4.6% 的磁盘空间占用。

Pegasus调整

  1. empty write需要关闭

其他存储引擎

可以考虑使用B+-tree及其变种的存储引擎,对读性能更加友好。

boltDB: 使用Golang开发的B+-tree KV存储引擎,被应用于influxDB项目作为底层存储

ForestDB:CouchBase使用的KV存储引擎,基于HB+-tree。HB+-tree对于长key的性能相对B+-tree更好,但是range查询性能稍差

Reference

kvrocks在RocksDB上的优化实践

ForestDB paper解读