Living a Simple Life is a Happy Life

有饭吃,自由自在,就非常开心

Crontab Eight Comm

| Comments

网上收集,多次踩坑,立此存照

crontab八诫

  • 不要假定cron知道所需要的特殊环境,它其实并不知道。所以你要保证在shelll脚本中提供所有必要的路径和环境变量,除了一些自动设置的全局变量。所以注意如下2点:

    • 脚本中涉及文件路径时写全局路径;
    • 脚本执行要用到java或其他环境变量时,通过source命令引入环境变量,如:

        #!/bin/sh
        source /etc/profile
        export RUN_CONF=/home/xxxx/boss.conf
        /usr/local/jboss-4.0.5/bin/run.sh -c mev &
      
  • 当手动执行脚本OK,但是crontab死活不执行时。这时必须大胆怀疑是环境变量惹的祸,并可以尝试在crontab中直接引入环境变量解决问题。如:

      0 * * * * . /etc/profile;/bin/sh /var/www/java/audit_no_count/bin/restart_audit.sh
    
  • 新创建的cron job,不会马上执行,至少要过2分钟才执行。如果重启cron则马上执行。

  • 每条 JOB 执行完毕之后,系统会自动将输出发送邮件给当前系统用户。日积月累,非常的多,甚至会撑爆整个系统。所以每条 JOB 命令后面进行重定向处理是非常必要的: >/dev/null 2>&1, 前提是对 Job 中的命令需要正常输出已经作了一定的处理, 比如追加到某个特定日志文件。

  • 当crontab突然失效时,可以尝试/etc/init.d/crond restart解决问题。或者查看日志看某个job有没有执行/报错 tail -f /var/log/cron

  • 千万别乱运行 crontab -r。它从Crontab目录(/var/spool/cron)中删除用户的Crontab文件。删除了该用户的所有crontab都没了。

  • 在crontab中%是有特殊含义的,表示换行的意思。如果要用的话必须进行转义 \%,如经常用的date '+%Y%m%d'在crontab里是不会执行的,应该换成 date '+\%Y\%m\%d'

  • 永远要手工验证一下crontab中的命令

装服务器偶得

| Comments

最近工作需要,连续装了不少服务器。虽然做系统真是没什么技术含量的事,但做多了还是有些想法,记录下。

硬件tips

Dell

  • Dell PowerEdge 2950 2U

  • Dell PowerEdge R610 2U

  • Dell PowerEdge R630 1U

  • Dell PowerEdge R710 1U

  • Dell PowerEdge R720xd 1U

对Dell 系列的服务器印象一直很好,皮实耐折腾, R系列的兼容性也很好,开机启动速度也算是凑合。

但是最近发现一个问题,就是R630 系列的做了Raid5之后,分XFS分区,用clonezilla做镜像的时候非常慢。如果要调大xfs的blocksize,又需要重新编译内核,比较麻烦。

HP

  • HP ProLiant DL380 Gen6 2U

  • HP ProLiant DL360 Gen9 1U

网上对惠普 DL360系列的机器评价很好,但我对它印象不佳。

首先说设计,前面板只有一个usb接口,一般做系统的时候,条件简陋点,需要一个USB光驱,一套键鼠,光驱可以插后面,但是键鼠插后面太麻烦了,所以我比较喜欢前面板有两个USB接口的机器。

然后HP 的BIOS 自检极其缓慢,是Dell的1.5倍。很扯。

然后DL360系列,如果安装centos系,自编译内核的话,需要自己编译Raid驱动,这个极其不爽,而且惠普的官网找驱动,真是费力,而且kernel编出来总有种种小毛病。

比较值得赞扬的是 Gen9以后的机器,做Raid的界面做的挺漂亮的。但是极其坑爹的是,BIOS自检过了以后,没有明确提示按F8进Raid,一定要到网上查。而且我觉得HP的BIOS管理引导做的很啰嗦,要进三层才能看到功能。

