用elastic stack来分析下你的redis slowlog

redis是目前最流行的 NoSQL 内存数据库,然而如果在使用过程中出现滥用、乱用的情况,很容易发生性能问题,此时我们就要去关注慢查询日志,本文尝试给大家介绍一种通过 elastic stack 来快速分析 redis 慢查询日志的方法,希望能给大家提供帮助。

redis slowlog简介

redis是目前最流行的缓存系统,因其丰富的数据结构和良好的性能表现,被各大公司广泛使用。尽管redis性能极佳,但若不注意使用方法,极容易出现慢查询,慢查询多了或者一个20s的慢查询会导致操作队列(redis是单进程)堵塞,最终引起雪崩甚至整个服务不可用。对于慢查询语句,redis提供了相关的配置和命令。
配置有两个:slowlog-log-slower-thanslowlog-max-lenslowlog-log-slower-than是指当命令执行时间(不包括排队时间)超过该时间时会被记录下来,单位为微秒,比如通过下面的命令,就可以记录执行时长超过20ms的命令了。

config set slowlog-log-slower-than 20000

slowlog-max-len是指redis可以记录的慢查询命令的总数,比如通过下面的命令,就可以记录最近100条慢查询命令了。

config set slowlog-max-len 100

操作慢查询的命令有两个:slowlog get [len]slowlog resetslowlog get [len]命令获取指定长度的慢查询列表。

redis 127.0.0.1:6379> slowlog get 2
1) 1) (integer) 14
   2) (integer) 1309448221
   3) (integer) 15
   4) 1) "ping"
2) 1) (integer) 13
   2) (integer) 1309448128
   3) (integer) 30
   4) 1) "slowlog"
      2) "get"
      3) "100"

上面返回了两个慢查询命令,其中每行的含义如下:

  1. 第一行是一个慢查询id。该id是自增的,只有在 redis server 重启时该id才会重置。
  2. 第二行是慢查询命令执行的时间戳
  3. 第三行是慢查询命令执行耗时,单位为微秒
  4. 第四行是慢查询命令的具体内容。

slowlog reset命令是清空慢日志队列。

elastic stack

elastic stack是elastic公司的一系列软件产品,包括elasticsearch、kibana、logstash、beats等,感兴趣的可以去官网看各个产品的详细介绍,此次不再做详细的讲解。本次分析过程中,我们会用到elasticsearchkibanabeats三款产品。elasticsearch用来存储解析后的redis slowlog,kibana用于图形化分析,beats用于收集redis slowlog。
这里着重讲一下beats,它是一系列轻量级的数据收集产品统称,目前官方提供了filebeatpacketbeatheartbeatmetricbeat等,可以用来收集日志文件、网络包、心跳包、各类指标数据等。像我们这次要收集的redis slowlog,官方还没有提供相关工具,需要我们自己实现,但借助beats的一系列脚手架工具,我们可以方便快速的创建自己的rsbeat---redis slowlog beat

rsbeat原理简介

接下来我们先讲解一下rsbeat的实现原理,一图胜千言,我们先来看下它的工作流。

rsbeat工作流

我们由下往上分析:

  1. 最下面是我们要分析的redis server列表
  2. 再往上便是rsbeat,它会与这些redis server建立连接并定期去拉取 slowlog
  3. 在启动时,rsbeat会发送下面的命令到每一台redis server,来完成slowlog的配置,这里设置记录最近执行时长超过20ms的500条命令。
config set slowlog-log-slower-than 20000
config set slowlog-max-len 500
slowlog reset
  1. 然后rsbeat会定时去拉取每台redis server的慢查询命令
slowlog get 500
slowlog reset

注意之类slowlog reset是因为此次已经将所有的慢日志都取出了,下次获取时取最新生成的,防止重复计算。

  1. rsbeat将解析的慢日志发布到elasticsearch中进行存储
  2. 通过kibana进行slowlog的图形化分析

rsbeat的整个工作流到这里已经介绍完毕了,是不是很简单呢?下面我们来简单看一下rsbeat的核心代码实现。

rsbeat核心代码讲解

rsbeat已经在github上开源了,感兴趣的同学可以自己去下下来使用。下面我们分析的代码位于beater/rsbeat.go,这也是rsbeat的核心文件。

