一些有用的经验

虽然日期标注了14.8.19其实只是为了置顶罢了

记载一些心得感悟经验甚至是闪现的灵感

14.9.12

读源码的最好方式是往里面加log,根据log来追踪源码的运行,函数的调用链,变量的变化等等。读1W遍的理解也没有LOG输出一次深刻。

14.11.6

最近在堡垒机上用RZ老是出现乱码文件,记下来删除的解决办法

[root@192_168_100_35 musicwap]# ls

??,?K?k?ͨa.?J]?k?Φ??P???Z?b?A?R???X??u??.?????H@B?T???xS*

1
2
3
4
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080
service iptables save
service iptables restart

15.1.15

如何把两个静态库.a文件封装成一个静态库

有一个办法 就是 把第二个.a文件ar x 编程.o 文件

然后把第一个.a文件也ar x 编程.o文件

然后ar crvs 把所有的.o文件打包起来

15.1.15

分析程序和库的工具

size: 查看各个段大小

nm : 查看函数变量

objdump :查看段具体信息包括汇编等

15.1.20

封装C库,为了能让G++编译,要加上一段在头文件里面

1
2
3
4
5
6
7
#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif

15.1.27

1
2
3
4
5
6
生成动态连接库的方法
g++ -m32 hello1.cpp hello2.cpp -fPIC -shared -o ../lib/linux32/libhello.so
生成静态连接库的方法
g++ -m32 hello1.cpp -c -o hello1.o //编译hello1.cpp 生成中间文件hello1.o
g++ -m32 hello2.cpp -c -o hello2.o //编译hello2.cpp 生成中间文件hello1.o
ar rcs libhello.a hello2.o hello1.o //将hello1.o和hello2.o添加到静态链接库

15.2.2

在centos上gdb调试,出现Missing separate debuginfos,use: debuginfo-install glibc-2.12-1.132.el6.i686

先修改/etc/yum.repos.d/CentOS-Debuginfo.repo里面的debuginfo目录中enabled=1

如果没这个文件,从/etc/yum.repos.d/bak里面cp一个出来

centos自带源可能不全,如果是这样

找到/etc/yum.repos.d/epel.repo,在epel,epel-debuginfo,epel-source中分别替换baseurl

baseurl=http://mirrors.ustc.edu.cn/epel/6/$basearch

baseurl=http://mirrors.ustc.edu.cn/epel/6/$basearch/debug

baseurl=http://mirrors.ustc.edu.cn/epel/6/SRPMS

然后yum install nss-softokn-debuginfo

安装好后,根据提示输入debuginfo-install glibc-2.12-1.132.el6.i686

完毕

15.4.10

sar工具是个好东西,要判断系统瓶颈问题,有时需几个 sar 命令选项结合起来

怀疑CPU存在瓶颈,可用 sar -u 和 sar -q 等来查看

怀疑内存存在瓶颈,可用 sar -B、sar -r 和 sar -W 等来查看

怀疑I/O存在瓶颈,可用 sar -b、sar -u 和 sar -d 等来查看

详细的可以戳这里看:sar使用简介

15.5.12

编程时想获取linux一些系统性能数据怎么办?

戳这里:linux系统性能数据获取

15.5.22

epoll下LT和ET的处理都是大致相同的

LT模式例子:

https://www.cnblogs.com/lojunren/p/3856290.html

https://github.com/hurley25/ANet

https://juejin.im/post/5ab3c5acf265da2380598efa

https://www.zhihu.com/question/22840801

https://blog.codingnow.com/2012/04/mread.html

ET相当于LT的while循环版本,LT的循环是整个事件循环罢了

ET的读处理是一直read

返回-1,检查errno,如果是EAGAIN那么不再读(缓冲区读完),如果是其他那么说明连接出错,进行报错然后也不再读。

返回0,说明对端关闭

返回大于0,成功读到数据

写处理是一直write,直到数据写完

返回-1,检查errno,如果是EAGAIN那么不再写(缓冲区写完),如果是其他那么说明连接出错,进行报错然后也不再写。

返回大于0,成功写数据

15.8.13

当nginx到后端超时时,可以通过修改日志格式来查看后端的实际响应情况

1
2
3
4
5
# $upstream_response_time 后端应用服务器响应时间
# $upstream_addr 后端服务器IP和端口号
log_format main '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent '
'"$request_time" "$upstream_response_time" "$upstream_addr" "$request_body "'

可以修改后端的超时时间来剔除这些超时服务器

1
2
3
4
# time out settings  
proxy_connect_timeout 1s;
proxy_send_timeout 1s;
proxy_read_timeout 1s;

15.11.7

如果想知道文件属于那个RPM包

1 如果是已经安装的文件,那么rpm -qf即可

例如

1
2
[root@localhost.localdomain ~]# rpm -qf /usr/lib64/libgij.so.10
libgcj-4.4.7-3.el6.x86_64

2 如果是未安装的文件,那么yum provides即可

例如

1
2
3
4
5
[root@localhost.localdomain ~]# yum provides */libgij.so.10
libgcj-4.4.7-16.el6.x86_64 : Java runtime library for gcc
Repo : base
Matched from:
Filename : /usr/lib64/libgij.so.10

另外,如果是ubuntu下的未安装文件,用apt-file find即可

root@ubuntu:~/# apt-file find /libc_p.a libc6-prof: /usr/lib/x86_64-linux-gnu/libc_p.a