Lenovo

  • Lenovo System x3550 M5

公司里说进了IBM的服务器,开机一看,打的Lenovo的LOGO,好吧,原来联想已经做到这个程度了。

机器的配置不错,说说吐槽点:

  • 首先自检的速度又慢了一个档次,重启一遍可以买个包子吃了。

  • BIOS 工具又是层层深入,做Raid估计要进入5级菜单才能搞定。

  • 不支持centos5系了,同事打电话问客服,号称没测过centos6.4以下的,真是理直气壮

吐槽

  • 所有的机器做Raid的那套东西大同小异,控制器都是一家的。但是界面包装有好有坏,按靠谱程度排序 HP>DELL>Lenovo

  • 做好机器后,总是需要在前面贴个标签,现在机器越做越小,最直观的感觉就是前面贴个标签都找不到地方了。看人家管理,有把标签挂在上面的,有在LED屏上编号的,都不方便。为什么没有厂商在前面设计一个小卡片槽,专门放标签纸呢,我估计这个小功能肯定会讨得很多人欢心。

  • 我装服务器,到现在为止一个最大的吐槽点,没有见过一家厂商解决过。就是机器自检的时候,很多显示器兼容性不好,会把左边屏幕的输出吃掉一截。最坑爹的是,每家的BIOS输出都是紧靠左边打出来的,往往会有 F2=Setup 前面的 F2被吃掉的情况,他们就不知道把输出居中一点,我只能说这些公司真是僵化了,下一个诺基亚,说不定就是惠普。

  • 最后就是所有的所谓大公司,官网做的都和微软帮助一个style,就是我按照提示一步步点下去,又回到开始了,它还问我”有帮助吗?”,已经吐槽无力了。在我看来,这些所谓的高科技大公司,其实已经比很多传统行业还恐龙了,看看他们数十年如一日的BIOS就知道了。只不过积累在那里,让他们产生自我感觉良好的错觉。这些公司死是早晚的事。

软件tips

centos5 -> centos6 -> centos7

redhat系的的安装界面 一代比一代漂亮,也一代比一代依赖鼠标。

  • centos5不支持鼠标,熟练后完全依赖键盘一路打下去,很方便
  • centos6 界面很朴素,但比较好用,键盘鼠标都能不是很痛苦的搞定
  • centos7 界面比较花哨了,都做到一个安装界面里,鼠标操作很方便,键盘操作很痛苦,我曾经在没有鼠标的环境下,硬是花了半个小时装了个centos7.1U

孰是孰非,让后来人评说。

xfs resize blocksize

  • xfs做文件系统的时候,试图mkfs.xfs -b –size=xxx ,不生效,默认redhat系的page_size设置的就是4K,xfs的blocksize必须不大于这个size,如果要设大,只能重新编译kernel

Linux Profile and Debug Tools of Performance

| Comments

用perf工具统计系统调用

1
perf top

或者统计一段时间内的调用

1
2
perf record -a -g -F 1000 sleep 30
perf report -g

用strace 追踪某个进程的调用

1
strace -c ls

或者attach一个进程

1
strace -c -p pid

查看磁盘调用

1
lsof -p pid

磁盘负载

1
iostat -x 5 -m

整体负载统计

1
vmstat 5 

Linux Cheat Sheet

| Comments

收集linux下需要多次google的命令

编码问题

  • utf16 > utf8
1
iconv -f UTF-16 -t UTF-8 file_name

web开发命令

  • curl post 一个json文件
1
curl -H "Content-Type: application/json"--data @body.json http://localhost:8080/ui/webapp/conf
  • curl post 一个json字符串
1
curl -H "Content-Type: application/json"-d '{"username":"xyz","password":"xyz"}' http://localhost:3000/api/login

系统时间

  • centos6系列修改时区
1
2
3
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
vim /etc/sysconfig/clock
ZONE="Asia/Shanghai"
  • centos7系列修改时区