func poolInit(server string, slowerThan int) *redis.Pool {
    return &redis.Pool{
        MaxIdle:     3,
        MaxActive:   3,
        IdleTimeout: 240 * time.Second,
        Dial: func() (redis.Conn, error) {
            c, err := redis.Dial("tcp", server, redis.DialConnectTimeout(3*time.Second), redis.DialReadTimeout(3*time.Second))
            if err != nil {
                logp.Err("redis: error occurs when connect %v", err.Error())
                return nil, err
            }
            c.Send("MULTI")
            c.Send("CONFIG", "SET", "slowlog-log-slower-than", slowerThan)
            c.Send("CONFIG", "SET", "slowlog-max-len", 500)
            c.Send("SLOWLOG", "RESET")
            r, err := c.Do("EXEC")

            if err != nil {
                logp.Err("redis: error occurs when send config set %v", err.Error())
                return nil, err
            }

            logp.Info("redis: config set %v", r)
            return c, err
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            logp.Info("redis: PING")
            return err
        },
    }
}

poolInit方法是rsbeat初始化时进行的操作,这里也就是发送slowlog配置的地方,代码很简单,就不展开解释了。

func (bt *Rsbeat) redisc(beatname string, init bool, c redis.Conn, ipPort string) {
    defer c.Close()
    logp.Info("conn:%v", c)

    c.Send("SLOWLOG", "GET")
    c.Send("SLOWLOG", "RESET")
    logp.Info("redis: slowlog get. slowlog reset")

    c.Flush()
    reply, err := redis.Values(c.Receive()) // reply from GET
    c.Receive()                             // reply from RESET

    logp.Info("reply len: %d", len(reply))

    for _, i := range reply {
        rp, _ := redis.Values(i, err)
        var itemLog itemLog
        var args []string
        redis.Scan(rp, &itemLog.slowId, &itemLog.timestamp, &itemLog.duration, &args)
        argsLen := len(args)
        if argsLen >= 1 {
            itemLog.cmd = args[0]
        }
        if argsLen >= 2 {
            itemLog.key = args[1]
        }
        if argsLen >= 3 {
            itemLog.args = args[2:]
        }
        logp.Info("timestamp is: %d", itemLog.timestamp)
        t := time.Unix(itemLog.timestamp, 0).UTC()

        event := common.MapStr{
            "type":           beatname,
            "@timestamp":     common.Time(time.Now()),
            "@log_timestamp": common.Time(t),
            "slow_id":        itemLog.slowId,
            "cmd":            itemLog.cmd,
            "key":            itemLog.key,
            "args":           itemLog.args,
            "duration":       itemLog.duration,
            "ip_port":        ipPort,
        }

        bt.client.PublishEvent(event)
    }
}

redisc方法实现了定时从redis server拉取最新的slowlog列表,并将它们转化为elasticsearch中可以存储的数据后,发布到elasticsearch中。这里重点说下每一个字段的含义:

  1. @timestamp是指当前时间戳。
  2. @log_timestamp是指慢日志命令执行的时间戳。
  3. slow_id是该慢日志的id。
  4. cmd是指执行的 redis 命令,比如saddscard等等。
  5. key是指redis key的名称
  6. args是指 redis 命令的其他参数,通过 cmdkeyargs我们可以完整还原执行的redis命令。
  7. duration是指redis命令执行的具体时长,单位是微秒。
  8. ip_port是指发生命令的 redis server 地址。

有了这些字段,我们就可以用kibana来愉快的进行可视化数据分析了。

Kibana图形化分析slowlog

Kibana提供了非常方便的数据分析操作,这里不展开解释了,感兴趣的可以自行去学习,这里直接上图,看下最终的分析结果。

列表详情页
时间段自由指定
查看慢日志按照时间的分布情况

上图可以看到最近有一个很明显的数量减少,原因是我们解决了相关的慢查询。

按慢查询数目来查看cmd分布和key分布
按慢查询时长来查看cmd分布和key分布
表格呈现慢查询的具体命令

看完上面的截图,有没有心动,想亲自操刀试一下?Kibana操作起来非常简单,尤其对于程序员来讲,使用起来得心应手。赶紧下载rsbeat下来自己试一下吧!

总结

随着 elastic stack 的发展,其使用门槛越来越低,我认为目前所有的有志于做数据分析的工程师都应该了解和掌握它的用法。有了它的帮助,你可以以极快的速度搭建起自己的一套免费强大的数据分析软件,它的优点包括但不限于下面提到的:

  1. 数据源任意且自定制。只要你能将数据读取出来并存储到elasticsearch中即可分析。
  2. 支持海量数据分析。得益于elastic多年的迅猛发展,其产品已经非常成熟,上TB的数据都可以轻松应对存储与分析。有了它,你就可以舍弃数据一多就卡顿的excel了。
  3. 强大的开源社区支持。elastic产品的迅猛发展离不开开源社区的支持,你只要在社区中提出自己的问题或者需求,总会有人即时给你答复和建议。如果你有一定的开发能力,那么完全可以按照自己的想法来折腾。

别再看了,赶紧去自己动手实践下吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容