一不小心把docker daemon重启了,几十个容器瞬间死亡,所以,最好在重启docker daemon时有一个确认信息:
1 |
read -p "Are you confirm to restart Docker Daemon ?(Y/N): " answer; [[ $answer == "Y" ]] && echo "重启" |
DevOps
一不小心把docker daemon重启了,几十个容器瞬间死亡,所以,最好在重启docker daemon时有一个确认信息:
1 |
read -p "Are you confirm to restart Docker Daemon ?(Y/N): " answer; [[ $answer == "Y" ]] && echo "重启" |
树的章节一般分两大部分: 一部分将树,一部分将二叉树;虽然二叉树也是树,但是二叉树足够特殊,足够有用,所以重点来讲;或者说,如果不是二叉树,树的家族也不会如此的德高望重。
在二叉树中,又有一些特殊性质的二叉树,可能没法用树的结构来描述他们之间的关系;比如: 满二叉树一定是完全二叉树;完全二叉树和二叉排序树直接却没有从属关系;完全二叉树和二叉排序树是从不同的维度定义出来的特殊的二叉树。
二叉排序树(也叫二叉查找树)在树的家族中是一颗耀眼的明星,但是在树的章节中没有被介绍,大概因为这是二叉树的实际应用,而和树本身的形态没有直接关系;还有一些特殊的树,如:红黑树、B+、B-树,稍后再研究,有些数据结构的书是没有提及的,大概因为这些东西可以自学,不需要教吧。
树是n(n>=0)个结点的有限集合。当 n= 0 时,称为空树;任意一颗非空树满足一下两个条件:
一般有四种表示形式:
二叉树是一种最简单的树结构,其存储结构更具有规范性和确定性,在一系列条件的约束下,使得二叉树具有很多的性质,方便我们研究和使用二叉树。
二叉树有5个重要的性质,他们主要讨论了树的深度、结点数等之间的关系
2.如果2i>n那么节点i没有左孩子,否则其左孩子为2i
3.如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1
思想: 将一棵树通过添加“虚节点”的方式完善成完全二叉树,然后存储
缺点: 空间浪费严重,只适合存储完全二叉树的情况
实际问题: select * from tb where id < N limit 2; 在这种情况下,我们不仅要查到id=2的结点,还要找到他附近的一些结点;即: 需要访问二叉树中的结点在某种遍历序列中的前驱和后继;
于是: 在存储结构中应该保存结点在某种遍历序列中前驱和后继的信息。
思想: 根据二叉树的性质可知,二叉树中有n+1个指针域为空,可以想办法利用起来;通过添加标记来区分是孩子指针还是前驱(或后继)指针;注意: 挨着自己的孩子在线索化中未必就挨着自己,但是要找到挨着自己的那个结点并不难,对于中序线索链表,如果自己子树的深度为k,则,找到自己的前驱或后继的时间复杂度为log2k
由于二叉树的遍历次序有三种,因此有三种意义上的前驱和后继,相应的也有三种线索链表:前序线索链表、中序线索链表、后序线索链表。中序线索链表看起来更加直观一些
tail -f 时,有如下报错:
1 |
tail: inotify cannot be used, reverting to polling: Too many open files |
说明:tail -f 在远古的时候,是不断地轮询检查文件有没有更新,这个方式效率比较低;新石器时代,kernel提供了inotify机制,就是,你不需要总来问,只要你说一声,文件有更新的话我就通知你,strace 部分信息如下:
1 2 3 4 |
inotify_init() = 4 inotify_add_watch(4, "/data/logs/phpor.20160708.log", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1 fstat(3, {st_mode=S_IFREG|0666, st_size=858053, ...}) = 0 read(4, |
上面的错误是: 需要notify的文件太多超过最大限制了,修改方式如下:
修改 fs.inotify.max_user_instances 到一个更大的值
docker容器相比完全虚拟机来讲,没有密码也能进去执行命令,还可以容易地批量执行,如下:
1 |
docker ps -q|while read id; do echo "hostname" | docker exec -i $id /bin/bash ;done |
PAM是linux上提供的一个可插拔认证模块,应该说还是比较强大、方便好用的,但是一旦配置不好,遇到问题也是不好解决的。
通过authconfig-tui图形界面配置是比较简单的,但是,现在有遇到问题了。
vsftpd通过ldap验证无法正常登录,如果去读pam的相关规范然后debugpam代码去发现问题将会花费很多的时间,怎么办呢?
首先, 通过strace、tcpdump确认ftp验证确实走了ldap而且返回结果是正确的。
其次, 确认ssh能正常登录
第三, 比较ssh、vsftpd的pam文件,通过注释掉一些行来验证是哪些配置有问题
注释掉如下行,问题解决:
1 |
auth required pam_shells.so |
man pam_shells
1 2 3 4 5 6 7 8 9 10 11 |
NAME pam_shells - PAM module to check for valid login shell SYNOPSIS pam_shells.so DESCRIPTION pam_shells is a PAM module that only allows access to the system if the users shell is listed in /etc/shells. It also checks if /etc/shells is a plain file and not world writable. |
然后,cat /etc/shells
1 2 3 |
/bin/sh /bin/bash /sbin/nologin |
问题查到这里基本要结束了,因为记起我们的ldap中没有设置登录shell的属性
遗留问题: 为什么ldap中缺少登录shell的时候,ssh登录没有问题?
场景:
同步大量文件从A到B, 先同步全量,在同步增量
scp同步文件也能同步目录,但是同步目录中的增量就不太好使了
脚本:
1 2 3 |
#!/bin/bash ip=xxx.xxx.xxx.xxx ssh $ip 'find /data1/files/ -type f -mtime -1 -mmin +1' |while read f;do echo $f; d=`dirname $f`; [ ! -d $d ] && mkdir -p $d; scp $ip:$f $f; done |
功能: 将目标机器的文件同步到本地对应目录(这里是相同目录)
注意:
虚拟机桥接到宿主机的网卡,虚拟机访问宿主机时有如下arp包:
说明:
arp查询之后会在本地缓存一段时间,当缓存超过一段时间后,可能实际信息已发生变化,于是发送一个单播的arp查询请求校验一下;话说既然可能会失效了,那么删掉重新查一次不行吗?
正常的arp请求是不知道某IP在哪里,只好广播,谁是谁响应;由于广播的开销比较大,所以,当我知道很有可能某IP就在你那里的话,我不妨先发个单播包校验一下,如果确实发生变化了,就再发送广播包不迟
当我们strace -c pid的时候,经常会发现futex占用大量时间,如下图:
那么, futex究竟是个什么东西呢?
futex – Fast Userspace Locking system call
一般来讲,futex是用于多线程程序中线程同步使用的; futex本身不是一个锁,但是可以利用这个机制实现锁。
传统的多线程同步是这样的(不保证说的对):
请求锁:
成功 –>干活 –> 干完 –> 发送信号给要加锁的线程
失败 –> 睡眠–> 收到信号–>继续请求锁
futex类似这样:
1 2 3 |
void waitUntilNotEqual(volatile int* addr, int value) { while (*addr == value) {} } |
在我们使用strace的时候,经常会遇到如下情景:
你们 restart_syscall 究竟是个什么系统调用呢?什么时候会用到该系统调用呢?
一般情况下,如果遇到这种情况,那么使用pstack看看进程的调用栈,会发现,很可能该进程处于sleep状态。
下面有一个实验:
1 |
strace php -r 'sleep(5);' |
回车之后,当看到nanosleep({5, 0}, 立即ctrl-z,会发现程序stop了, 然后,输入 fg(切换后台任务到前台,继续运行),这时,又一次看到了restart_syscall 了,如下:
或许可以这么解释: 当程序收到一个信号时,离开正在执行的系统调用去处理信号,处理完信号(上面是直到收到一个sigcont信号才算处理完上刚才的信号),继续执行运来的系统调用,似乎就是通过restart_syscall 这个系统调用进入未完的那个系统调用的,所以说,看到restart_syscall意味着刚才的系统调用没有完成的时候被迫去做别的了;
为什么strace一个sleep的进程总会看到这个呢?
strace本身是先给正在执行的进程发了个信号(什么信号?….然后….),再然后发送SIGCONT信号让程序继续执行,于是,程序进入restart_syscall ; 当然,不是所有系统调用可以中断的,也不是所有系统调用中断后都能restart的,参考: man strace
总结:
参考资料: https://www.quora.com/What-are-the-use-cases-of-restart_syscall-system-call-on-Linux-Systems
linux源码在线看: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
gdb对python的调试支持还是比较成熟的,如果gdb版本(>7)够高的话,gdb默认编译了对python的支持,可以直接:
1 |
gdb -p pid_of_python |
当然,需要先安装对应版本的python-debuginfo
参考资料:
1. http://www.cnblogs.com/dkblog/p/3806277.html 这里的libpython.py 可能并不需要
2.