1
2
timedatectl list-timezones | grep Asia
timedatectl set-timezone Asia/Shanghai
  • 设置系统时间
1
date +"%Y%m%d%H%M%S"

系统状态

  • 查看系统占用句柄数
1
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more

程序

  • mongo导出
1
mongoexport  -u crossflow -p '0701!1523#SH' -authenticationDatabase admin -d bpc -c main_app_datapath -o main_app_datapath.json

shell 处理

  • 获取当前路径
1
export CURRENT_PATH=$(cd "$(dirname "$0")"; pwd)
  • 检查CPU load
1
2
CURRENT_LOAD=`top -b -n 1|grep 'load average'|awk '{print $12}'|sed 's/,//'`
declare -i current_load=${CURRENT_LOAD%.*}
  • find 匹配多个pattern
1
find /usr/lib64 -name '*.so' -o -name '*.so.1'

文本处理

  • 根据某个字段做uniq
1
sort -u -t, -k1 file

Debug Kernel Panic in Centos

| Comments

当你面对一台新机器,出于某些原因(不是闲的慌)不得不自己编译一个内核时,会碰上kernel panic。

kernel panic很让人心烦,启动时的panic更让人烦,没有挂上硬盘,没有任何log的panic尤其让人烦。

提供几个解决问题的瞎搞方法: (以下内容针对于redhat系,但大部分方法是通用的)

判断引起panic的环节

简单描述下启动流程:

1 Power On                                 Maybe Err:Worlds Collides
2 BIOS                                     Maybe Err:Worlds Collides
3 Load Grub From MBR                       Maybe Err:See nothing
4 load Grub and show it                    Maybe Err:Grub loads failed
5 Grub reads menu.list                     Maybe Err:Grub loads failed
6 Grub loads kernel image                  Maybe Err:Grub loads failed
7 kernel mounts root filesystem            Maybe Err:PANIC
8 kernel runs init                         Maybe Err:PANIC
9 init runs scripts to start               Maybe Err:PANIC

首先你要确认下是哪个环节引起的panic,如果你的log打得比较全,一般能根据蛛丝马迹判断是上面那个环节引起的问题。一般panic发生在step7,step8, step9环节当中。

  • step9: 走到这里已经无大碍,无非是/etc/rc.sysinit 之流挂载了不该有的设备,启动了不知道神马的服务,可以直接在启动脚本中打各种log调试

  • step8: 这个就比较棘手,一般是initramfs 解压后执行某些脚本报错,所幸是大部分都是init级别的,一般可以在grub的kernel后面加参数,挂载shell调,也可以直接用工具修改initramfs镜像中的文件,重新打包二分法定位

  • step7: 也比较棘手,一般panic总要怀疑磁盘驱动,我感觉这个是导致panic的大户,另外如果屏幕没有东东输出,估计视频驱动也要鼓捣一番。

下面针对 step7,step8级别的panic提供一些瞎搞手段

在kernel 参数中加入调试开关,关闭ACPI,selinux

1
2
3
4
  title CentOS (2.6.32-358.el6.x86_64)
          root (hd0,0)
          kernel /vmlinuz-2.6.32-358.el6.x86_64 ro root=/dev/mapper/vg_localhost-lv_root rd_NO_LUKS rd_NO_MD rd_LVM_LV=vg_localhost/lv_swap crashkernel=128M LANG=zh_CN.UTF-8 rd_LVM_LV=vg_localhost/lv_root  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM debug selinux=0 acpi=0
          initrd /initramfs-2.6.32-358.el6.x86_64.img

这是考验人品的时候,不管三七二十一,先把最有可能的问题点排除掉。另外redhat系的会在kernel后面加上 rhgb quiet 之类的参数,统统去掉,开机的时候好好盯着屏幕看看,有没有可疑的东东输出。 因为系统可能会在短时间内输出大量log而没有记录,你需要设置一下输出log的速率和暂停时机,更详细的参数可以在这里找到:

https://wiki.archlinux.org/index.php/Boot_debugging

