扩充你的工具箱
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 鍵值對數(shù)據(jù),想通過這些數(shù)據(jù)提取出當(dāng)前 Redis 的 Key 和這些 Key 的類型。其文件的每行結(jié)構(gòu)類似于:
KEY: IAmATestKey || TYPE: STRING || expiretime:-1 || value:IAmTheTestValue
下文就是此問題的跳坑和脫坑過程:
文章經(jīng)常被人爬,而且還不注明原地址,我在這里的更新和糾錯沒法同步,這里注明一下原文地址:http://www.cnblogs.com/zhenbianshu/p/7486530.html 以防誤人子弟。
通用解決方案不好使
awk長時間處理中
對 linux 命令稍熟悉的同學(xué)可能就會說了:這些數(shù)據(jù)格式這么統(tǒng)一,數(shù)據(jù)字段間也有明顯的分隔符,不正是 awk 工具大顯身手的時刻嗎?
是的,awk 是 linux 下一個強大而又略復(fù)雜的命令,使用它的簡單語句也可以高效地處理大量文本,但是今天的主角不是它,我也不想復(fù)制粘貼網(wǎng)上到處都是的教程,就不再多介紹了。
原以為使用 awk -F ' ' '{printf $2","$6}' rdb.log >>keys.txt 將結(jié)果重定向到 keys.txt,也就一行命令的事,可是執(zhí)行后,發(fā)現(xiàn)執(zhí)行了兩個小時還沒有結(jié)束的意思。
是文件太大,awk 卡住了么?
切割文件也無法解決
文件太大處理不方便,這時,就要用到linux的另一個工具了:split 將文件以行數(shù)/大小平均分割; split [-b bytes][-l line] input_file output_prefix
由于每一行的大小是不同的,按照大小來分割的話可能會導(dǎo)致某一行被拆散,于是以每個文件 100 萬行,分割出7個文件,再對這些文件分別使用 awk 來處理, split -l 1000000 rdb.log rdb_split_
對分割后的文件使用awk,結(jié)果奇怪的是還是會在某個文件上執(zhí)行很長時間沒反應(yīng)。
這時使用 ls 命令查看文件大小的時候發(fā)現(xiàn),15G 的文件分割成了 7 份,有一個竟然有 7G 大小,這時想到可能會有的 set 或 list 很大,占用幾 G 的內(nèi)存也是有可能的。而 awk 長時間處理有可能是因為這些特別大的行。
用C來高效處理
既然如此,那就只好用別的方法先處理一下文件了,這里我考慮取出文件數(shù)據(jù)每行的前100個字符,由于鍵都很短,100個字符已經(jīng)是足夠包括鍵名和類型了。
可是印象中沒有相關(guān)的工具或命令,于是找谷哥搜索一下文件的大行怎么處理。。。結(jié)果并沒有相應(yīng)的解決方式,只好考慮自己來寫腳本了,由于其邏輯并不復(fù)雜,而且對效率要求高,就舍棄了 PHP,準(zhǔn)備使用 C 來解決。
整體思想是:利用 C 文件操作函數(shù) fgets(&res, length, file_hanler) 在每一行讀到換行符或讀到 length 個字符的特點。如果讀到100個字符還沒有讀到結(jié)尾(最后一個字符不是換行符),就說明此行是一個大行,那么就讀取單個字符并丟棄,直到讀到換行符,再繼續(xù)處理下一行。
這里貼上 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 執(zhí)行得還是很快的,大概三分鐘。執(zhí)行結(jié)束后,再使用 awk 工具,果然很快就把鍵和類型拆了出來。
此時心情大好,果然多掌握一門像 C 這種高效語言就是有用啊。
還有更好的工具
當(dāng)從 leader 口中得知 cut 命令時,我的表情是這樣的:
好吧,趕快了解一下 cut 命令:
cut [options] [file.name] :從每個文件中輸出指定部分到標(biāo)準(zhǔn)輸出。
其選項有:
-b n 輸出第n個字節(jié);
-c n 輸出第n個字符,用于處理類似utf-8中文這種三個字節(jié)的字符;
-f n 輸出第n個字段,其字段分隔符用 -d 指定;
不光有我腳本取前 n 個字符的功能,還能直接取第 n 個字段。。
試了下,cut -b 100 rdb.log >>keys.log 取前 100 個字符用了 8 分鐘,雖然比 C 腳本要慢,可是它不用手寫腳本,而且適用范圍比我寫的腳本要大。
小結(jié)
問題是順利解決了,可是解決過程引起我的思考。這個問題應(yīng)該會被更快更方便地解決的,搞得這么麻煩主要是因為 linux命令掌握不全。
不知道 linux 還有 cut 命令。其實也不是不知道,事后發(fā)現(xiàn)我筆記里已經(jīng)有了關(guān)于 cut 的簡單記錄了,可能是由于命令太過簡單,沒有很多參數(shù),也沒想到太多應(yīng)用場景,被我記入了 linux 的雜項。
同時也發(fā)現(xiàn)了跟 cut 一樣被遺忘的還有其他小知識點,是時候回憶一波了。
另外谷哥搜索命令的關(guān)鍵詞也大有問題,沒有抓住取文件前 n 字符的本質(zhì),竟然去搜索文件大行處理,因為急著要下班去接女朋友,失了智了,最后一個彌補工具問題的機會被拋棄了。
我一直認(rèn)為:解決問題的能力 ~ 個人工具箱的大小。掌握的工具越多,面對問題就會有更多選擇,解決問題也就越得心應(yīng)手。開發(fā)技能是基礎(chǔ),工具用好才能快速高效地解決問題。
寫幾個常用自動化腳本、alias 簡化一下很長的命令、掌握一些常用的快捷鍵,開發(fā)效率就能這么一點點提升了。
關(guān)于本文有什么問題可以在下面留言交流,如果您覺得本文對您有幫助,可以點擊下面的 推薦 支持一下我。博客一直在更新,歡迎 關(guān)注 。
總結(jié)
- 上一篇: 什么是同构数
- 下一篇: 8. 云停车(臻识相机)