扩充你的工具箱

code[class*=”language-“],
pre[class*=”language-“] {
background-color: #fdfdfd;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 1em;
}

:not(pre) > code[class*=”language-“] {
position: relative;
padding: .2em;
-webkit-border-radius: 0.3em;
-moz-border-radius: 0.3em;
-ms-border-radius: 0.3em;
-o-border-radius: 0.3em;
border-radius: 0.3em;
color: #c92c2c;
border: 1px solid rgba(0, 0, 0, 0.1);
display: inline;
white-space: normal;
}

pre[class*=”language-“]:before,
pre[class*=”language-“]:after {
content: ”;
z-index: -2;
display: block;
position: absolute;
bottom: 0.75em;
left: 0.18em;
40%;
height: 20%;
max-height: 13em;
-webkit-box-shadow: 0px 13px 8px #979797;
-moz-box-shadow: 0px 13px 8px #979797;
box-shadow: 0px 13px 8px #979797;
-webkit-transform: rotate(-2deg);
-moz-transform: rotate(-2deg);
-ms-transform: rotate(-2deg);
-o-transform: rotate(-2deg);
transform: rotate(-2deg);
}

:not(pre) > code[class*=”language-“]:after,
pre[class*=”language-“]:after {
right: 0.75em;
left: auto;
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-ms-transform: rotate(2deg);
-o-transform: rotate(2deg);
transform: rotate(2deg);
}

.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #7D8B99;
}

.token.punctuation {
color: #5F6364;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted {
color: #c92c2c;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.function,
.token.builtin,
.token.inserted {
color: #2f9c0a;
}

.token.operator,
.token.entity,
.token.url,
.token.variable {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}

.token.atrule,
.token.attr-value,
.token.keyword,
.token.class-name {
color: #1990b8;
}

.token.regex,
.token.important {
color: #e90;
}

.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}

.token.important {
font-weight: normal;
}

.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

.token.entity {
cursor: help;
}

.namespace {
opacity: .7;
}

@media screen and (max- 767px) {
pre[class*=”language-“]:before,
pre[class*=”language-“]:after {
bottom: 14px;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}

}

.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before {
color: #e0d7d1;
}

pre[class*=”language-“].line-numbers {
padding-left: 0;
}

pre[class*=”language-“].line-numbers code {
padding-left: 3.8em;
}

pre[class*=”language-“].line-numbers .line-numbers-rows {
left: 0;
}

pre[class*=”language-“][data-line] {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
}
pre[data-line] code {
position: relative;
padding-left: 4em;
}
pre .line-highlight {
margin-top: 0;
}

pre.line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}

pre.line-numbers > code {
position: relative;
}

.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;

-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

.line-numbers-rows > span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}

.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
–>
code[class*=”language-“],
pre[class*=”language-“] {
background-color: #fdfdfd;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 1em;
}

/* Inline code */
:not(pre) > code[class*=”language-“] {
position: relative;
padding: .2em;
-webkit-border-radius: 0.3em;
-moz-border-radius: 0.3em;
-ms-border-radius: 0.3em;
-o-border-radius: 0.3em;
border-radius: 0.3em;
color: #c92c2c;
border: 1px solid rgba(0, 0, 0, 0.1);
display: inline;
white-space: normal;
}

pre[class*=”language-“]:before,
pre[class*=”language-“]:after {
content: ”;
z-index: -2;
display: block;
position: absolute;
bottom: 0.75em;
left: 0.18em;
40%;
height: 20%;
max-height: 13em;
-webkit-box-shadow: 0px 13px 8px #979797;
-moz-box-shadow: 0px 13px 8px #979797;
box-shadow: 0px 13px 8px #979797;
-webkit-transform: rotate(-2deg);
-moz-transform: rotate(-2deg);
-ms-transform: rotate(-2deg);
-o-transform: rotate(-2deg);
transform: rotate(-2deg);
}

:not(pre) > code[class*=”language-“]:after,
pre[class*=”language-“]:after {
right: 0.75em;
left: auto;
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-ms-transform: rotate(2deg);
-o-transform: rotate(2deg);
transform: rotate(2deg);
}

.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #7D8B99;
}

.token.punctuation {
color: #5F6364;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted {
color: #c92c2c;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.function,
.token.builtin,
.token.inserted {
color: #2f9c0a;
}

.token.operator,
.token.entity,
.token.url,
.token.variable {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}

.token.atrule,
.token.attr-value,
.token.keyword,
.token.class-name {
color: #1990b8;
}

.token.regex,
.token.important {
color: #e90;
}

.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}

.token.important {
font-weight: normal;
}

.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

.token.entity {
cursor: help;
}

.namespace {
opacity: .7;
}

@media screen and (max- 767px) {
pre[class*=”language-“]:before,
pre[class*=”language-“]:after {
bottom: 14px;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}

}

/* Plugin styles */
.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before {
color: #e0d7d1;
}

/* Plugin styles: Line Numbers */
pre[class*=”language-“].line-numbers {
padding-left: 0;
}

pre[class*=”language-“].line-numbers code {
padding-left: 3.8em;
}

pre[class*=”language-“].line-numbers .line-numbers-rows {
left: 0;
}

/* Plugin styles: Line Highlight */
pre[class*=”language-“][data-line] {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
}
pre[data-line] code {
position: relative;
padding-left: 4em;
}
pre .line-highlight {
margin-top: 0;
}
–>
code {
position: relative;
}

.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;

-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;

}

.line-numbers-rows > span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}

.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
–>

前言