在kernel 参数中加入dracut的调试开关

redhat系后期采用了dracut构建 initrd镜像,关于dracut的手册在这里:

http://people.redhat.com/harald/dracut-rhel6.html#lsinitrd

调试开关在这里:

https://fedoraproject.org/wiki/How_to_debug_Dracut_problems

你可以设定rdshell,在panic之后跳入dracut提供的shell,打dmesg看看log信息。

最后的最后,实在不知道为啥了,而且你很闲,可以考虑启动时加串口设备调试

一些tooltip

  • 编译kernel的时候,make menuconfig,3.10以后的内核支持搜索某个开关后按数字键直接跳到那个开关的设置项中,这个很有用

  • redhat系用dracut构建initrd,配置文件默认在 /usr/share/dracut/ ,如果你懒得改 initramfs,可以直接修改里面的配置文件,然后重新make install即可

  • 有时候你不好确认根文件系统挂载到哪里了,可以参考这里:

http://free-electrons.com/blog/find-root-device/

其它参考资料:

http://www.tuxradar.com/content/how-fix-linux-boot-problems

Tcpdump Commands

| Comments

tcpdump 的抓包保存到文件的命令参数是-w xxx.cap

  • 抓eth1的包
1
tcpdump -i eth1 -w /tmp/xxx.pcap
  • 抓eth1的包,用ip+port的形式显示通信对
1
tcpdump -i eth1 -nn -w /tmp/xxx.pcap
  • 抓 192.168.1.123的包
1
tcpdump -i eth1 host 192.168.1.123 -w /tmp/xxx.cap
  • 抓192.168.1.123的80端口的包
1
tcpdump -i eth1 host 192.168.1.123 and port 80 -w /tmp/xxx.cap
  • 抓192.168.1.123的icmp的包
1
tcpdump -i eth1 host 192.168.1.123 and icmp -w /tmp/xxx.cap
  • 抓192.168.1.123的80端口和110和25以外的其他端口的包
1
tcpdump -i eth1 host 192.168.1.123 and ! port 80 and ! port 25 and ! port 110 -w /tmp/xxx.cap
  • 抓vlan 1的包
1
tcpdump -i eth1 port 80 and vlan 1 -w /tmp/xxx.cap
  • 抓pppoe的密码
1
tcpdump -i eth1 pppoes -w /tmp/xxx.cap
  • 以100m大小分割保存文件, 超过100m另开一个文件
1
tcpdump -i eth1 -w /tmp/xxx.cap  -C 100m
  • 把后两个数据包并到一个数据包merge.pcap
1
mergecap -w merge.pcap 1.pcap 2.pcap
  • 按照radius条件过滤数据包
1
tshark -r 1.pcap radius -w radius.pcap
  • 按照数据包数分割一个大的数据
1
editcap -c 1000000 merge.pcap split01.pcap
  • split pcap
1
editcap -c 100000 in.pcap out.pcap

How to Xargs Separate Parameters

| Comments

做过很多遍了,每次还是得现查,记一下:

echo "'param 1' 'param 2'" | xargs -n1 | xargs -I@ echo \[@\] \[@\]

output:

1
2
[param 1] [param 1]
[param 2] [param 2]

xargs里面替换字符串

ls|xargs -I @  echo "mv @ @.pack"|sed 's/.json.pack.pack/.pack/g'|bash

Python编程实战 - 笔记1

| Comments

这本书讲的挺实在的,设计模式的部分又复习了一遍。另外又学了几个Python3的新decorator。

创建型设计模式

抽象工厂 (Abstract Factory)

  • 名字就用AbstractFactory好了,不要起什么BaseFactory之类的
  • 相关类都放到对应的Factory Class里面,不要暴露给外面了

建造者模式 (Build)

  • 和工厂的区别就是保存了创建对象时各个部分的细节

工厂模式

  • 根据情况实例化对象
  • 还是注意和抽象工厂的区别,抽象工厂是将创建对象的行为抽象出来,而工厂模式则是根据要创建的对象类型实例化

