这篇文章里我会记录一些平时做node后台的一些小点,非常零碎,不适合完整阅读。
1. 日志定位之awk的妙用
定位日志是web后台开发的日常,由于我这个部门基础设施比较原始,并没有诸如ELK的强大日志系统。一切都靠grep
、grep
和grep
。
但是,除了grep
还有另一个强大的过滤日志工具,那就是awk
。
只要日志符合规范,就能够用awk
按照分隔符来轻松取出对应字段并加上逻辑进行处理。比如我们的日志就是按照空格去分隔的,假设时间的是第4个,IP的是第8个。
zcat ~/log/error/xxx.log.gz | grep 'xxx' | awk '{if(\$4<\"20:26:00\" && \$4>\"17:45:00\"){print \$8}}' | sort | uniq -c | wc -l |
上面这个命令,就可以通过去重IP,找到这段时间内调用这条cgi的用户量。
sort
是排序
uniq
是去重 -c
参数是统计出每个IP重复的数量
wc
是用来统计行数,有多少个IP就多少个用户
2. ssh的加解密算法配置
其实一般来说ssh配置已经没有什么坑了,一般的机器可以如下配置:
Host NewDevelop |
这样,直接通过ssh NewDevelop
就能连接到对应机器。
但是万万没想到,在这个部门遇到个老古董机器,普通的ssh机器是无法连接的。
这台机器是用了特殊的加解密算法,经过一段时间的google和摸索,终于摸索出了一套算法配置:
Host NewDevelop |
3. gzip加密过的html解码
有个需求是需要在node端解析用户设置的url,然后从中提取出图文。没错就是模仿微信的图文消息那种感觉。
(问题是,人家微信是提供了js api,然后用户直接在html里调用api来设置头图的,我们敢吗,敢也没人用==)
总之用了一个xss
库,本来是用来过滤html中的xss的,结果被我用来解析出里面的各种标签和图片。策略是解析出<title>
和第一个<img>
标签中的图。
然后遇到一个投诉,说解析出来是乱码。一开始怀疑是编码问题,但是发现那个返回的html已经设置了utf-8
的,就算是gb2312
,我node后台也有做识别和转码。这个url用浏览器访问没有任何问题,虽然是用asp的,但是返回的html还是比较符合规范的。
所以问题出在哪呢?试了半天发现,原来这个网址用的是gzip压缩,我并没有做解压,浏览器则都是自动识别+解压的。
其实一般的场景下,用request
这个自带的模块传对应参数,就能自动做到解压gzip
。但我们场景特殊,对于外网请求都要用一个C++插件去proxy转发,那个插件可没帮我们做gzip解压。
还好node有自带的解压库zlib
,这个库就可以解压gzip
压缩过的文档流。
大致判断是这样的(不要吐槽var,我们还在用node 0.12)
if (data.head.indexOf('Content-Encoding: gzip') > -1) { |
但是在写这个ungzip
方法的时候发现,如果直接用自带的zlib.gunzip
去解压整个html,会报错Error: unexpected end of file
经过一番摸索,我发现还有一种基于流的解压方式:
/** |
虽然对于这个用户的案例来说,每次解压到最后一定会报错,但是没关系,数据已经拿到了,直接回调就是了。
4. rsync
的优化
作为全干工程师,devops当然也是要自己动手的,那么涉及到devops就难免涉及到持续集成,涉及到持续集成就难免涉及到rsync
这个好用的命令。就这么一个命令,支撑起了那么多重要代码的传输也是神奇。
但是rsync
有个问题在于,如果你的目录是动态生成的(比如根据分支名),那么极有可能你的目标机器上没有这样一个目录。这个时候rsync命令就会报错。
其实rsync
是有参数来解决这个问题的,但是比较难用,那就是--include-from
这个东西一般是和--exclude-from
一起用的,所以甚至需要专门读取一个配置文件,+
代表include,-
代表exclude。
在搜索了一大堆令人一头雾水的stackoverflow问题后,我决定还是放弃这个想法。
现在说下背景,之所以会有动态rsync路径的问题,是因为自己希望能够根据git push
每次产生的对比文件列表来增量地rsync
构建后的文件,这样就能大大降低CI的时间。(因为历史原因,我们的项目非常、非常庞大,如果全量rsync构建后的文件,时间可以长达1000s)
而构建后的路径,是按照git分支名区分的,目标机器(测试机)不一定有对应的目录,比如你开了一个新分支这种情况,目标机器没有对应目录,导致增量rsync单独文件的时候报错。
为了解决这个问题我甚至想过在测试机维护一个node服务,通过监听git的webhook来动态创建目录,但是在研究了那台机器的linux环境我果断选择了放弃,这台机器不仅外网不通,安装全靠手动上传,连vim、ssh的配置都被魔改过,我实在不想碰这个机器。
结果一位老程序员对我的提醒如醍醐灌顶:
“你直接创建一个同样目录结构的上级目录,只复制需要增量rsync的文件,然后直接rsync这个目录就行了”
这简直有种从更高维看事情的感觉,虽然很粗鲁,但是确实很香。
5. child_process
的使用
前端出身的全干工程师,可能经常会写一些nodejs的脚本来代替shell脚本来做一些devops的事情,(事实上shell脚本确实不是很好用)。
但是毕竟nodejs也是基于调用系统底层接口来达到操作系统的目的,不可避免的经常需要用child_process
来跑一些shell脚本,比如上面提到的rsync
。
当然,你可以通过像shelljs
这种库来调用,但是…我这个项目吧,历史原因,历史原因。
举个例子,下面这个rsync
的调用:
const child = require('child_process') |
如果像这样调用的话,你会发现rsync
的输出并没有到console中,这是因为如果不指定输出的参数,child_process
不会把结果输出到console中。
可以这样指定输出参数:
child.execSync(`rsync -acvzK --exclude=".svn" ./server/proto/ root@8.8.8.8::/${BRANCH_NAME}/server/proto/`, { |
这样的话,输出就会到console中。
6. docker 的多分支测试环境调试(这里可能之后单独分一篇文章)
经过半年的努力,终于把项目迁移到git + docker的分支部署测试环境模式,不管怎么说,对我来说,比原来svn的开发模式舒服多了。
但是目前分支实在太多(50+),每个微服务也都是共用这个母机的,所以做了多个母机来承载不同分支的测试用docker.
进入docker的命令是
docker exec -it yourdocker su - root |
由于某些项目采用了docker-compose,当你重启mac的时候发现mac开机特别慢(不要问我为什么会重启,你敢相信互联网公司会不时断电),很有可能是因为自动启动了docker以及里面所有的容器。重启docker倒是没什么关系啦,但是所有容器一起启动就有点…你可以通过docker ps
来查看当前正在运行的容器
docker ps |
你瞧,一重启mac,这些mongodb、mysql、memcached全都重启,那可真是要命。
所以可以通过docker update -restart=no CONTAINER-ID
来把这些容器的自动重启关掉。
参考这个链接:https://stackoverflow.com/questions/37599128/docker-how-do-you-disable-auto-restart-on-a-container