zoukankan      html  css  js  c++  java
  • 一个异步访问redis的内存问题

    | 分类 redis  |

    遇到一个redis实例突然内存飙高的案例, 具体症状如下:

    • 客户端使用异步访问模式
    • 单个请求的回包很大,hgetall一个8M的key

    由于访问量比较大,已经登录不上redis了, 看不到具体在做什么做操, 因此使用perf来看下调用栈, 此处且按下不表。

    为何内存会飙高呢,我们线下重现一下:

    import redis
    import time
    
    r=redis.Redis("127.0.0.1", 9988)
    pipe = r.pipeline()
    key="8Mhashkey"
    for i in range(100):
        pipe.hgetall(key)
    rsp=pipe.execute()
    time.sleep(1)
    
    

    执行这个脚本若干次, 我们可以发现9988的内存瞬间升高了, 而9988本身只有一个key, 8Mhashkey。

    执行一下client list, 得到:

    可以发现,是client 的output buffer占用的大量的内存。 那为什么会出现这个现象呢? 根本原因是: redis并不是使用ping/pong的模式来处理请求。对于来自同一个连接上面的请求,并不是走如下模式:

    大专栏  一个异步访问redis的内存问题anguage-css highlighter-rouge">
    1. 接受客户端请求
    2. 处理请求,生成回包
    3. 给客户端发送回包,跳转1
    

    而是这种模式:

    // 处理请求
    1. 接受客户端请求
    2. 处理请求生成回包, 跳转1
    
    // 处理回复
    while 有回包
        把回包发给客户端
    

    也就是说, 也就是说对于同一个连接上的请求,不需要等上一个请求的回包都被发送到客户端了,才去处理下一个请求; 即使上一个请求的回包没有被发送到客户端, redis也可以去接受并处理下一个请求。 redis把这些请求的回包都保存在内存里面了,内存大小通过如下参数配置:

    client-output-buffer-limit normal 0 0 0
    

    epoll_wait在返回时, 如果客户端连接可写,则向这些客户端上面上送回包, 已经发送给客户端的回包所对应的内存会被释放。

    到此, 原因就明显了。 异步方式访问redis时,如果生成回包的速度大于客户端读取回包的速度,redis的内存就会上涨。

    突然想起来上次在SACC上面有人问我异步访问redis有什么问题,当时由于时间关系没有解释很充分。 现在看来,redis的这种网络模型,收包和回包互不阻塞的方式,在多链接的情况下,不同链接上的请求上的延时是能保证的。 唯一的问题,可能就是这个内存问题。


    上一篇     下一篇
  • 相关阅读:
    第7.10节 Python类中的实例变量定义与使用
    第7.9节 案例详解:Python类封装
    第7.8节 Python中隐秘的类封装方法
    第7.7节 案例详解:Python类继承机制
    第7.6节 Python中类的继承机制详述
    第7.5节 揭开Python类中self的面纱
    第7.4节 Python中与众不同的类
    第7.3节 Python特色的面向对象设计:协议、多态及鸭子类型
    第7.2节 关于面向对象设计的一些思考
    (独孤九剑)--流程控制
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12247634.html
Copyright © 2011-2022 走看看