• 云计算之路-阿里云上:读取缓存时的“黑色0.1秒”团队


    看到标题中的“0.1秒”,你也许会呲之以鼻:不会吧,0.1秒也要计较,不是吃饱撑着,是没吃饱也撑着。

    依然没撑着!在memcached应用场景中,响应速度是处于1ms级别的,0.1s可是比1ms慢了100倍啊。

    如果你不相信1ms级别,请看这篇文章(微博CacheService架构浅析)中的一段话:

    目前微博平台部分业务子系统的Cache服务已经迁移到了CacheService之上,它在实际的运行过程中也取得了良好的性能表现,目前整个集群在线上每天支撑着超过300W的QPS,平均响应耗时低于1ms。

    进入正题。。。

    自从使用阿里云以来,我们一直被一个问题困扰——日志中时不时会记录读取缓存超过100ms的情况。

    一开始我们用的是云服务器跑memcached作为缓存服务,当时以为是虚拟机跑memcached性能跟不上,于是就期待阿里云的缓存服务能解决这个问题。

    可是等到阿里云推出OCS(开放缓存服务),换上去之后,读取缓存超过100ms的情况还是会出现。

    难道是memcached客户端EnyimMemcached的问题,看了EnyimMemcached的源代码,也没看出问题,EnyimMemcached只是Socket读取数据然后二进制反序列化,这地方再慢也不至于超过100ms吧。

    百思不得其解,这个问题就一直放着。。。

    今天早上发现日志中记录了00:00-8:00之间竟然发生了近1200次的读取缓存超过100ms的情况,几乎每分钟都出现。昨天刚刚给“黑色n秒”问题找到了最合理的猜想,正处在劲头上。于是趁热打铁,给“黑色n秒”家族添加了一位新成员——“黑色0.1秒”,好好分析一下。

    那分析从何处开始呢?我们把怀疑对象锁定在了网络TCP层,所以从抓包开始。

    对于Windows系统,最强大的抓包工具非Wireshark莫属。

    在云服务器上启动Wireshark,选择与OCS进行通信的内网接口,配置Capture Filter只抓取与OCS进行通信的TCP包。

    wireshark配置

    Wireshark Capture运行没多久,就出现了一次“黑色0.1秒”。

    应用日志

    成功抓到了包,根据日志中时间点及缓存Key找到了对应的TCP包:

    wireshark抓包

    然后在Wireshark的右击菜单中选择“Follow TCP Strem”,只显示这个TCP流的包:

    wireshark菜单

    wireshark抓包

    结果有了一个惊人的发现:云服务器收到OCS响应包的时间是11:23:22.780498,而云服务器发出ACK确认包的时间却是11:23:793597,竟然相差了130.9913.099ms(不好意思,这个地方犯了一个低级错误,应该是13ms。下面对TCP层问题的推断是错误的,我们会重新分析这个问题);而日志中缓存读取时间是132.8142ms,0.1秒都耗在了云服务器TCP层在收到包与发ACK包之间。

    这个问题应该是TCP层的问题,与上层没问题,与EnyimMemcached就更没关系了。

    为了验证这一点,我们修改了一下EnyimMemcached的源代码,在Enyim.Caching.Memcached.Protocol.Binary.BinaryResponse的Read方法中添加了一行代码System.Threading.Thread.Sleep(2000);,让EnyimMemcached在读取缓存数据时暂停2s:

    public unsafe bool Read(PooledSocket socket)
    {
        this.StatusCode = -1;
    
        if (!socket.IsAlive)
            return false;
    
        System.Threading.Thread.Sleep(2000);
    
        var header = new byte[HeaderLength];
        socket.Read(header, 0, header.Length);
    
        int dataLength, extraLength;
    
        DeserializeHeader(header, out dataLength, out extraLength);
    
        if (dataLength > 0)
        {
            var data = new byte[dataLength];
            socket.Read(data, 0, dataLength);
    
            this.Extra = new ArraySegment<byte>(data, 0, extraLength);
            this.Data = new ArraySegment<byte>(data, extraLength, data.Length - extraLength);
        }
    
        return this.StatusCode == 0;
    }

    然后在正常情况下抓包(没有出现黑色0.1秒)

    云服务器收到OCS响应包与发ACK包之间只相差了0.00002秒(0.02ms)。

    抓包数据证明了“黑色0.1秒”与EnyimMemcached没有关系,属于TCP层的问题。

    于是又引发了一个问了无数次的问题?是微软Windows的问题还是阿里云虚拟机的问题? 

    【该问题的后续分析】

    云计算之路-阿里云上:原来“黑色0.1秒”发生在socket读取数据时

    【推荐学习材料】

    Understanding TCP Sequence and Acknowledgment Numbers

  • 相关阅读:
    throw关键字
    Android WebView 调试方法
    webpack的Hot Module Replacement运行机制
    如何使用Node.js编写命令工具——以vue-cli为例
    webpack3新特性简介
    node.js如何制作命令行工具(一)
    webpack务虚扫盲
    web worker 扫盲篇
    httpd配置ResponseHeader
    针对iPhone的pt、Android的dp、HTML的css像素与dpr、设计尺寸和物理像素的浅分析
  • 原文地址:https://www.cnblogs.com/cmt/p/3719568.html
Copyright © 2020-2023  润新知