centos7之systemctl

Centos7之前,我们都通过service命令来管理(启动、停止、重启)服务,通过chkconfig来管理服务的自启动; 然而,这两个命令并不属于同一个软件包, service命令属于initscripts软件包,chkconfig是一个单独的chkconfig软件包。

service命令非常好用,但是服务名和操作的顺序不太符合一些人的口味,如: service mysql start ; 有些人就经常写做: service start mysql

而,chkconfig虽然可以添加、查看服务,但是添加的服务脚本也有一点苛刻,脚本中需要添加:

别以为这是注释,没有的话,chkconfig add是不认的,如果不chkconfig add的话,chkconfig也list不出来你的服务的。

Centos7中服务的管理使用的是systemctl, 他是systemd软件包中的一个命令,该命令不仅仅管理服务,包括关机都能管

几个关键路径:

  1. 服务脚本目录: /usr/lib/systemd/system/
  2. 服务自动启动目录:/etc/systemd/system/
    systemctl enable xxx的时候就在这个目录下添加一个软连接到实际的脚本

参考资料: http://www.linuxidc.com/Linux/2015-04/116648.htm

 

systemd-vs-sysVinit-cheatsheet

 

数据结构 之 树

概述

树的章节一般分两大部分: 一部分将树,一部分将二叉树;虽然二叉树也是树,但是二叉树足够特殊,足够有用,所以重点来讲;或者说,如果不是二叉树,树的家族也不会如此的德高望重。

在二叉树中,又有一些特殊性质的二叉树,可能没法用树的结构来描述他们之间的关系;比如: 满二叉树一定是完全二叉树;完全二叉树和二叉排序树直接却没有从属关系;完全二叉树和二叉排序树是从不同的维度定义出来的特殊的二叉树。

二叉排序树(也叫二叉查找树)在树的家族中是一颗耀眼的明星,但是在树的章节中没有被介绍,大概因为这是二叉树的实际应用,而和树本身的形态没有直接关系;还有一些特殊的树,如:红黑树、B+、B-树,稍后再研究,有些数据结构的书是没有提及的,大概因为这些东西可以自学,不需要教吧。

树的逻辑结构

树的定义

树是n(n>=0)个结点的有限集合。当 n= 0 时,称为空树;任意一颗非空树满足一下两个条件:

  1. 有且只有一个特定的称为根的结点
  2. 当 n > 1 时,除根结点之外的其余结点被分成m(m>0)个互不相交的有限集合T1, T2, …, Tm,其中每个集合又是一棵树,并称为这个根结点的子树

树的基本术语

  1. 结点的度,树的度
  2. 叶子结点,分支结点
  3. 孩子结点,双亲结点,兄弟结点
  4. 路径、路径长度
  5. 祖先、子孙
  6. 结点的层数、树的深度(高度)
  7. 层序编号
  8. 有序树、无序树
  9. 森林
  10. 同构

树的表示形式

一般有四种表示形式:

  1. 树形图
  2. 嵌套图
  3. 凹凸表
  4. 广义表

树的遍历

  1. 前(根)序遍历
  2. 后(根)序遍历
  3. 层序遍历
    注: 这里说的是树,不是二叉树,所以没有中序遍历(如果有的话,三个子树的树根应该放哪里?)

树的存储结构

  1. 双亲表示法
    1. 思想: 每个结点都记住自己双亲结点的位置(即可保证该树是唯一的)
    2. 缺点: 要找到一个结点的所有孩子是比较麻烦的
    3. 使用数组存储还是比较方便的
  2. 孩子表示法
    1. 思想: 每个结点都记住自己孩子的位置(即可保证该树是唯一的)
    2. 缺点: 要找到结点的双亲结点比较麻烦
    3.  两种形式:
      1.  多重链表标识
        1. 思想: 父亲那N个绳拉住自己的N个孩子
        2. 关于拿几根绳?两种办法:
          1. 有几个孩子拿几根绳
            1. 需要有一个地方记录自己的绳子数目(就是该结点的度)
          2. 孩子最多的父亲拿几根绳子大家就都拿几根绳子
            1. 没人的绳子数目是一样的,不需要各自记录
      2. 孩子链表
        1. 思想:所有节点维护在一个数组中;然后,父亲拿一根绳子牵着老大,然后老大牵着老二;依次类推
  3. 孩子双亲表示法
    1. 思想:孩子表示法中,添加一个双亲节点的指针
  4. 孩子兄弟表示法
    1. 思想: 每个节点都左手拉着自己孩子,右手拉着自己的弟弟妹妹

