blog review 第二十五期
启发式是不是就是拍脑袋靠经验?
jump table怎么翻译?跳转表?
唉 2020年我从老东家的shared disk离开,去新工作做shared nothing的项目,最近这些年又变回shared disk了 降本增效
我这些年可以说是原地踏步了
The Taming of the B-Trees
https://github.com/scylladb/scylladb/blob/master/docs/dev/row_cache.md
用std::map 来MVCC,二分快一些,但没有btree缓存友好,介绍了一些背景
branch-free 二分 https://algorithmica.org/en/eytzinger 话说这个博客我一直没看完
Cachelines and Striped Locks
写了个分片锁,然后发现得加cachelinepad 避免false sharing,老生常谈的玩意
内存使用高 磁盘IO延迟高
page cache = /proc/meminfo Active(file) + Inactive(file) + Shmem + SwapCached
观察Active(file) + Inactive(file)占用,占用低说明内存不够用了,文件没法缓存,会发生内存驱逐
cat /proc/vmstat | grep allocstall 观察数字 |
网络流定位 https://access.redhat.com/sites/default/files/attachments/20150325_network_performance_tuning.pdf
文档有点旧但是指引思路没啥问题
- NIC网卡buffer -> 硬中断 -> 软中断 -> app socket queue <- app
cat /proc/interrupts 看硬件断,可以grep网卡 关注中断分布是否均匀 -> irqbalance?也可以自己控制亲和性
cat /proc/softirqs 看软中断 可以grap TX RX看网卡 -> CPU负?是否快速处理了中断 sysctl -w net.core.netdev_budget=600 默认300
cat /proc/net/softnet_stat 看第三列的数字
- 常用工具
netstat/ip/ethtool/ss/dropwatch
netstat -s // 看错误
ethtool -S eth1 // 看错误
-
setsockopt(SO_RCVBUF) 会覆盖系统socket buffer策略
-
网卡流控暂停帧?没这个必要吧改动较大
-
硬件中断合并
ethtool -C eth1 延迟敏感的可以调小
- 关闭自适应中断
ethtool -C eth3 adaptive-rx off rx-usecs 0 rx-frames 0
- 协议栈前队列满 调整参数
sysctl -w net.core.netdev_max_backlog=X
- RXTX Buffer
ethtool -G eth1 rx 8192 tx 8192
- 传输队列调整
ip link set dev eth1 txqueuelen 2000
- TCP CPU算力转移到网卡,比如TSO之类的
ethtool -K ethi
- TCP时间戳
sysctl -w net.ipv4.tcp_timestamps = 1
- TCP SACK 可能有多余计算,取决于集群网络环境
sysctl -w net.ipv4.tcp_sack=0
- TCP窗口缩放
sysctl -w net.ipv4.tcp_window_scaling = 1
- TCP rmem
sysctl -w net.ipv4.tcp_rmem=“16384 349520 16777216”
sysctl -w net.core.rmem_max=16777216
- TCP listen backlog
sysctl -w net.core.somaxconn = 128
sysctl -w net.core.somaxconn = 2048
sysctl -w net.core.somaxconn = 2048
- 改善 socket buffer溢出 sysctl -w net.ipv4.tcp_adv_win_scale=1
赌你看不懂:分布式存储系统的数据强一致性挑战
- 你是否遇到过数据越删越多或者已经删除了很多数据但是空间长时间不能释放的问题呢?
我们知道 RocksDB 的删除操作其实只是写入了一个 tombstone 标记,而这个标记往往只有被 compact 到最底层才能被丢掉的。 所以这里的问题很可能是由于层数过多或者每一层之间的放大系数不合理导致上面的层的 tombstone 不能被推到最底层。 这时候大家可以考虑开启 level_compaction_dynamic_level_bytes这个参数来解决。
- 你是否遇到过 iterator 的抖动导致的长尾问题呢?
这个可能是因为 iterator 在释放的时候需要做一些清理工作的原因,尝试开启 avoid_unnecessary_blocking_io 来解决。
- 你是否遇到过 ingest file 导致的抖动问题?
在 ingest file 的过程中,RocksDB 会阻塞写入,所以如果 ingest file 的某些步骤耗时很长就会带来明显的抖动。
例如如果 ingest 的 SST 文件跟 memtable 有重叠,则需要先把 memtable flush 下来,而这个过程中都是不能写入的。
所以为了避免这个抖动问题,我们会先判断需要 ingest 的文件是否跟 memtable 有重叠,
如果有的话会在 ingest 之前先 flush,等 flush 完了再执行 ingest。而这个时候 ingest 之前的 flush 并不会阻塞写,所以也就避免了抖动问题。
- 你是否遇到过某一层的一个文件跟下一层的一万个文件进行 compaction 的情况呢?
RocksDB 在 compaction 生成文件的时候会预先判断这个文件跟下一层有多少重叠,
来避免后续会产生过大的 compaction 的问题。然而,这个判断对 range deletion 是不生效的,
所以有可能会生成一个范围非常广但是实际数据很少的文件,那么这个文件再跟下一层 compact 的时候就会涉及到非常多的文件,
这种 compaction 可能需要持续几个小时,期间所有文件都不能被释放,磁盘很容易就满了。由于我们需要 delete range 的场景很有限,
所以目前我们通过 delete files in range + scan + delete 的方式来替换 delete range。虽然这种方式比 delete range 开销更大,但是更加可控。
虽然也可以通过 compaction filter 来进一步优化,但是实现比较复杂,我们暂时没有考虑
从 perftune.py 说起
介绍网卡绑定亲和性的,有点意思
io_uring + Seastar
这哥们对seastar io_uring理解挺深的
Evaluating SIMD Compiler-Intrinsics for Database Systems
编译器帮忙优化SIMD,而不是自己手写SIMD
Alex Gallego — Co-designing Raft + thread-per-core execution model for the Kafka-API
ppt https://assets.ctfassets.net/oxjq45e8ilak/4tsyJRt4PCecrG78b0wESv/a623a848945e878f4a385eb9ce8c4ec7/hydraconf_-alex_gallego-_2021.pdf
很有意思。fdatasync tls,各种设计省share/拷贝
感觉可以把这个raft抠出来。里面的rpc设计也挺有意思的,ciste.rocks(magic_get) + seastar
PolygonStore,一款“业务驱动”而生的 NoSQL 多模数据库产品
真多模,我脑子里想的多模就这样的
怎么实现一种kv支持多种API来查询呢?这个映射关系没说
我猜,可能每条KV有api_type,然后不同的api_type 额外生成辅助数据,比如图的采样?
The Hallucinated Rows Incident
他们实现了一个differentflow的玩意,然后底层数据库是rocksdb。 rocksdb存的都是string,来排序
上层的数据rocksdb没捞出来,排序模式不同导致
Take Out the TraChe: Maximizing (Tra)nsactional Ca(che) Hit Rate
简单说是事务用到的是一组key,而缓存系统是单key LRU/LFU 最多2Q/ARC防颠簸
但这种cache对于事务来说并不能很好的cover住,可能三个key事务,有一个没缓存住
短板导致延迟升高,这种场景下,普通的缓存命中率已经无法概括这种场景,提出了THR 来评估缓存命中率
感觉就是另一种cache系统,根据事务的组key概念来延长cache的淘汰时间
Take care of system clock change
简单说就是condvar 用的时钟不是steady_lock 是systemlock 这种可能存在改动导致wait失效/延长
这个BUG直到 gcc10才修 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861
FAST19 | DistCache:分布式缓存
cache+ db架构 cache db也有一层cache
想法是分别查两个,来规避热点问题
cache的分片策略和db cache的分片策略不同,这样key的热点均摊开,然后power-of-two-choices,上下选一个负载低的
问题在于,一般来说这种设计 db层的cache可能缓存效果并不好,如果db层cache和前段的cache一样大,岂不是cache两倍数据,成本谁受得了
然后请求是两层路由随便选一个负载低的,客户端得改造
两层cache,真有钱
False sharing and 128-byte alignment/padding
看代码 https://github.com/facebook/folly/blob/main/folly/lang/Align.h
“Intel® 64 and IA-32 architectures optimization reference manual”, in section 3.7.3 “Hardware Prefetching for Second-Level Cache”, about the Intel Core microarchitecture:
“Streamer — Loads data or instructions from memory to the second-level cache. To use the streamer, organize the data or instructions in blocks of 128 bytes, aligned on 128 bytes. The first access to one of the two cache lines in this block while it is in memory triggers the streamer to prefetch the pair line.”
// Memory locations within the same cache line are subject to destructive
// interference, also known as false sharing, which is when concurrent
// accesses to these different memory locations from different cores, where at
// least one of the concurrent accesses is or involves a store operation,
// induce contention and harm performance.
//
// Microbenchmarks indicate that pairs of cache lines also see destructive
// interference under heavy use of atomic operations, as observed for atomic
// increment on Sandy Bridge.
//
// We assume a cache line size of 64, so we use a cache line pair size of 128
// to avoid destructive interference.
//
// mimic: std::hardware_destructive_interference_size, C++17
constexpr std::size_t hardware_destructive_interference_size =
(kIsArchArm || kIsArchS390X) ? 64 : 128;
理解 std::hardware_destructive_interference_size和std::hardware_constructive_interference_size
destructive 避免false sharing constructive 尽可能的true sharing
false sharing 128更明显一些,64可能还是有影响。
如何使用? https://github.com/facebook/folly/blob/main/folly/ProducerConsumerQueue.h
using AtomicIndex = std::atomic<unsigned int>;
char pad0_[hardware_destructive_interference_size];
const uint32_t size_;
T* const records_;
alignas(hardware_destructive_interference_size) AtomicIndex readIndex_;
alignas(hardware_destructive_interference_size) AtomicIndex writeIndex_;
char pad1_[hardware_destructive_interference_size - sizeof(AtomicIndex)];
一次奇怪的 page cache 大量突然回收的 bug
简单说就是抓进程
pidstat -r 10
抓到个采集metric的服务导致的pagecache回收
redis大量的连接创建导致cpu飙高
复现
for((;;));do redis-cli ${ip} -p 6379 quit ;done
简单说就是大量连接导致,redis框架对于这种滥用连接没有限制,某些框架可能会做个连接池,超出就拒绝?