原型模式 (Prototype)

  • 这个模式其实在javascript的根本,不过Python的实现方法还真是五花八门,我说直接用copy就好了嘛

单例模式 (Singleton)

  • 我最中意的一种实现:
1
2
3
4
5
6
7
8
9
10
11
class Borg:
    _shared_state = {}
    def __init__(self):
        self.__dict__ = self._shared_state

class Singleton(Borg):
    def __init__(self, arg):
        Borg.__init__(self)
        self.val = arg
    def __str__(self):
        return self.val

结构型设计

  • 作用就是改装对象,或者把小对象合并为大对象

Adapter

  • 其实就是转接方法

Bridge

  • 把方法抽象出来

Composite

  • Python里面有一种省一点内存的写法,可以直接用CompositeItem和Item两个类来实现,不过我觉得不直观

decorator

  • 几个新的decorator:

    • @functools_wraps : 装饰器工厂

    • @statically_typed : 类型检查

  • 另外@ensure类修饰符可以用来简化设置property的代码

Facade

  • 这个模式其实是天天在做的,就是把接口聚合的好看一点
  • 其实思想可以推广到很多方面,比如Docker,就是LXC的一个Facader,而且做的比较好看,于是大家就都来用了

Flyweight

  • 管理许多小对象的时候用引用
  • Python用__slot__ Attribute来做最方便
  • 里面关于用shelve对象存储class attribute的思路挺实用的

Multiline Comments in Docker File

| Comments

为了减少Image的fs layout数目,Dockerfile中经常会把多个命令集中到一个 RUN 指令下。

多行之后可读性就很差了。

有个比较偏门的写注释的方法:

1
2
3
4
5
6
7
8
9
10
11
RUN mkdir -p /home/build/npm3 && \
    mkdir -p /home/build/smartprobe && \
    mkdir -p /home/build/bpc3 && \
    `#====================================================` \
    `#=============checkout and install rpms==============` \
    svn export xxx && \
    rpm -ivh --force --nodeps *.rpm && \
    `#====================================================` \
    `#=============checkout and install python==============` \
    ... && \

比较实用,推荐之。

Different Users in Same Unix Group Can Not Run Mongod

| Comments

事情的缘起是这样的…….

想要在Dockerfile中启动一个MongoDB,之后编译为Docker image。(不要问我问什么要在docker image中存一个mongodb数据库,真实世界的需求你永远想不到)

Docker build不支持 –privileged,所以默认的/etc/init.d/mongod 这个脚本中的

1
runuser -s /bin/bash mongod -c 'ulimit -S -c 0 >/dev/null 2>&1 ; numactl --interleave=all /usr/bin/mongod -f /etc/mongod.conf'

这种写法就死翘翘了。

github上有这个Issue:

https://github.com/docker/docker/issues/1916

大家讨论了1年多,对于怎么解决,还是没有个所以然。(话说要再吐槽一下github的issue了,一般大一点的项目,一个issue跨度以年来论,长篇大论读完也不容易呀)

最后只好在Dockerfile中这么搞:

1
2
3
4
mongod --fork -f /etc/mongod.conf && \
mongod --shutdown -f /etc/mongod.conf && \
chown mongod:mongod /opt/lib/mongodbpath -R

这样build就顺利完成了。

可是启动这个image为container后,执行:

1
/etc/init.d/mongod start

报错:

1
 [initandlisten] warning couldn't write to / rename file /datadir/journal/prealloc.0: couldn't open file /datadir/journal/prealloc.0 for writing errno:1 Operation not permitted

虾米,明明已经加了mongod的group了。而且errorno是1,不是 "errno:13 Permission denied",有点奇怪。

问题在这里:

https://jira.mongodb.org/browse/SERVER-7583

要再加一个指令:

1
setcap cap_fowner+ep /usr/bin/mongod

就是这么折腾。