一文掌握RocksDB的核心组件和读写路径
nanshan 2024-10-20 07:34 28 浏览 0 评论
1. RocksDB简介
- 一个带版本的Key-Value存储引擎,Key/Value采用字符串编码,Key和Value最大长度为4GB,主要针对高性能的SSD场景,也支持不同介质的存储模型
- 它是一个C++库,支持点查和范围查询,提供不同类型的ACID保障
- 将随机写转换为顺序写,带来读写放大的问题
- Key有序,支持Get(key)/Put(Key)/Delete(Key)/Merge(Key) and NewIterator()方法
- 它引入了LevelDB project(version 1.5)的部分源码,同时吸收了Apache Hbase的一些优秀的设计理念,LevelDB 的选择是:牺牲部分 Get 性能,换取强悍 Put 性能,再极力优化 Get
2. RocksDB Feature Timeline
3. RocksDB的存储结构
3.1. MemoryTable
开发库提供了三个 memtable:
- skiplist memtable
- vector memtable
- 前缀散列(prefix-hash) memtable
Vector memtable 适用于将数据批量加载到数据库中。每个写入在向量的末尾插入一个新元素; 当它刷新 memtable 到存储的时候,向量中的元素被排序并写出到 L0 中的文件。
前缀散列 memtable 允许对 gets,puts 和 scans-within-a-key-prefix 进行有效的处理。
SkipList:跳表由 William Pugh 在 1990 年提出,相关论文为:Skip Lists: A Probabilistic Alternative to Balanced Trees。跳表是一种可以取代平衡树的数据结构。跳表使用概率均衡而非严格均衡策略,从而相对于平衡树,大大简化和加速了元素的插入和删除。
3.2. SSTable
SSTable 的格式为文件本身就是一个排序的、不可变的、持久的Key/Value对Map。其中Key和value都可以是任意的byte字符串。 KeyValue 对根据固定比较规则有序地写入到文件中,文件内部分成一系列的Blocks(Block 不会太大,可自定义,默认4KB,常见的是 64KB,RocksDB对应配置项:table_options.block_size),同时具有必要的索引信息。这样就既可以顺序地读取内部 KeyValue 记录,也能够根据某个Key值进行快速定位。
如图所示,SST 文件从头到尾分成5个部分。
名称 | 占用空间 | 说明 |
Footer | 固定48字节 | 指出 IndexBlock 和 MetaIndexBlock 在文件中的偏移量信息,它是元信息的元信息,它位于 sstable 文件的尾部 |
IndexBlock | 占用一个 block 空间 | 记录了 DataBlock 相关的元信息 |
MetaIndexBlock | 占用一个 block 空间 | 各个元信息的Block,包括Filter、Properties(整个table的属性信息)、Compression dictionary、Range deletion tombstone |
MetaBlock | 可能占用多个 block空间 | 存储布隆过滤器的二进制数据 及其他元信息数据 |
DataBlock | 可能占用多个 block空间 | 存储实际的数据即键值对内容 |
3.3. Block
从上面的表格可以看出RocksDB的SSTable除了Footer外其余都是使用Block进行存储的,Block在硬盘上存储的时候,会在实际数据之后加上5个字节的额外内容:compression type、crc,如下图所示:
3.4. Bloom Filter
这里再说一下MetaBlock中的Bloom Filter,Bloom Filter的作用是对于任意集合的key,基于BitMap可以用来构建一个bit数组的算法。给出任意key,这个bit数组可以用于决定这个key是不是可能存在或者绝对不存在于这个key集合,用来减少无用的查询次数,从而加快查询的速度。
3.5. Footer
以上各部分都是 Block 的结构,只有 Footer 不同,是一个定长的格式。
序列化后,Footer的长度固定,为48个字节(旧)或53字节(新),格式如下:
// legacy footer format:
// metaindex handle (varint64 offset, varint64 size)
// index handle (varint64 offset, varint64 size)
// <padding> to make the total size 2 * BlockHandle::kMaxEncodedLength
// table_magic_number (8 bytes)
// new footer format:
// checksum type (char, 1 byte)
// metaindex handle (varint64 offset, varint64 size)
// index handle (varint64 offset, varint64 size)
// <padding> to make the total size 2 * BlockHandle::kMaxEncodedLength + 1
// footer version (4 bytes)
// table_magic_number (8 bytes)
Footer 中的信息,指明了 MetaIndexBlock 和 IndexBlock的位置,进而找到 MetaBlock 和 DataBlock。
读取 SST文件的时候,就是从文件末尾,固定读取这48或53字节,进而得到了 Footer 信息。
3.6. 磁盘文件
- *.log: 事务日志用于保存数据操作日志,可用于数据恢复
- *.sst: 数据持久换文件(此处的例子没有生成sst文件是因为第一次写数据,数据量小没触发flush操作,数据都在内存的MemoryTable中)
- MANIFEST:数据库中的 MANIFEST 文件记录数据库状态。Compaction过程会添加新文件并从数据库中删除旧文件,并通过将它们记录在 MANIFEST 文件中使这些操作持久化。
- CURRENT:记录当前正在使用的MANIFEST文件
- LOCK:rocksdb自带的文件锁,防止两个进程来打开数据库。
- IDENTITY:id
- LOG:统计日志
- OPTIONS:配置信息
3.7. 内存
RocksDB的内存大致有如下四个区:
- Block Cache
- Indexes and bloom filters
- Memtables
- Blocked pinned by iterators
Block Cache
RocksDB 的数据的缓存,这个缓存可以在多个 RocksDB 的实例下缓存。一般默认的Block Cache 中存储的值是未压缩的,而用户可以再指定一个 Block Cache,里面的数据可以是压缩的。用户访问数据先访问默认的 Block Cache,待无法获取后再访问用户 Cache,用户 Cache 的数据可以直接存入 page cache 中。
Cache 有两种:LRUCache 和 BlockCache。Block 分为很多 Shard,以减小竞争,所以 shard 大小均匀一致相等,默认 Cache 最多有 64 个 shards,每个 shard 的 最小 size 为 512k,总大小是 8M,类别是 LRU。
std::shared_ptr<Cache> cache = NewLRUCache(capacity);
BlockedBasedTableOptions table_options;
table_options.block_cache = cache;
Options options;
options.table_factory.reset(new BlockedBasedTableFactory(table_options));
这个 Cache 是不压缩数据的,用户可以设置压缩数据 BlockCache,方法如下:
table_options.block_cache_compressed = cache;
如果 Cache 为 nullptr,则RocksDB会创建一个,如果想禁用 Cache,可以设置如下 Option:
table_options.no_block_cache = true;
默认情况下RocksDB用的是 LRUCache,大小是 8MB, 每个 shard 单独维护自己的 LRU list 和独立的 hash table,以及自己的 Mutex。
RocksDB还提供了一个 ClockCache,每个 shard 有自己的一个 circular list,有一个 clock handle 会轮询这个 circular list,寻找过时的 kv,如果 entry 中的 kv 已经被访问过则可以继续存留,相对于 LRU 好处是无 mutex lock,circular list 本质是 tbb::concurrenthashmap,从 benchmark 来看,二者命中率相似,但吞吐率 Clock 比 LRU 稍高。
Block Cache初始化之时相关参数:
- capacity 总的内存使用量
- num_shards_bits 把 key 的前 n bits 作为 shard id,则总 shard 的数目为 2 ^ num_shards_bits;
- strict_capacity_limit 在一些极端情况下 block cache 的总体使用量可能超过 capacity,如在对 block 进行读或者迭代读取的时候可能有插入数据的操作,此时可能因为加锁导致有些数据无法及时淘汰,使得总体capacity超标。如果这个选项设置为 true,则此时插入操作是被允许的,但有可能导致进程 OOM。如果设置为 false,则插入操作会被 refuse,同时读取以及遍历操作有可能失败。这个选项对每个 shard 都有效,这就意味着有的 shard 可能内存已满, 别的 shard 却有很多空闲。
- high_pri_pool_ratio block中为高优先级的 block 保留多少比例的空间,这个选项只有 LRU Cache 有。
默认情况下 index 和filter block 与 block cache 是独立的,用户不能设定二者的内存空间使用量,但为了控制 RocksDB 的内存空间使用量,可以用如下代码把 index 和 filter 也放在 block cache 中:
BlockBasedTableOptions table_options;
table_options.cache_index_and_filter_blocks = true;
Indexes and bloom filters
Index 由 key、offset 和 size 三部分构成,当 Block Cache 增大 Block Size 时,block 个数必会减小,index 个数也会随之降低,如果减小 key size,index 占用内存空间的量也会随之降低。
filter是 bloom filter 的实现,如果假阳率是 1%,每个key占用 10 bits,则总占用空间就是 num_of_keys * 10 bits,如果缩小 bloom 占用的空间,可以设置 options.optimize_filters_for_hits = true,则最后一个 level 的 filter 会被关闭,bloom 占用率只会用到原来的 10% 。
结合 block cache 所述,index & filter 有如下优化选项:
- cache_index_and_filter_blocks 这个 option 如果为 true,则 index & filter 会被存入 block cache,而 block cache 中的内容会随着 page cache 被交换到磁盘上,这就会大大降低 RocksDB的性能,把这个 option 设为 true 的同时也把 pin_l0_filter_and_index_blocks_in_cache 设为 true,以减小对性能的影响。
如果 cache_index_and_filter_blocks 被设置为 false (其值默认就是 false),index/filter 个数就会受 max_open_files 影响,官方建议把这个选项设置为 -1,以方便 RocksDB 加载所有的 index 和 filter 文件,最大化程序性能。
可以通过如下代码获取 index & filter 内存量大小:
std::string out;
db->GetProperty(“rocksdb.estimate-table-readers-mem”, &out);
Memtable
memtable 则是写 buffer,所有 kv 首先都会被写进 memtable,其 size 是 write_buffer_size。 memtable 占用的空间越大,则写放大效应越小,因为数据在内存被整理好,磁盘上就越少的内容会被 compaction。如果 memtable 磁盘空间增大,则 L1 size 也就随之增大,L1 空间大小受 max_bytes_for_level_base option 控制。
可以通过如下代码获取 memtable 内存量大小:
std::string out;
db->GetProperty(“rocksdb.cur-size-all-mem-tables”, &out);
Blocks pinned by iterators
这部分内存空间一般占用总量不多,但是如果有 100k 之多的transactions 发生,每个 iterator 与一个 data block 外加一个 L1 的 data block,所以内存使用量大约为 num_iterators * block_size * ((num_levels-1) + num_l0_files)。
可以通过如下代码获取 Pin Blocks 内存量大小:
table_options.block_cache->GetPinnedUsage();
4. I/O流
4.1. 写流程
rocksdb写入时,直接以append方式写到WAL文件以及memtable,随即返回,因此非常快速。memtable达到一定阈值后切换为Immutable Memtable,只能读不能写。
Immutable memtable触发阈值后,后台Flush线程负责按照时间顺序将Immutable Memtable刷盘 生成Level 0 SST,Level 0 SST触发阈值后,经合并操作(compaction)生成level 1 SST,level 1 SST 合并操作生成level 2 SST,以此类推,生成level n SST。流程如下:
同步写 与 异步写
默认情况下,RocksDB 的写是异步的:仅仅把数据写进了操作系统的缓存区就返回了,而这些数据被写进磁盘是一个异步的过程。如果为了数据安全,可以用如下代码把写过程改为同步写:
rocksdb::WriteOptions write_options;
write_options.sync = true;
db->Put(write_options, …);
这个选项会启用 Posix 系统的 fsync(...) or fdatasync(...) or msync(..., MS_SYNC) 等函数。
异步写的吞吐率是同步写的一千多倍。异步写的缺点是机器或者操作系统崩溃时可能丢掉最近一批写请求发出的由操作系统缓存的数据,但是 RocksDB 自身崩溃并不会导致数据丢失。而机器或者操作系统崩溃的概率比较低,所以大部分情况下可以认为异步写是安全的。
RocksDB 由于有 WAL 机制保证,所以即使崩溃,其重启后会进行写重放保证数据一致性。如果不在乎数据安全性,可以把 write_option.disableWAL 设置为 true,加快写吞吐率。
RocksDB 调用 Posix API fdatasync() 对数据进行异步写。如果想用 fsync() 进行同步写,可以设置 Options::use_fsync 为 true。
4.2. 读流程:
按照 memtable --> Level 0 SST–> Level 1 SST --> … -> Level n SST的
顺序读取数据。这和记录的新旧顺序是一的。因此只要在当前级别找到记录,就可以返回。
4.3. Flush流程
简单来说在RocksDB中,每一个ColumnFamily都有自己的Memtable,当Memtable超过固定大小之后(或者WAL文件超过限制),它将会被设置为Immutable Memtable,然后会有后台的线程启动来刷新这个Immutable Memtable到磁盘(SST)。
在下面这几种条件下RocksDB会flush Memtable到磁盘:
- 当某一个Memtable的大小超过write_buffer_size
- 当所有的Memtable的大小超过db_write_buffer_size
- 当WAL文件的大小超过max_total_wal_size,我们需要清理WAL,因此此时我们需要将此WAL对应的数据都刷新到磁盘,也是刷新Memtable
4.4. Compaction操作
Compaction操作的具体作用:
- 数据合并迁移:首先当上层level的sst文件数量或者大小达到阈值时,就会触发指定的sst文件的合并并迁移到下一层。每一层都会检查是否需要进行compaction,直到数据迁移到最下层
- 数据真删:LSM树的特点决定数据的修改和删除都不是即时的真删,而是写入一条新的数据进行冲抵。这些数据只会在compaction时才会真正删除(HBase是在major compaction中才会删除,minor compaction不会进行真删),所以compaction能释放空间,减少LSM树的空间放大,但是代价就是写放大,需要根据业务场景要求通过参数来调整两者之间的关系,平衡业务与性能。
- 冷热数据管理:RocksDB的数据流向是从Memtable到level 0 最后到 level N,所以数据查询时也是通过这个路径进行的。由于业务上查询大多是热数据的查询,所以数据的冷热管理就显得很必要,能很大程度上提高查询效率;而且由于各个level的sst文件可以使用不同的压缩算法,所以可以根据自己的业务需求进行压缩算法的配置,达到最佳性能。
LSM tree相关的经典压缩算法有下面几种:经典Leveled,Tiered,Tiered+Leveled,Leveled-N,FIFO。除了这些,RocksDB还额外实现了Tiered+Leveled和termed Level,Tiered termed Universal,FIFO。这些算法各有各的特点,适用于不同的场景,不同的 compaction 算法,可以在空间放大、读放大和写放大之间这三个LSM tree的"副作用"中进行取舍,以适应特定的业务场景。大家可以按需选择,如果没有特殊需求,开箱即用即可。至于每一种压缩算法的具体方式以及实现将会在高级特性篇进行讲解。
Compaction算法
主要两个类型的LSM树合并算法:
Leveled
leveled 合并,这个是RocksDB的默认策略
leveled 算法的特点是以读放大和写放大为代价最小化空间放大。
LSM-tree 可以看作是包含若干 level 的序列,每个 level 是仅包括1个 sorted run。相邻 level 的大小之比通常被我们称为 fanout(扇出),当不同 level 之间的 fanout 相同时,LSM-tree 的写放大最小。compaction 选择 L(n) 的数据,与原有 L(n+1) 的数据进行合并,得到新的 L(n+1) 数据。每次 compaction 的最大写放大系数等同于 fanout。
Tiered
一种替代合并策略,有时候被叫做“size tiered”或者“tiered”
Tiered合并通过增加读放大和空间放大,来最小化写放大 。
LSM-tree 依然可以看作是包含若干 level 的序列,每个 level 包括 N 个 sorted run。L(n) 的 sorted run 大小是 L(n-1) 的 N 倍。compaction 通常选择 L(n) 的数据合并得到新的 sorted run 输出到 L(n+1),但并不与 L(n+1) 的已有数据进行合并。每次 compaction 的最大写放大系数是 1。
两种算法的主要差别在于,leveled合并倾向于更加频繁的把小的排序结果合并到大的里面,而“tiered”等待多个大小接近的排序结果,然后把它们合并到一起。
Tiered+Leveled
Tiered+Leveled会有比leveled更小的写放大,以及比teired更小的空间放大。
Tiered+Leveled实现方式是一种混合实现,在小的层使用tiered,在大的层使用leveld。具体哪一层切换tiered和leveled可以非常灵活。
RocksDB中的Leveled合并也是Tiered+Leveled。一个memtable落盘过程类似于tiered合并——memtable的输出在L0构建一个新的排序结果并且不需要读/重写L0上已经存在的排序结果。根据level0_file_num_compaction_trigger的配置,L0可以有多个sort run,所以L0是Teired的。 其它层为Leveled。
FIFO Compaction
FIFO Style Compaction 是最简单的合并策略。很适合用于保存低开销的事件日志数据(例如查询日志)。当文件总大小超过配置值 CompactionOptionsFIFO::max_table_files_size (默认值为 1GB) 时,最早的 SST 文件将会被删除。
使用FIFO时,所有的文件都位于 L0,因此SST文件过多,导致查询性能急剧下降。
开启 CompactionOptionsFIFO.allow_compaction 参数,可以触发 L0 IntraCompaction,每次至少选取 level0_file_num_compaction_trigger 个 SST 文件进行合并,从而减少文件数量。
FIFO Compaction with TTL
FIFO Compaction with TTL 在 FIFO compaction 的基础之上,提供 SST 文件级别的过期删除功能。当 SST 的最新的 key 存在时间超过 mutable_cf_options.ttl,则该 SST 文件将会在 TTL compaction 中被删除。
Write Stall
Too many memtables
- 写限速: 如果max_write_buffer_number大于3,将要flush的memtables大于等于max_write_buffer_number - 1,write会被限速。
- 禁写: memtable个数大于等于max_write_buffer_number,触发禁写,等到flush完成后允许写入
Too many level-0 SST files
- 写限速: L0文件数量达到level0_slowdown_writes_trigger,触发写限速。
- 禁写: L0文件数量达到level0_stop_writes_trigger,禁写。
Too many pending compaction bytes
- 写限速: 等待compaction的数据量达到soft_pending_compaction_bytes,触发写限速。
- 禁写: 等待compaction的数据量达到hard_pending_compaction_bytes,触发禁写。
4.5. Compression操作
使用options.compression来指定使用的压缩方法。默认是Snappy。但是大多数情况下LZ4总是比Snappy好。之所以把Snappy作为默认的压缩方法,是为了与旧版本保持兼容。LZ4/Snappy是轻量压缩,所以在CPU使用率和存储空间之间能取得一个较好的平衡。
如果你想要进一步减少存储的使用并且你有一些空闲的CPU,你可以尝试设置options.bottommost_compression来使用一个更加重量级的压缩。最底层会使用这个方式进行压缩。通常最底层会保存大部分的数据,所以用户通常会选择偏向空间的设定,而不是花费cpu在各个层压缩所有数据。我们推荐使用ZSTD。如果没有,Zlib是第二选择。
如果你有大量空闲CPU并且希望同时减少空间和写放大,把options.compression设置为重量级的压缩方法,所有层级都生效。推荐使用ZSTD,如果没有就用Zlib
当然也可以通过一个已经过期的遗留选项options.compression_per_level,你可以有更好的控制每一层的压缩方式。当这个选项被使用的时候,options.compression不会再生效,但是正常情况下这个是不必要的,除非你有极特殊的需求或者性能优化要求。
最后可以通过把BlockBasedTableOptions.enable_index_compression设置为false来关闭索引的压缩。
4.5. 离线Ingest
Ingest实现上主要是两部分:创建SST文件和导入SST文件:
4.5.1. 创建SST文件
创建SST文件的过程比较简单,创建了一个SstFileWriter对象之后,就可以打开一个文件,插入对应的数据,然后关闭文件即可。 写文件的过程比较简单,但是要注意下面三点:
- 传给SstFileWriter的Options会被用于指定表类型,压缩选项等,用于创建sst文件。
- 传入SstFileWriter的Comparator必须与之后导入这个SST文件的DB的Comparator绝对一致。
- 行必须严格按照增序插入
4.5.2. 导入SST文件
导入SST文件也非常简单,需要做的只是调用IngestExternalFile()然后把文件地址封装成vector以及相关的options传入参数即可。下面是IngestExternalFile()的实现逻辑:
- 把文件拷贝,或者链接到DB的目录。
- 阻塞DB的写入(而不是跳过),因为我们必须保证db状态的一致性,所以我们必须确保,我们能给即将导入的文件里的所有key都安全地分配正确的序列号。
- 如果文件的key覆盖了memtable的键范围,把memtable进行flush操作。
- 把文件安排到LSM树的最合适的层级。
- 给文件赋值一个全局序列号。
- 重新启动DB的写操作。
为了减少compaction的压力,我们总是想将目标的sst文件写入最合适的层级,即合适写入的最低层级,下面三个条件作为约束可以选出合适的层级:
- 文件可以安排在这个层
- 这个文件的key的范围不会覆盖上面任何一层的数据
- 这个文件的key的范围不会覆盖当前层正在进行压缩
另外,5.5以后的新版本的RocksDB的IngestExternalFile加载一个外部SST文件列表的时候,支持下层导入,意思是如果ingest_behind为true,那么重复的key会被跳过。在这种模式下,我们总是导入到最底层。文件中重复的key会被跳过,而不是覆盖已经存在的key。
相关推荐
- 实战派 | Java项目中玩转Redis6.0客户端缓存
-
铺垫首先介绍一下今天要使用到的工具Lettuce,它是一个可伸缩线程安全的redis客户端。多个线程可以共享同一个RedisConnection,利用nio框架Netty来高效地管理多个连接。放眼望向...
- 轻松掌握redis缓存穿透、击穿、雪崩问题解决方案(20230529版)
-
1、缓存穿透所谓缓存穿透就是非法传输了一个在数据库中不存在的条件,导致查询redis和数据库中都没有,并且有大量的请求进来,就会导致对数据库产生压力,解决这一问题的方法如下:1、使用空缓存解决对查询到...
- Redis与本地缓存联手:多级缓存架构的奥秘
-
多级缓存(如Redis+本地缓存)是一种在系统架构中广泛应用的提高系统性能和响应速度的技术手段,它综合利用了不同类型缓存的优势,以下为你详细介绍:基本概念本地缓存:指的是在应用程序所在的服务器内...
- 腾讯云国际站:腾讯云服务器如何配置Redis缓存?
-
本文由【云老大】TG@yunlaoda360撰写一、安装Redis使用包管理器安装(推荐)在CentOS系统中,可以通过yum包管理器安装Redis:sudoyumupdate-...
- Spring Boot3 整合 Redis 实现数据缓存,你做对了吗?
-
你是否在开发互联网大厂后端项目时,遇到过系统响应速度慢的问题?当高并发请求涌入,数据库压力剧增,响应时间拉长,用户体验直线下降。相信不少后端开发同行都被这个问题困扰过。其实,通过在SpringBo...
- 【Redis】Redis应用问题-缓存穿透缓存击穿、缓存雪崩及解决方案
-
在我们使用redis时,也会存在一些问题,导致请求直接打到数据库上,导致数据库挂掉。下面我们来说说这些问题及解决方案。1、缓存穿透1.1场景一个请求进来后,先去redis进行查找,redis存在,则...
- Spring boot 整合Redis缓存你了解多少
-
在前一篇里面讲到了Redis缓存击穿、缓存穿透、缓存雪崩这三者区别,接下来我们讲解Springboot整合Redis中的一些知识点:之前遇到过,有的了四五年,甚至更长时间的后端Java开发,并且...
- 揭秘!Redis 缓存与数据库一致性问题的终极解决方案
-
在现代软件开发中,Redis作为一款高性能的缓存数据库,被广泛应用于提升系统的响应速度和吞吐量。然而,缓存与数据库之间的数据一致性问题,一直是开发者们面临的一大挑战。本文将深入探讨Redis缓存...
- 高并发下Spring Cache缓存穿透?我用Caffeine+Redis破局
-
一、什么是缓存穿透?缓存穿透是指查询一个根本不存在的数据,导致请求直接穿透缓存层到达数据库,可能压垮数据库的现象。在高并发场景下,这尤其危险。典型场景:恶意攻击:故意查询不存在的ID(如负数或超大数值...
- Redis缓存三剑客:穿透、雪崩、击穿—手把手教你解决
-
缓存穿透菜小弟:我先问问什么是缓存穿透?我听说是缓存查不到,直接去查数据库了。表哥:没错。缓存穿透是指查询一个缓存中不存在且数据库中也不存在的数据,导致每次请求都直接访问数据库的行为。这种行为会让缓存...
- Redis中缓存穿透问题与解决方法
-
缓存穿透问题概述在Redis作为缓存使用时,缓存穿透是常见问题。正常查询流程是先从Redis缓存获取数据,若有则直接使用;若没有则去数据库查询,查到后存入缓存。但当请求的数据在缓存和数据库中都...
- Redis客户端缓存的几种实现方式
-
前言:Redis作为当今最流行的内存数据库和缓存系统,被广泛应用于各类应用场景。然而,即使Redis本身性能卓越,在高并发场景下,应用于Redis服务器之间的网络通信仍可能成为性能瓶颈。所以客户端缓存...
- Nginx合集-常用功能指导
-
1)启动、重启以及停止nginx进入sbin目录之后,输入以下命令#启动nginx./nginx#指定配置文件启动nginx./nginx-c/usr/local/nginx/conf/n...
- 腾讯云国际站:腾讯云怎么提升服务器速度?
-
本文由【云老大】TG@yunlaoda360撰写升级服务器规格选择更高性能的CPU、内存和带宽,以提供更好的处理能力和网络性能。优化网络配置调整网络接口卡(NIC)驱动,优化TCP/IP参数...
- 雷霆一击服务器管理员教程
-
本文转载莱卡云游戏服务器雷霆一击管理员教程(搜索莱卡云面版可搜到)首先你需要给服务器设置管理员密码,默认是空的管理员密码在启动页面进行设置设置完成后你需要重启服务器才可生效加入游戏后,点击键盘左上角E...
你 发表评论:
欢迎- 一周热门
-
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
[常用工具] OpenCV_contrib库在windows下编译使用指南
-
WindowsServer2022|配置NTP服务器的命令
-
Ubuntu系统Daphne + Nginx + supervisor部署Django项目
-
WIN11 安装配置 linux 子系统 Ubuntu 图形界面 桌面系统
-
解决Linux终端中“-bash: nano: command not found”问题
-
Linux 中的文件描述符是什么?(linux 打开文件表 文件描述符)
-
NBA 2K25虚拟内存不足/爆内存/内存占用100% 一文速解
-
K3s禁用Service Load Balancer,解决获取浏览器IP不正确问题
-
- 最近发表
-
- 实战派 | Java项目中玩转Redis6.0客户端缓存
- 轻松掌握redis缓存穿透、击穿、雪崩问题解决方案(20230529版)
- Redis与本地缓存联手:多级缓存架构的奥秘
- 腾讯云国际站:腾讯云服务器如何配置Redis缓存?
- Spring Boot3 整合 Redis 实现数据缓存,你做对了吗?
- 【Redis】Redis应用问题-缓存穿透缓存击穿、缓存雪崩及解决方案
- Spring boot 整合Redis缓存你了解多少
- 揭秘!Redis 缓存与数据库一致性问题的终极解决方案
- 高并发下Spring Cache缓存穿透?我用Caffeine+Redis破局
- Redis缓存三剑客:穿透、雪崩、击穿—手把手教你解决
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)