二叉树

概述

二叉树是一种最简单的树结构,其存储结构更具有规范性和确定性,在一系列条件的约束下,使得二叉树具有很多的性质,方便我们研究和使用二叉树。

二叉树的定义

二叉树的5种基本形态

  1. 空二叉树
  2. 只有一个根结点
  3. 根结点只有左子树
  4. 根结点只有右子树
  5. 根结点既有左子树又有右子树

特殊二叉树

  1. 斜树
    1. 左斜树
    2. 右斜树
  2. 满二叉树
  3. 完全二叉树
    1. 从满二叉树的最后面的结点去掉n (n >= 0)个结点都是完全二叉树
    2. 满二叉树是一种特殊的完全二叉树

二叉树的性质

二叉树有5个重要的性质,他们主要讨论了树的深度、结点数等之间的关系

  1. 在二叉树的第i层上至多有2i-1个结点 (i >= 1)
  2. 深度为k的二叉树至多有2k-1个结点 (k >=1)
  3. 对任何一颗二叉树T,如果其叶子结点数为n0,度为2的结点数为n2,则:n0=n2+1
  4. 具有n个结点的完全二叉树的深度为log2n+1
  5. 如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有1.如果i=1,则节点是二叉树的根,无双亲,如果i>1,则其双亲节点为[i/2],向下取整

    2.如果2i>n那么节点i没有左孩子,否则其左孩子为2i

    3.如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1

二叉树的遍历

  1. 前序遍历
  2. 中序遍历
  3. 后序遍历

二叉树的存储

顺序表

思想: 将一棵树通过添加“虚节点”的方式完善成完全二叉树,然后存储

缺点: 空间浪费严重,只适合存储完全二叉树的情况

链式存储

  1. 二叉链表
    1. 思想: 每个结点包含数据域和左右孩子两个指针域
    2. 缺点: 寻找双亲结点不方便
  2. 三叉链表
    1. 思想: 在二叉链表的基础上添加双亲结点指针域

线索链表

实际问题: select * from tb where id < N limit 2; 在这种情况下,我们不仅要查到id=2的结点,还要找到他附近的一些结点;即: 需要访问二叉树中的结点在某种遍历序列中的前驱和后继;

于是: 在存储结构中应该保存结点在某种遍历序列中前驱和后继的信息。

思想: 根据二叉树的性质可知,二叉树中有n+1个指针域为空,可以想办法利用起来;通过添加标记来区分是孩子指针还是前驱(或后继)指针;注意: 挨着自己的孩子在线索化中未必就挨着自己,但是要找到挨着自己的那个结点并不难,对于中序线索链表,如果自己子树的深度为k,则,找到自己的前驱或后继的时间复杂度为log2k

由于二叉树的遍历次序有三种,因此有三种意义上的前驱和后继,相应的也有三种线索链表:前序线索链表、中序线索链表、后序线索链表。中序线索链表看起来更加直观一些

中序线索链表上求结点前驱
中序线索链表上求结点后继
中序线索链表上遍历

 

linux 之 fs.inotify

tail -f 时,有如下报错:

说明:tail -f 在远古的时候,是不断地轮询检查文件有没有更新,这个方式效率比较低;新石器时代,kernel提供了inotify机制,就是,你不需要总来问,只要你说一声,文件有更新的话我就通知你,strace 部分信息如下:

上面的错误是: 需要notify的文件太多超过最大限制了,修改方式如下:

修改 fs.inotify.max_user_instances 到一个更大的值

 

PAM配置ldap验证

PAM是linux上提供的一个可插拔认证模块,应该说还是比较强大、方便好用的,但是一旦配置不好,遇到问题也是不好解决的。

通过authconfig-tui图形界面配置是比较简单的,但是,现在有遇到问题了。

vsftpd通过ldap验证无法正常登录,如果去读pam的相关规范然后debugpam代码去发现问题将会花费很多的时间,怎么办呢?