15.11.14

1
2
3
4
5
proxy_next_upstream http_404 http_502;
upstream group1 {
server 192.168.1.1:80 max_fails=1;
server 192.168.1.2:80 max_fails=1;
}

这样配置以后,upstream对于404和502错误的处理是不同的

例如192.168.1.1上出现502错误,那么这一台的fail会+1,在默认的30秒内被踢下线,这段时间请求直接通往192.168.1.2

如果192.168.1.1上出现404错误,那么请求会转发到192.168.1.2上,如果也返回404错误,那么最终返回404错误,不会对fail+1

15.11.20

线程和信号的坑:

多线程程序中,所有线程对于每个信号的信号处理函数都是相同的

所以子线程进行信号处理函数的注册是会覆盖主线程的这个信号处理函数

对于主线程和子线程需要相同信号,却触发的不同信号处理逻辑的情况,则需要使用pthread_self判断线程ID来进行区分操作

15.11.20

对于ubuntu系统来说,没有/etc/sysconfig/iptables文件

也无法service iptables start/stop

对于想要关闭除了22端口以外的其他端口,可以使用命令写入这样的内容

1
2
3
4
5
6
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j RETURN
-A INPUT -p tcp -j DROP
-A OUTPUT -p tcp -m tcp --sport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 22 -j RETURN
-A OUTPUT -p tcp -j DROP

然后

1
2
3
4
5
6
存储配置
iptables-save >/etc/iptables.rule
开启配置
iptables-load </etc/iptables.rule
关闭配置
iptables -F

15.12.8

ubuntu编译内核

研究RTO的时候代码看不懂,需要插入日志来看调用情况

先下载源码并且解压

1
2
3
4
apt-get install linux-source
tar xvf /usr/src/linux-source-3.13.0.tar.bz2
cd linux-source-3.13.0
cp /boot/config-3.13.0-24-generic .config

找到.config中CONFIG_LOCALVERSION,改为CONFIG_LOCALVERSION="fuck"(这里随便改)

1
2
make -j4 bzImage
make modules_install

查看/lib/modules,发现存在两个文件夹:3.13.0-24-generic,3.13.11-ckt30fuck

所以新编译的版本号就是3.13.11-ckt30fuck

1
2
3
4
5
cp .config /boot/config-3.13.11-ckt30fuck
cp arch/x86/boot/bzImage /boot/vmlinuz-3.13.11-ckt30fuck
mkinitramfs -o initrd.img-3.13.11-ckt30fuck 3.13.11-ckt30fuck
update-grub2
reboot
1
2
3
检查下版本
uname -a
Linux ubuntu 3.13.11-ckt30fuck #2 SMP Mon Dec 7 23:36:37 PST 2015 x86_64 x86_64 x86_64 GNU/Linux

15.12.22

开发加解密模块遇到一个血坑

openssl在cbc模式的算法实现上,具体在X86平台上的汇编实现上,假如输入的字串不是块的整数倍,那么加密的字串将无法被解密

在arm以及core算法里没这个问题

16.1.27

awk以一个或者多个空格作为分割,而cut以单个空格作为分割

例如

1
2
3
4
5
6
7
ps -ef|grep init|grep -v grep
root 1 0 0 17:54 ? 00:00:02 /sbin/init

awk要获得进程号
ps -ef|grep init|grep -v grep|awk '{print $2}'
cut的话
ps -ef|grep init|grep -v grep|cut -d ' ' -f10

awk变量

awk拼接变量和字符串

1
2
~# echo "A B C"|awk '{print "D"$1"E"$3"F"}'
DAECF

awk拼接变量和字符串时添加空格(awk使用逗号作为空格)

1
2
~# echo "A B C"|awk '{print "D"$1,"E",$3"F"}'
DA E CF
  • 添加双引号

    使用""双引号把一个双引号括起来,然后用转义字符,输出双引号。

    awk '{print "\""}'

  • 添加单引号

    使用一个双引号"",然后在双引号里面加入两个单引号'',接着在两个单引号里面加入一个转义的单引号',输出单引号。

    awk '{print "'\''"}'

17.7.14

替换文件夹下所有文件的字符串

1
sed -i "s/a/b/g" `grep -rl 'a' .`

如果要替换的字符串也要匹配正则的部分

1
sed -i "s/##\([^#]\)/## \1/g"

\1 代表了之前括号中的内容

17.10.18

mysql编码问题

修改/etc/my.cnf

1
2
3
4
5
[client]
default-character-set = utf8
[mysqld]
default-storage-engine = INNODB
character-set-server = utf8

重启后输入

1
show variables like '%char%';

查看编码

其次是Emoji表情,如果想支持必须设置为utf8mb4字符集合

如果不想支持可以用utf8库的RuneCountInString()对字节数是否大于3进行判断来过滤

18.3.7

常用crontab监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
count=`ps aux | grep "xxx" | grep grep -v | wc -l`
if [ $count == 0 ]
then
/data/node/start.sh
fi
mem=``
diskusage=`df -h |awk '{print substr($5,1,length($5)-1)}'|head -y|tail -1`
if [ $diskusage -gt 90 ]
then
rm -rf /data/node/log/*
/data/node/restart.sh
fi

判断进程是否存在,不在就启动

判断df -h的第y行的磁盘使用是否大于90%