前几天,从 DBA 手里接到一个 Redis RDB 文件,里面是 15G 约 660万 的 Redis 键值对数据,想通过这些数据提取出当前 Redis 的 Key 和这些 Key 的类型。其文件的每行结构类似于:

KEY: IAmATestKey || TYPE: STRING || expiretime:-1 || value:IAmTheTestValue

下文就是此问题的跳坑和脱坑过程:

文章经常被人爬,而且还不注明原地址,我在这里的更新和纠错没法同步,这里注明一下原文地址:http://www.cnblogs.com/zhenbianshu/p/7486530.html 以防误人子弟。


通用解决方案不好使

awk长时间处理中

对 linux 命令稍熟悉的同学可能就会说了:这些数据格式这么统一,数据字段间也有明显的分隔符,不正是 awk 工具大显身手的时刻吗?

是的,awk 是 linux 下一个强大而又略复杂的命令,使用它的简单语句也可以高效地处理大量文本,但是今天的主角不是它,我也不想复制粘贴网上到处都是的教程,就不再多介绍了。

原以为使用 awk -F ' ' '{printf $2","$6}' rdb.log >>keys.txt 将结果重定向到 keys.txt,也就一行命令的事,可是执行后,发现执行了两个小时还没有结束的意思。

是文件太大,awk 卡住了么?

切割文件也无法解决

文件太大处理不方便,这时,就要用到linux的另一个工具了:split 将文件以行数/大小平均分割; split [-b bytes][-l line] input_file output_prefix

由于每一行的大小是不同的,按照大小来分割的话可能会导致某一行被拆散,于是以每个文件 100 万行,分割出7个文件,再对这些文件分别使用 awk 来处理, split -l 1000000 rdb.log rdb_split_

对分割后的文件使用awk,结果奇怪的是还是会在某个文件上执行很长时间没反应。

这时使用 ls 命令查看文件大小的时候发现,15G 的文件分割成了 7 份,有一个竟然有 7G 大小,这时想到可能会有的 set 或 list 很大,占用几 G 的内存也是有可能的。而 awk 长时间处理有可能是因为这些特别大的行。


用C来高效处理

既然如此,那就只好用别的方法先处理一下文件了,这里我考虑取出文件数据每行的前100个字符,由于键都很短,100个字符已经是足够包括键名和类型了。

可是印象中没有相关的工具或命令,于是找谷哥搜索一下文件的大行怎么处理。。。结果并没有相应的解决方式,只好考虑自己来写脚本了,由于其逻辑并不复杂,而且对效率要求高,就舍弃了 PHP,准备使用 C 来解决。

整体思想是:利用 C 文件操作函数 fgets(&res, length, file_hanler) 在每一行读到换行符或读到 length 个字符的特点。如果读到100个字符还没有读到结尾(最后一个字符不是换行符),就说明此行是一个大行,那么就读取单个字符并丢弃,直到读到换行符,再继续处理下一行。

这里贴上 C 脚本:

#include <stdio.h>
#include <string.h>

int main() {
    FILE *fp_in;
    FILE *fp_out;
    char ch;
    char line[100];
    
    fp_in = fopen("rdb.log", "r");
    fp_out = fopen("keys.txt", "w");

    while (!feof(fp_in)) {
        fgets(line, 100, fp_in);  //读取一行
        fputs(line, fp_out);

        if (line[strlen(line) - 1] != '
') {
            while ((ch = fgetc(fp_in)) != '
') { 
                ;
            }
            fputc('
', fp_out);
        }
    }
    fclose(fp_in);
    fclose(fp_out);
}

C 执行得还是很快的,大概三分钟。执行结束后,再使用 awk 工具,果然很快就把键和类型拆了出来。

此时心情大好,果然多掌握一门像 C 这种高效语言就是有用啊。


还有更好的工具

当从 leader 口中得知 cut 命令时,我的表情是这样的:

好吧,赶快了解一下 cut 命令:

cut [options] [file.name] :从每个文件中输出指定部分到标准输出。

其选项有:

-b n 输出第n个字节;
-c n 输出第n个字符,用于处理类似utf-8中文这种三个字节的字符;
-f n 输出第n个字段,其字段分隔符用 -d 指定;

不光有我脚本取前 n 个字符的功能,还能直接取第 n 个字段。。

试了下,cut -b 100 rdb.log >>keys.log 取前 100 个字符用了 8 分钟,虽然比 C 脚本要慢,可是它不用手写脚本,而且适用范围比我写的脚本要大。


小结

问题是顺利解决了,可是解决过程引起我的思考。这个问题应该会被更快更方便地解决的,搞得这么麻烦主要是因为 linux命令掌握不全

不知道 linux 还有 cut 命令。其实也不是不知道,事后发现我笔记里已经有了关于 cut 的简单记录了,可能是由于命令太过简单,没有很多参数,也没想到太多应用场景,被我记入了 linux 的杂项。

同时也发现了跟 cut 一样被遗忘的还有其他小知识点,是时候回忆一波了。

另外谷哥搜索命令的关键词也大有问题,没有抓住取文件前 n 字符的本质,竟然去搜索文件大行处理,因为急着要下班去接女朋友,失了智了,最后一个弥补工具问题的机会被抛弃了。

我一直认为:解决问题的能力 ~ 个人工具箱的大小。掌握的工具越多,面对问题就会有更多选择,解决问题也就越得心应手。开发技能是基础,工具用好才能快速高效地解决问题。

写几个常用自动化脚本、alias 简化一下很长的命令、掌握一些常用的快捷键,开发效率就能这么一点点提升了。

关于本文有什么问题可以在下面留言交流,如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。博客一直在更新,欢迎 关注

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注