首先, 通过strace、tcpdump确认ftp验证确实走了ldap而且返回结果是正确的。

其次, 确认ssh能正常登录

第三, 比较ssh、vsftpd的pam文件,通过注释掉一些行来验证是哪些配置有问题
注释掉如下行,问题解决:

man pam_shells

然后,cat /etc/shells

问题查到这里基本要结束了,因为记起我们的ldap中没有设置登录shell的属性

 

遗留问题: 为什么ldap中缺少登录shell的时候,ssh登录没有问题?

 

 

文件同步

场景:

同步大量文件从A到B, 先同步全量,在同步增量

scp同步文件也能同步目录,但是同步目录中的增量就不太好使了

  1. scp 可以同步目录,但是是完全覆盖目标目录,保持和源一样,重复复制,目标目录中多余的文件会被删掉(rsync效果一样)
  2. 不期望同步正在写的文件(比如,认为修改时间在1分钟前的文件是可以同步的;当然不能完全避免同步的时候又突然有写入)

脚本:

功能: 将目标机器的文件同步到本地对应目录(这里是相同目录)

注意:

  1. 同步2天内、1分钟前修改过的文件
  2. find命令的 -mtime 是以24小时为单位计算的,如:
    1. 24小时前、48小时内: -mtime 1
    2. 24小时内: -mtime 0
    3. 48小时内:-mtime -1
  3. -mmin 和 -mtime不太一样
    1. 1分钟内: -mmin 1  (而不是 -mmin 0)

ARP单播问题

ARP单播问题

虚拟机桥接到宿主机的网卡,虚拟机访问宿主机时有如下arp包:

说明:

arp查询之后会在本地缓存一段时间,当缓存超过一段时间后,可能实际信息已发生变化,于是发送一个单播的arp查询请求校验一下;话说既然可能会失效了,那么删掉重新查一次不行吗?

正常的arp请求是不知道某IP在哪里,只好广播,谁是谁响应;由于广播的开销比较大,所以,当我知道很有可能某IP就在你那里的话,我不妨先发个单播包校验一下,如果确实发生变化了,就再发送广播包不迟

参考: http://www.ietf.org/rfc/rfc1122.txt

linux 之 futex

当我们strace -c pid的时候,经常会发现futex占用大量时间,如下图:

那么, futex究竟是个什么东西呢?

futex – Fast Userspace Locking system call

一般来讲,futex是用于多线程程序中线程同步使用的; futex本身不是一个锁,但是可以利用这个机制实现锁。

传统的多线程同步是这样的(不保证说的对):

请求锁:

成功 –>干活 –> 干完 –> 发送信号给要加锁的线程

失败 –> 睡眠–> 收到信号–>继续请求锁

futex类似这样:

 

 

系统调用之 restart_syscall

在我们使用strace的时候,经常会遇到如下情景:

你们 restart_syscall 究竟是个什么系统调用呢?什么时候会用到该系统调用呢?

一般情况下,如果遇到这种情况,那么使用pstack看看进程的调用栈,会发现,很可能该进程处于sleep状态。

下面有一个实验:

回车之后,当看到nanosleep({5, 0},  立即ctrl-z,会发现程序stop了, 然后,输入 fg(切换后台任务到前台,继续运行),这时,又一次看到了restart_syscall 了,如下:

或许可以这么解释: 当程序收到一个信号时,离开正在执行的系统调用去处理信号,处理完信号(上面是直到收到一个sigcont信号才算处理完上刚才的信号),继续执行运来的系统调用,似乎就是通过restart_syscall 这个系统调用进入未完的那个系统调用的,所以说,看到restart_syscall意味着刚才的系统调用没有完成的时候被迫去做别的了;

为什么strace一个sleep的进程总会看到这个呢?

strace本身是先给正在执行的进程发了个信号(什么信号?….然后….),再然后发送SIGCONT信号让程序继续执行,于是,程序进入restart_syscall ; 当然,不是所有系统调用可以中断的,也不是所有系统调用中断后都能restart的,参考: man strace

 

总结:

  1. 你几乎永远没有机会去调用restart_syscall 这个系统调用的

参考资料: 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/