• 【源码阅读】vminsert与vmstorage之间的通讯


    先说结论

    • vm-insert与vm-storage之间采用极其简单的通讯协议
      • 对于简单的场景,越简单性能越高
      • vm-insert连接到vm-storage后,先发送字符串vminsert.02,vm-storage收到后回复字符串ok,然后握手成功
      • vm-insert发送一个字节的压缩标志给vm-storage:1.默认会启用zstd压缩算法;2.除非命令行中使用-rpc.disableCompression来禁止压缩
      • 通讯协议使用:固定字节表示长度 + ZSTD压缩内容
        • ZSTD的压缩解压缩速度比最快的snappy稍慢,但是压缩率比zlib还要高。
      • 通讯协议看起来是单工的————也就是说,是请求-响应模式;无法在一个TCP通道上做到多个请求+响应。(为了简单嘛,也能理解)
      • 通讯的回包也极其简单:返回1代表成功,返回2代表存储节点只读。
    • 序列化方面:
      • vm-insert中:直接在一个buffer里面追加内容
      • 每个字段使用 length + value的形式
      • 因此序列化很快(从占用空间的维度说,并不见得比PB更好)
    • 高数据压缩比:
      • 从之前的监控数据统计来看,vm-insert进来的数据和发送到vm-storage的数据相差29倍
      • 简单协议+自定义序列化+合并发送+zstd压缩,最终达到了这个效果,牛逼
    • 合并发送:
      • vm-insert的每个http处理handle中,每个请求的所有metrics先序列化到context的buffer中
      • 然后放到connection对象的buffer中
      • connection对象的buffer达到一定长度后,进行压缩,然后发送给storage
      • 有坑:vm-insert转发到vm-storage必然有一定时间的延迟;且vm-insert突然崩溃的话,必然丢失部分数据。
        • 在监控数据极少的情况下,会不会一直等待?还没有看到对这种情况的处理。
    • 并发的处理:
      • http handle部分的处理是并行的,放到connection的buffer的时候加锁了(还有挺多细节没看明白)
    • vm-storage的寻址:
      • 对所有的label_name + label_value + projectid + accountid进行了hash运算
      • 使用了性能吊炸天的xxhash库
      • 使用uint64的hashcode,然后通过hash一致性算法,取得后端多个storage节点的下标
      • 因此:同一个time series被固定的发到一个后端节点上。storage节点的增加和减少只影响部分time series
      • 理论上可以修改源码,比如只对__name__取hashcode,这样的话,同一个监控项会被发到同一个存储节点上
    • 后端容灾的处理:
      • 如果发送给vm-storage失败,会对数据反序列化,然后重新计算hashcode,然后重新选vm-storage节点。
        • 新增vm-storage只能重启vm-insert,因此不存在对新服务发现的需要
      • vm-storage节点的侦测、迁移、恢复的逻辑,还没看到。

    2022-01-20补充:

    • vm-insert中,有N个后端节点,就会建立N个netstorage.storageNode对象
      • storageNode对象存在一个最多100MB的发送buffer
      • buffer中的数据采用了及其简单的序列化算法。且发送前会使用ZSTD压缩协议。
      • vm-insert发送数据到vm-storage的时机有两个:
        • storageNode中的buffer已经写满了(最多100MB,这个条件比较难触发,通常在后端已经出现问题的时候才会发生)
        • 每200毫秒发送一次。因此,如果你使用了VM体系的监控系统,采样率超过每秒5次毫无意义,会在vm-insert这里产生最多200ms的延迟。
      • 因为vm-insert会缓存数据,如果vm-insert节点突然崩溃,会损失最多200毫秒的采样数据。如果有N个vm-insert节点,就损失就再减少为N分之一。
    • http协议的remote-write的执行细节:
      • metric的数据,不会检查timestamp的合法性。(vm-storage层面是否会检查?还没看到)
      • 序列化好所有的label name和label value后,会使用xxhash计算一个uint64类型的hash值
        • 如果vm-insert级联,hash计算还会额外设置一个种子值
      • 全部序列化之后,加锁,copy数据到storageNode对象的发送buffer中
    • 容灾调度的细节:
      • 如果某个storageNode对象对应的后端不可用,遍历所有的可用的后端,然后排出掉最近发送过的节点
      • 这样的调度模式可能会带来这样一些问题:
        • 如果某个vm-storage节点长期不可用,vm-insert的fast path的处理路径就会无效,从而导致vm-insert的处理性能降低
        • 如果把原来第 x 个节点的数据,轮询的分给其他节点,可能在短期内导致所有节点的time series数量猛增。
        • vm-insert没有提供动态增减节点的机制,不够灵活
  • 相关阅读:
    从相册中获取图片
    Android中bitmap的相关处理
    Sublime Text的使用代码块安装的模块
    angular之控制器(0)
    13.程序集篇
    12.序列化与反序列篇
    11.泛型篇
    10.集合篇
    9.多态篇
    8.继承篇
  • 原文地址:https://www.cnblogs.com/ahfuzhang/p/15801975.html
Copyright © 2020-2023  润新知