还没想好用什么标题

0%

转载:http://www.cnblogs.com/f-ck-need-u/p/7231832.html

expr命令可以实现数值运算、数值或字符串比较、字符串匹配、字符串提取、字符串长度计算等功能。它还具有几个特殊功能,判断变量或参数是否为整数、是否为空、是否为0等。

先看expr命令的info文档info coreutils ‘expr invocation’的翻译。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
16.4.1 字符串表达式
-------------------------
'expr'支持模式匹配和字符串操作。字符串表达式的优先级高于数值表达式和逻辑关系表达式。

'STRING : REGEX'
执行模式匹配。两端参数会转换为字符格式,且第二个参数被视为正则表达式(GUN基本正则),它默认会隐含前缀"^"。随后将第一个参数和正则模式做匹配。

如果匹配成功,且REGEX使用了'\('和'\)',则此表达式返回匹配到的。

如果匹配失败,如果REGEX中使用了'\('和'\)',则此表达式返回空字符串,否则返回为0。

只有第一个'\(...\)'会引用返回的值;其余的'\(...\)'只在正则表达式分组时有意义。

在正则表达式中,'\+','\?'和'\|'分表代表匹配一个或多个,0个或1个以及两端任选其一的意思。

'match STRING REGEX'
等价于'STRING : REGEX'。

'substr STRING POSITION LENGTH'
返回STRING字符串中从POSITION开始,长度最大为LENGTH的子串。如果POSITION或LENGTH为负数,0或非数值,则返回空字符串。

'index STRING CHARSET'
CHARSET中任意单个字符在STRING中最前面的字符位置。如果在STRING中完全不存在CHARSET中的字符,则返回0。见后文示例。

'length STRING'
返回STRING的字符长度。

'+ TOKEN'
将TOKEN解析为普通字符串,即使TOKEN是像MATCH或操作符"/"一样的关键字。这使得'expr length + "$x"'或'expr + "$x" : '.*/\(.\)''可以正常被测试,即使"$x"的值可能是'/'或'index'关键字。这个操作符是一个GUN扩展。
通用可移植版的应该使用'" $token" : ' \(.*\)''来代替'+ "$token"'。

要让expr将关键字解析为普通的字符,必须使用引号包围。

16.4.2 算术表达式
--------------------------

'expr'支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。

'+ -'
加减运算。两端参数会转换为整数,如果转换失败则报错。

'* / %'
乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。

16.4.3 逻辑关系表达式
---------------------------

'expr'支持普通的逻辑连接和逻辑关系。它的优先级最低。

'|'
如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。

经过测试,以上手册内容是错误的。正确的应该是:如果第一个参数非0,则返回第一个参数的值,否则返回第二个参数。但如果任意一个参数为空,则报错。除非空字符串使用引号包围,此时将和0的处理方式一样。

'&'
如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。

经过测试,以上手册内容是错误的。正确的应该是:如果两个参数都非0,则返回第一个参数,否则返回0。但任意一个参数为空,则报错。除非空字符串使用引号包围,此时将和0的处理方式一样。

'< <= = == != >= >'
比较两端的参数,如果为true,则返回1,否则返回0。"=="是"="的同义词。"expr"首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。

括号'()'可以改变优先级,但使用时需要使用反斜线对括号进行转义。

16.4.4 'expr'使用示例
-------------------------------

以下为expr的一些示例,其中有将shell的元字符使用引号包围的示例。

将shell中变量'foo'的值增加1:

foo=$(expr $foo + 1)

输出变量路径变量'$fname'中不包含'/'的文件名部分:

expr $fname : '.*/\(.*\)' '|' $fname

解释:其中的'|'是expr中的连接符,只不过是被引号包围防止被shell解析。例如$fname=/etc/hosts,则此表达式返回hosts,如果$fname=/usr/share/,则此表达式'|'的左边为空,所以返回'|'右边的值,即$fname,即返回/usr/share/。

An example showing that '\+' is an operator:

expr aaa : 'a\+' # 解释:因为REGEX部分没有使用\(\),所以返回匹配的字符数
=> 3

expr abc : 'a\(.\)c' # 解释:因为REGEX部分使用了\(\),所以返回匹配的字符
=> b
expr index abcdef cz
=> 3
expr index index a # 解释:因为第二个index是关键字
error-> expr: syntax error
expr index + index a # 解释:使用+将index关键字解析为普通字符串
=> 0

下面将使用示例来介绍expr的用法,在介绍之前,需要注意三点:

1
2
3
4
5
(1).数值表达式("+ - * / %")和比较表达式("< <= = == != >= >")会先将两端的参数转换为数值,转换失败将报错。所以可借此来判断参数或变量是否为整数。

(2).expr中的很多符号需要转义或使用引号包围。

(3).所有操作符的两边,都需要有空格。

以下是expr示例。

1. “string : REGEX”字符串匹配示例。要输出匹配到的字符串结果,需要使用”(“和”)“,否则返回的将是匹配到的字符串数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@xuexi ~]# expr abcde : 'ab\(.*\)'
cde

[root@xuexi ~]# expr abcde : 'ab\(.\)'
c

[root@xuexi ~]# expr abcde : 'ab.*'
5

[root@xuexi ~]# expr abcde : 'ab.'
3

[root@xuexi ~]# expr abcde : '.*cd*'
4

注意,由于REGEX中隐含了”^”,所以使得匹配时都是从string首字符开始的。

1
2
[root@xuexi ~]# expr abcde : 'cd.*'  
0

之所以为0,是因为真正的正则表达式是"^cd.*",而abcde不是c开头而是a开头的,所以无法匹配到任何结果。因此,任何字符串匹配时,都应该从首字符开始。

字符串匹配时,会先将两端参数转换为字符格式。

2. “index string chars”用法示例。

该表达式是从string中搜索chars中某个字符的位置,这个字符是string中最靠前的字符。例如:

1
2
[root@xuexi ~]# expr index abcde dec
3

该命令将对字符串”dec”逐字符分解,首先分解得到第一个字符d,从abcde中搜索到d的位置为4,再分解得到第二个字符e,该字符在abcde中的位置为5,最后得到的字符是c,该字符在abcde中的位置为3。其中3是最靠前的字符,所以命令返回的结果为3。

1
2
[root@xuexi ~]# expr index abcde xdc
3

如果chars中的所有字符都不存在于string中,则返回0。

1
2
3
4
5
[root@xuexi ~]# expr index abcde 1
0

[root@xuexi ~]# expr index abcde 1x
0

3. “substr string pos len”用法示例。

该表达式是从string中取出从pos位置开始长度为len的子字符串。如果pos或len为非正整数时,将返回空字符串。

1
2
3
4
5
6
7
8
9
10
11
12
[root@xuexi ~]# expr substr abcde 2 3
bcd

[root@xuexi ~]# expr substr abcde 2 4
bcde

[root@xuexi ~]# expr substr abcde 2 5
bcde

[root@xuexi ~]# expr substr abcde 2 0

[root@xuexi ~]# expr substr abcde 2 -1

4. “length string”用法示例。该表达式是返回string的长度,其中string不允许为空,否则将报错,所以可以用来判断变量是否为空。

1
2
3
4
5
6
7
8
9
10
11
[root@xuexi ~]# expr length abcde
5

[root@xuexi ~]# expr length 111
3

[root@xuexi ~]# expr length $xxx
expr: syntax error

[root@xuexi ~]# if [ $? -ne 0 ];then echo '$xxx is null';fi
$xxx is null

5. “+ token”用法示例。

expr中有些符号和关键字有特殊意义,如”match”、”index”、”length”,如果要让其成为字符,使用该表达式将任意token强制解析为普通字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@xuexi ~]# expr index index d
expr: syntax error

[root@xuexi ~]# expr index length g
expr: syntax error

[root@xuexi ~]# expr index + length g
4
其实可以通过字符串匹配的方式,将关键字转换为字符串。例如:

[root@xuexi ~]# expr index 'length : "\(length\)"' g
4
对值为关键字的变量来说,则无所谓。

[root@xuexi ~]# len=lenght

[root@xuexi ~]# expr index $len g
4

6. 算术运算用法示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@xuexi ~]# expr 1 + 2
3

[root@xuexi ~]# a=3
[root@xuexi ~]# b=4

[root@xuexi ~]# expr $a + $b
7

[root@xuexi ~]# expr 4 + $a
7

[root@xuexi ~]# expr $a - $b
-1
`

算术乘法符号”*”因为是shell的元字符,所以要转义,可以使用引号包围,或者使用反斜线。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@xuexi ~]# expr $a * $b
expr: syntax error

[root@xuexi ~]# expr $a '*' $b
12

[root@xuexi ~]# expr $a \* $b
12

[root@xuexi ~]# expr $b / $a # 除法只能取整数
1

[root@xuexi ~]# expr $b % $a
1

任意操作符两端都需要有空格,否则:

1
2
3
4
5
[root@xuexi ~]# expr 4+$a 
4+3

[root@xuexi ~]# expr 4 +$a
expr: syntax error

由于expr在进行算术运算时,首先会将操作符两边的参数转换为整数,任意一端转换失败都将会报错,所以可以用来判断参数或变量是否为整数。

1
2
3
4
5
[root@xuexi ~]# expr $a + $c
expr: non-integer argument

[root@xuexi ~]# if [ $? != 0 ];then echo '$a or $c is non-integer';fi
$a or $c is non-integer

7. 比较操作符< <= = == != >= >用法示例。其中”<”和”>”是正则表达式正的锚定元字符,且”<”会被shell解析为重定向符号,所以需要转义或用引号包围。

这些操作符会首先会将两端的参数转换为数值,如果转换成功,则采用数值比较,如果转换失败,则按照字符集的排序规则进行字符大小比较。比较的结果若为true,则expr返回1,否则返回0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@xuexi ~]# a=3

[root@xuexi ~]# expr $a = 1
0

[root@xuexi ~]# expr $a = 3
1

[root@xuexi ~]# expr $a \* 3 = 9
1

[root@xuexi ~]# expr abc \> ab
1

[root@xuexi ~]# expr akc \> ackd
1

8. 逻辑连接符号”&”和”|”用法示例。这两个符号都需要转义,或使用引号包围。

以下是官方文档中给出的解释,但实际使用过程中是不完全正确的。

1
2
3
"&"表示如果两个参数同时满足非空且非0,则返回第一个参数的值,否则返回0。且如果发现第一个参数为空或0,则直接跳过第二个参数不做任何计算。

"|"表示如果第一个参数非空且非0,则返回第一个参数值,否则返回第二个参数值,但如果第二个参数为空或为0,则返回0。且如果发现第一个参数非空或非0,也将直接跳过第二个参数不做任何计算。

正确的应该是:

1
2
3
"&"表示如果两个参数都非0,则返回第一个参数,否则返回0。但任意一个参数为空,则expr报错。除非空字符串使用引号包围,则处理方法和0一样。

"|"表示如果第一个参数非0,则返回第一个参数的值,否则返回第二个参数。但如果任意一个参数为空,则expr报错。除非空字符串使用引号包围,则处理方法和0一样。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@xuexi ~]# expr $abc '|' 1
expr: syntax error

[root@xuexi ~]# expr "$abc" '|' 1
1

[root@xuexi ~]# expr "$abc" '&' 1
0

[root@xuexi ~]# expr $abc '&' 1
expr: syntax error

[root@xuexi ~]# expr 0 '&' abc
0

[root@xuexi ~]# expr abc '&' 0
0

[root@xuexi ~]# expr abc '|' 0
abc

[root@xuexi ~]# expr 0 '|' abc
abc

[root@xuexi ~]# expr abc '&' cde
abc

[root@xuexi ~]# expr abc '|' cde
abc

ELK的简单科普文章,加入了自己的一些理解。 内容包括ELK的基本介绍, 应用场景, 架构设计, 监控及自监控, 业界进展及推荐资料等。

用户故事

场景一

作为一个运维工程师, 某天虚拟机出现故障, 想看看虚拟机是否有异常日志,物理机上是否有异常日志, 管理物理机的云平台/系统是否有发生异常日志, 一个个主机 系统登陆过去, 输入账号密码费时费力,有时还会出现记不住密码干着急的情况,大大影响了排障的效率。 有没有一个系统,能够集中查看和搜索日志,不需要繁琐的登陆, 方便的获取排障所需的重要信息, 有异常还能够订阅?

场景二

作为一个开发人员, 开发的系统经常需要调用外部的api, 每次出现问题需要去查看日志,看是哪个环节出现问题, 是调用第三方api出错,还是连接数据库出错,只能一个一个查。 另外还会遇到的问题是, 有时候无意中grep了一个大的文件,导致iowait冲高,引发不必要的系统异常告警。 有没有一个工具能够提供各种仪表盘,每次打开一个页面就能一目了然的看到调用各个api的情况,调用了多少次, 失败了多少次?

场景三

开发人员上线新版本,上线过程中可能会出现各种问题。 有时不能及时发现会引起哪些异常,对其它系统有哪些影响。有没有一个工具 可以看到和分析上线新版本前后的变化?这样 就能有助于分析相应的故障是否是和上线新版本有关了。

场景四

作为一个团队领导, 团队开发产品已经上线一段时间了, 希望看到产品有多少人访问, 哪个功能访问了多少次,模块的出错率如何,每次都到机器上去跑分析脚本,费时费力,还不直观, 如果产品部署在分布式集群统计起来更是麻烦, 有没有一个系统能以更加简便的方式可以查看到这些情况?

上述的问题,ELK统统可以解决。

ELK是什么鬼?

简而言之, 如果说日志是埋在土里的宝藏,那么ELK是开采宝藏的蓝翔挖掘机。

概述

ELK是一套解决方案而不是一款软件, 三个字母分别是三个软件产品的缩写。 E代表Elasticsearch,负责日志的存储和检索; L代表Logstash, 负责日志的收集,过滤和格式化;K代表Kibana,负责日志的展示统计和数据可视化。

其中Elasticsearch是整个ELK的核心, L和K都有相应的替代方案。 这里重点介绍下ElasticSearch(下面简称es)的一些知识。

相关架构概念

上面是一个1个node, 2个replica, 3个shard的结构
cluster(集群)由多个node(节点)组成
数据会被索引,并保存在index里(类比RDBMS里的DB)
一个index可以切成多个shard(分片),每个shard可以有多个replica(副本)
node分为三种类型, 分别是master node,data node ,client node。 每个cluster会有一个node被选举成master,负责维护cluster state data。
shard均匀分布在所有可用的data node
ES 和 关系型数据库的概念比较

ES本身可以理解为自带搜索引擎的数据库。 有些概念可以和关系型数据库(比如说MySQL) 进行对比。 概念的对比如下表所示:

ELK vs Linux Grep

ELK能做什么?

应用场景

安全领域
通过分析系统日志, 发现攻击或者非法访问行为,可以追踪定位相关安全问题。 比如结合FreeIPA(一款集成的安全信息管理解决方案), 可以做一些暴力破解行为可视化分析等。

网络领域
日志分析和监控可以作为网络设备监控的一种补充, 其它监控系统,如zabbix大多是通过snmp的方式来获取网络设备的性能数据, 这种方式有其局限性,如无法监控端口的flapping, 无法监测到设备引擎挂掉等情况。 此外由于snmp监控的方案通用型不好, 各个厂商有自己的私有OID, 意味着需要对这些不同的厂商适配不同的监控模板。 另外, snmp获取数据的实时性相对会比syslog日志慢一些。

应用领域
分析和展示移动端业务的实时情况,如设备类型分析, 业务访问量, 业务访问高峰情况等;分析nginx日志得到网站的访问情况,如网站点击数, api请求总数、平均每秒请求数、峰值请求数,可以大体了解系统压力,作为系统扩容、性能及压力测试时的直接参考。

另类应用
用于社会工程学的用户画像;函数堆栈调用分析;网络流量分析

ELK落地方案

架构选型

下面是一种常见的ELK架构

这个架构的优点是简单,维护起来也方便。 但是也有一些问题。

shipper耗主机资源。 直接用logstash当作日志采集的agent, 会比较重,会占用不少主机资源, 因此官方现在已经不推荐用logstash当shipper了, 推荐使用beat。
权限控制的问题。 kbana自身对页面访问权限控制这块是比较弱。 如果希望对页面的访问权限做控制, 可以考虑使用es search guard + ldap + nginx的方案来实现。
跨网络分区的问题 。如果有多个数据中心,且日志的流量比较大, 让日志跨网络分区进行传输,无疑会占用不少宝贵的专线带宽资源,会增加运营的成本,且有可能影响到其它应用的正常运行。 有一个解决此类问题的方案, 在各个网络分区各搭建一套ELK集群,日志不跨网络分区进行传输, 然后单独使用某些es节点作为tribe角色, 对搜索请求进行合并和路由。
为解决上面提到的问题, 设计了以下架构:

当然, 上面的架构也不是一层不变。如果日志量更大,可以考虑使用hangout来代替logstash, 用kafka来替代redis, 从而获得更大的日志吞吐量。

监控告警

日志的告警

可以采用elastalert。 当然也可以自己开发应用从es或者kafka取数据来做分析。

自身的监控

使用zabbix 监控。 网上可以找到对应的模版。
使用官方提供的marvel方案, 不过是收费的。
使用open falcon监控。 我们内部有一套open falcon系统, 所以我们尝试用open falcon来监控es集群。
挑战和思路

SaaS化

就是把ELK提供为SaaS服务,目前新浪云, 青云, aws等云平台上面已经有相应的服务了。 把日志分析系统SaaS化, 可以免去用户搭建和维护elk集群的麻烦,减少用户的使用成本,同时也可以给云平台自身带来更多的附加值。

大数据分析

用ELK堆栈来存储和索引海量的日志数据, 后面再结合大数据分析和机器学习工具,可以做智能运维分析, 减少运维人员之苦。

推荐资料

《Elasticsearch 权威指南》
《ELK中文指南》
《Mastering ElasticSearch》
《Manning Elasticsearch in Action》

参考《深入理解Linux内核》 第十七章

针对ext2文件系统,先说下对当个文件大小限制

Block 大小 1KB 2KB 4KB
最大單一檔案限制 16GB 256GB 2TB
最大檔案系統總容量 2TB 8TB 16TB

示例计算大小


ext2以一种特殊的文件实现了目录,这种文件的数据块存放了文件名和吸纳高硬度索引节点号。特别说明的是,这样的数据块包含了类型为ext2_dir_entry_2的结构。下表列出了这个结构的域,因为该结构最后一个名字域是最大为ext2_name_len(通常是255)个字符的边长数组,因此这个结构的长度是可变的。此外,因为效率的原因,一个目录项的长度总是4的倍数,并在必要时用null自读(\0) 填充文件名的末尾。name_len域存放实际的文件名长度

类型 描述
__u32 inode 索引节点号
__u16 rec_len 目录项长度
__u8 name_len 文件名长度
__u8 file_type 文件类型
char [ext2_name_len] name 文件名

file_type域存放制定的文件类型的值, rec_len域可以被解释为指向下一个有效目录项的指针:他是偏移量,与目录项的起始地址相加就得到下一个有效目录项的起始地址。为了删除一个目录项,把他的inode域置为0并适当地增加前一个有效目录项rec——len域的值就足够了。仔细看一下图 rec_len域,你会发现”oldfile“项已被删除,因为”usr”的”rec_len”域被置为12+16 (”usr”和 “odlfile”目录项的长度)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
                      file_type---+
|
name_len---+ |
| |
inode rec_len | | name
+-----------------+--------+----+----+----+----+----+----+
| 21 | 12 | 1 | 2 | . | \0 | \0 | \0 |
+-----------------+--------+----+----+----+----+----+----+
| 22 | 12 | 2 | 2 | . | . | \0 | \0 |
+-----------------+--------+----+----+----+----+----+----+----+----+----+----+
| 53 | 16 | 5 | 2 | h | o | m | e | 1 | \0 | \0 | \0 |
+-----------------+--------+----+----+----+----+----+----+----+----+----+----+
| 67 | 28 | 3 | 2 | u | s | r | \0 |
+-----------------+--------+----+----+----+----+----+----+----+----+----+----+
| 0 | 16 | 7 | 1 | o | l | d | f | i | l | e | \0 |
+-----------------+--------+----+----+----+----+----+----+----+----+----+----+
| 34 | 12 | 4 | 2 | s | b | i | n |
+-----------------+--------+----+----+----+----+----+----+

下面做个简单的测试
先随机生成84个40字符长度的文件 按照前面的介绍占用空间(84个文件加两个目录)应该有 84(40+8) + (8 + 4)2= 4056

1
mkdir /tmp/dir1 && for num in `seq 1 84`; do mktemp --tmpdir=/tmp/dir1 --suffix=.txt  dd79fcba-c737-4854-ba33-bb222ceab513.XXX;done

看下目前的文件目录大小

1
2
3
4
5
6
7
8
9
10
11
drwxr-xr-x  2 root root 4096 Oct 10 19:07 ./
drwxrwxrwt 11 root root 4096 Oct 10 19:07 ../
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_11gCHL.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_1ZiBMU.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_2DMtQw.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_30VwjB.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_34bGTx.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_3BdNFC.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_3X9Bfu.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_4WHZMV.txt
.......

这样还有 4096-4056=40
我们在生成一个32字符长度的文件

1
touch 12345678901234567890123456789012

这样再看下文件夹大小

1
2
3
4
5
6
7
8
9
10
drwxr-xr-x  2 root root 4096 Oct 10 19:08 ./
drwxrwxrwt 11 root root 4096 Oct 10 19:07 ../
-rw-r--r-- 1 root root 0 Oct 10 19:08 12345678901234567890123456789012
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_11gCHL.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_1ZiBMU.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_2DMtQw.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_30VwjB.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_34bGTx.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_3BdNFC.txt
......

删除刚创建的32字符长度文件后建立一个30字符长度的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
rm 12345678901234567890123456789012

touch 123456789012345678901234567890

drwxr-xr-x 2 root root 4096 Oct 10 19:11 ./
drwxrwxrwt 11 root root 4096 Oct 10 19:10 ../
-rw-r--r-- 1 root root 0 Oct 10 19:11 123456789012345678901234567890
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_11gCHL.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_1ZiBMU.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_2DMtQw.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_30VwjB.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_34bGTx.txt
......

目录大小保持4096, 这样删除30字符大小文件,建立33字符长度文件

1
2
3
4
5
6
7
8
9
10
11
12
13
rm 123456789012345678901234567890

touch 123456789012345678901234567890123

drwxr-xr-x 2 root root 12288 Oct 10 19:13 ./
drwxrwxrwt 11 root root 4096 Oct 10 19:10 ../
-rw-r--r-- 1 root root 0 Oct 10 19:13 123456789012345678901234567890123
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_11gCHL.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_1ZiBMU.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_2DMtQw.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_30VwjB.txt
-rw------- 1 root root 0 Oct 10 19:07 random_forty_length_file_name_34bGTx.txt
......

按照计算 (40+8)84 + (32+8)1 + (4+8)*2 = 4096
所以建立33个字符长度的文件时,超出一个block大小, 需要另外申请block存储了,这里还有一个地方需要注意 文件系统并不是只申请一个block,而是一次性申请了两个 目录大小达到了 12288

原文:
Why does running a background task over ssh fail if a pseudo-tty is allocated?

问题:
I’ve recently run into some slightly odd behaviour when running commands over ssh. I would be interested to hear any explanations for the behaviour below.

Running ssh localhost 'touch foobar &' creates a file called foobar as expected:

1
2
3
[bob@server ~]$ ssh localhost 'touch foobar &'
[bob@server ~]$ ls foobar
foobar

However running the same command but with the -t option to force pseudo-tty allocation fails to create foobar:

1
2
3
4
5
6
[bob@server ~]$ ssh -t localhost 'touch foobar &'
Connection to localhost closed.
[bob@server ~]$ echo $?
0
[bob@server ~]$ ls foobar
ls: cannot access foobar: No such file or directory

My current theory is that because the touch process is being backgrounded the pseudo-tty is allocated and unallocated before the process has a chance to run. Certainly adding one second sleep allows touch to run as expected:

1
2
3
4
[bob@pidora ~]$ ssh -t localhost 'touch foobar & sleep 1'
Connection to localhost closed.
[bob@pidora ~]$ ls foobar
foobar

回答:
This is related with how process groups work, how bash behaves when invoked as a non-interactive shell with -c, and the effect of & in input commands.

The answer assumes you’re familiar with how job control works in UNIX; if you’re not, here’s a high level view: every process belongs to a process group (the processes in the same group are often put there as part of a command pipeline, e.g. cat file | sort | grep 'word' would place the processes running cat(1), sort(1) and grep(1) in the same process group). bash is a process like any other, and it also belongs to a process group. Process groups are part of a session (a session is composed of one or more process groups). In a session, there is at most one process group, called the foreground process group, and possibly many background process groups. The foreground process group has control of the terminal (if there is a controlling terminal attached to the session); the session leader (bash) moves processes from background to foreground and from foreground to background with tcsetpgrp(3). A signal sent to a process group is delivered to every process in that group.

If the concept of process groups and job control is completely new to you, I think you’ll need to read up on that to fully understand this answer. A great resource to learn this is Chapter 9 of Advanced Programming in the UNIX Environment (3rd edition).

That being said, let’s see what is happening here. We have to fit together every piece of the puzzle.

In both cases, the ssh remote side invokes bash(1) with -c. The -c flag causes bash(1) to run as a non-interactive shell. From the manpage:

An interactive shell is one started without non-option arguments and without the -c option whose standard input and error are both connected to terminals (as determined by isatty(3)), or one started with the -i option. PS1 is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this state.

Also, it is important to know that job control is disabled when bash is started in non-interactive mode. This means that bash will not create a separate process group to run the command, since job control is disabled, there will be no need to move this command between foreground and background, so it might as well just remain in the same process group as bash. This will happen whether or not you forced PTY allocation on ssh with -t.

However, the use of & has the side effect of causing the shell not to wait for command termination (even if job control is disabled). From the manpage:

If a command is terminated by the control operator &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0. Commands separated by a ; are executed sequentially; the shell waits for each command to terminate in turn. The return status is the exit status of the last command executed.

So, in both cases, bash will not wait for command execution, and touch(1) will be executed in the same process group as bash(1).

Now, consider what happens when a session leader exits. Quoting from setpgid(2) manpage:

If a session has a controlling terminal, and the CLOCAL flag for that terminal is not set, and a terminal hangup occurs, then the session leader is sent a SIGHUP. If the session leader exits, then a SIGHUP signal will also be sent to each process in the foreground process group of the controlling terminal.

When you don’t use -t

When you don’t use -t, there is no PTY allocation on the remote side, so bash is not a session leader, and in fact no new session is created. Because sshd is running as a daemon, the bash process that is forked + exec()’d will not have a controlling terminal. As such, even though the shell terminates very quickly (probably before touch(1)), there is no SIGHUP sent to the process group, because bash wasn’t a session leader (and there is no controlling terminal). So everything works.

When you use -t

-t forces PTY allocation, which means that the ssh remote side will call setsid(2), allocate a pseudo-terminal + fork a new process with forkpty(3), connect the PTY master device input and output to the socket endpoints that lead to your machine, and finally execute bash(1). forkpty(3) opens the PTY slave side in the forked process that will become bash; since there’s no controlling terminal for the current session, and a terminal device is being opened, the PTY device becomes the controlling terminal for the session and bash becomes the session leader.

Then the same thing happens again: touch(1) is executed in the same process group, etc., yadda yadda. The point is, this time, there is a session leader and a controlling terminal. So, since bash does not bother waiting because of the &, when it exits, SIGHUP is delivered to the process group and touch(1) dies prematurely.

About nohup

nohup(1) doesn’t work here because there is still a race condition. If bash(1) terminates before nohup(1) has the chance to set up the necessary signal handling and file redirection, it will have no effect (which is probably what happens)

A possible fix

Forcefully re-enabling job control fixes it. In bash, you do that with set -m. This works:

1
ssh -t localhost 'set -m ; touch foobar &'

Or force bash to wait for touch(1) to complete:

1
ssh -t localhost 'touch foobar & wait `pgrep touch`'

mongodb同步

py-mongo-sync

MongodbSync

mongodb 的一个同步工具,具备将一个数据源上的数据,同步到其它 mongodb 上,支持:

mongos -> (mongos, mongod)
mongod -> (mongos, mongod)
如果源是 mongos,情况比较复杂,需要从 mongos 里将副本信息全部取出来,同步到 mongod 中; 需要注意的是,源和目的 mongo,都需要使用 admin 账号,以取得所有权限; 支持 oplog 格式为:”ts” : Timestamp(1372320938000, 1) 目前的 2.6.4 版本是这种格式;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sync-info
mode: 取值为 incr 表示增量同步;all 表示全量同步,会将源数据拷贝到目标库;smart 表示智能同步,会先全量拷贝,再进行增量;
record_interval: 读取了一定量数据,会对 optime 进行更新;
record_time_interval: 读取了一定的时间,会对 optime 进行更新;
opt_file: optime 记录在 该文件中,all 模式在拷贝完更新它,incr, smart 模式不定期更新它,如果文件不存在则默认从 1 小时前同步;
all_dbs: 为 true 表示同步全部的数据库, 不包括 admin,config,local, 否则同步 dbs;
dbs: 需要同步的数据库集合,不包括 admin,config,local,如果要同步某个db下的collection,使用 db.collection 形式;
queue_num: 队列最大数目,暂无使用该参数,代码里固定了是 20000;
threads: 线程数,由于源和目的 的网络状况可能不一样,可以有多个连接去写目的地址;

mongo-src
addr: 源地址,可以是一个副本集,也可以是 mongos,如果是 mongos,系统会自动连接到相应的副本集;
user: 管理员账号
pwd: 管理员密码

mongo-dest
addr: 目的地址,可以是一个副本集,也可以是 mongos;
user: 管理员账号
pwd: 管理员密码

当目的没有数据库时和集合时:会自动创建,包括索引

当源为 mongos 时:所有副本集的内容会同步过去;

当源为 副本集 时:所有副本集的内容会同步过去;

增加、删除、修改 数据命令:OK;

增加、删除 collection 时:OK;

db 级别的操作:忽略;

同步性能:取决于网络带宽;

容错能力:能处理源和目的的网络异常,系统有容错处理能力;

参考金步国翻译的systemd中文手册: http://www.jinbuguo.com/systemd/index.html
金步国翻译质量都很高, 非常适合做参考

原文:https://wiki.archlinux.org/index.php/Systemd_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

systemd 是 Linux 下的一款系统和服务管理器,兼容 SysV 和 LSB 的启动脚本。systemd 的特性有:支持并行化任务;同时采用 socket 式与 D-Bus 总线式激活服务;按需启动守护进程(daemon);利用 Linux 的 cgroups 监视进程;支持快照和系统恢复;维护挂载点和自动挂载点;各服务间基于依赖关系进行精密控制。

systemd 基本工具

监视和控制systemd的主要命令是systemctl。该命令可用于查看系统状态和管理系统及服务。详见systemctl(1)

提示:

  • 在 systemctl 参数中添加 -H <用户名>@<主机名> 可以实现对其他机器的远程控制。该功能使用 SSH 连接。
  • systemadm 是 systemd 的官方图形前端。官方软件仓库提供了稳定版本 systemd-ui 。
  • Plasma 用户可以安装 systemctl 图形前端 systemd-kcm。安装后可以在 System administration 下找到。

分析系统状态

显示 系统状态:

1
$ systemctl status

输出激活的单元:

1
$ systemctl

以下命令等效:

1
$ systemctl list-units

输出运行失败的单元:

1
$ systemctl --failed

所有可用的单元文件存放在 /usr/lib/systemd/system/ 和 /etc/systemd/system/ 目录(后者优先级更高)。查看所有已安装服务:

1
$ systemctl list-unit-files

使用单元

一个单元配置文件可以描述如下内容之一:系统服务(.service)、挂载点(.mount)、sockets(.sockets) 、系统设备(.device)、交换分区(.swap)、文件路径(.path)、启动目标(.target)、由 systemd 管理的计时器(.timer)。详情参阅 systemd.unit(5)
使用 systemctl 控制单元时,通常需要使用单元文件的全名,包括扩展名(例如 sshd.service )。但是有些单元可以在 systemctl 中使用简写方式。

  • 如果无扩展名,systemctl 默认把扩展名当作 .service 。例如 netcfg 和 netcfg.service 是等价的。
  • 挂载点会自动转化为相应的 .mount 单元。例如 /home 等价于 home.mount 。
  • 设备会自动转化为相应的 .device 单元,所以 /dev/sda2 等价于 dev-sda2.device 。

注意: 有一些单元的名称包含一个 @ 标记(例如: [email protected] ),这意味着它是模板单元 [email protected] 的一个 实例。 string 被称作实例标识符,在 systemctl 调用模板单元时,会将其当作一个参数传给模板单元,模板单元会使用这个传入的参数代替模板中的 %I 指示符。

在实例化之前,systemd 会先检查 [email protected] 文件是否存在(如果存在,就直接使用这个文件,而不是模板实例化)。大多数情况下,包含 @ 标记都意味着这个文件是模板。如果一个模板单元没有实例化就调用,该调用会返回失败,因为模板单元中的 %I 指示符没有被替换。

提示:

  • 下面的大部分命令都可以跟多个单元名, 详细信息参见 systemctl(1)。
  • systemctl命令在enable、disable和mask子命令中增加了–now选项,可以实现激活的同时启动服务,取消激活的同时停止服务。
  • 一个软件包可能会提供多个不同的单元。如果你已经安装了软件包,可以通过pacman -Qql package | grep systemd命令检查这个软件包提供了哪些单元。

立即激活单元:

1
# systemctl start <单元>

立即停止单元:

1
# systemctl stop <单元>

重启单元:

1
# systemctl restart <单元>

重新加载配置:

1
# systemctl reload <单元>

输出单元运行状态:

1
$ systemctl status <单元>

检查单元是否配置为自动启动:

1
$ systemctl is-enabled <单元>

开机自动激活单元:

1
# systemctl enable <单元>

取消开机自动激活单元:

1
# systemctl disable <单元>

禁用一个单元(禁用后,间接启动也是不可能的):

1
# systemctl mask <单元>

取消禁用一个单元:

1
# systemctl unmask <单元>

显示单元的手册页(必须由单元文件提供):

1
# systemctl help <单元>

重新载入 systemd,扫描新的或有变动的单元:

1
# systemctl daemon-reload

电源管理

安装 polkit 后才能以普通用户身份使用电源管理。
如果你正登录在一个本地的 systemd-logind 用户会话,且当前没有其它活动的会话,那么以下命令无需 root 权限即可执行。否则(例如,当前有另一个用户登录在某个 tty ), systemd 将会自动请求输入root密码。

重启:

1
$ systemctl reboot

退出系统并关闭电源:

1
$ systemctl poweroff

待机:

1
$ systemctl suspend

休眠:

1
$ systemctl hibernate

混合休眠模式(同时休眠到硬盘并待机):

1
$ systemctl hybrid-sleep

编写单元文件

systemd 单元文件的语法来源于 XDG 桌面项配置文件.desktop文件,最初的源头则是Microsoft Windows的.ini文件。单元文件可以从两个地方加载,优先级从低到高分别是:

  • /usr/lib/systemd/system/ :软件包安装的单元
  • /etc/systemd/system/ :系统管理员安装的单元
  • 当 systemd 运行在用户模式下时,使用的加载路径是完全不同的。
  • systemd 单元名仅能包含 ASCII 字符,下划线和点号。其它字符需要用 C-style “\x2d” 替换。参阅 systemd.unit(5) 和 systemd-escape(1) 。}}

单元文件的语法,可以参考系统已经安装的单元,也可以参考 systemd.service(5) 中的EXAMPLES章节。

提示: 以 # 开头的注释可能也能用在 unit-files 中,但是只能在新行中使用。不要在 systemd 的参数后面使用行末注释, 否则 unit 将会启动失败。

处理依赖关系

使用 systemd 时,可通过正确编写单元配置文件来解决其依赖关系。典型的情况是,单元 A 要求单元 B 在 A 启动之前运行。在此情况下,向单元 A 配置文件中的 [Unit] 段添加 Requires=B 和 After=B 即可。若此依赖关系是可选的,可添加 Wants=B 和 After=B 。请注意 Wants= 和 Requires= 并不意味着 After= ,即如果 After= 选项没有制定,这两个单元将被并行启动。
依赖关系通常被用在服务(service)而不是目标(target)上。例如, network.target 一般会被某个配置网络接口的服务引入,所以,将自定义的单元排在该服务之后即可,因为 network.target 已经启动。

服务类型

编写自定义的 service 文件时,可以选择几种不同的服务启动方式。启动方式可通过配置文件 [Service] 段中的 Type= 参数进行设置。

  • Type=simple :(默认值) systemd认为该服务将立即启动。服务进程不会 fork 。如果该服务要启动其他服务,不要使用此类型启动,除非该服务是socket 激活型。
  • Type=forking :systemd认为当该服务进程fork,且父进程退出后服务启动成功。对于常规的守护进程(daemon),除非你确定此启动方式无法满足需求,使用此类型启动即可。使用此启动类型应同时指定 PIDFile=,以便 systemd 能够跟踪服务的主进程。
  • Type=oneshot :这一选项适用于只执行一项任务、随后立即退出的服务。可能需要同时设置 RemainAfterExit=yes 使得 systemd 在服务进程退出之后仍然认为服务处于激活状态。
  • Type=notify :与 Type=simple 相同,但约定服务会在就绪后向 systemd 发送一个信号。这一通知的实现由 libsystemd-daemon.so 提供。
  • Type=dbus :若以此方式启动,当指定的 BusName 出现在DBus系统总线上时,systemd认为服务就绪。
  • Type=idle :systemd会等待所有任务处理完成后,才开始执行 idle 类型的单元。其他行为与 Type=simple 类似。
    type 的更多解释可以参考 systemd.service(5)。

修改现存单元文件

为了避免和 pacman 冲突,不应该直接编辑软件包提供的文件。要更改由软件包提供的单元文件,先创建名为 /etc/systemd/system/<单元名>.d/ 的目录(如 /etc/systemd/system/httpd.service.d/) ,然后放入 *.conf 文件,其中可以添加或重置参数。这里设置的参数优先级高于原来的单元文件。例如,如果想添加一个额外的依赖,创建如下文件即可:

1
2
3
4
/etc/systemd/system/<unit>.d/customdependency.conf
[Unit]
Requires=<新依赖>
After=<新依赖>

As another example, in order to replace the ExecStart directive for a unit that is not of type oneshot, create the following file:

1
2
3
4
/etc/systemd/system/unit.d/customexec.conf
[Service]
ExecStart=
ExecStart=new command

修改 ExecStart 前必须将其置空,参见 ([1] 。所有可能多次赋值的变量都需要这个操作,例如定时器的 OnCalendar 。
下面是自动重启服务的一个例子:

1
2
3
4
/etc/systemd/system/unit.d/restart.conf
[Service]
Restart=always
RestartSec=30

然后运行以下命令使更改生效:

1
2
# systemctl daemon-reload
# systemctl restart <单元>

此外,把旧的单元文件从 /usr/lib/systemd/system/ 复制到 /etc/systemd/system/,然后进行修改,也可以达到同样效果。在 /etc/systemd/system/ 目录中的单元文件的优先级总是高于 /usr/lib/systemd/system/ 目录中的同名单元文件。注意,当 /usr/lib/ 中的单元文件因软件包升级变更时,/etc/ 中自定义的单元文件不会同步更新。此外,你还得执行 systemctl reenable ,手动重新启用该单元。因此,建议使用前面一种利用 *.conf 的方法。

提示: systemd-delta 命令用来查看哪些单元文件被覆盖、哪些被修改。系统维护的时候需要及时了解哪些单元已经有了更新。
安装 vim-systemd 软件包,可以使单元配置文件在 Vim 下支持语法高亮。

目标(target)

运行级别(runlevel)是一个旧的概念。现在,systemd 引入了一个和运行级别功能相似又不同的概念——目标(target)。不像数字表示的启动级别,每个目标都有名字和独特的功能,并且能同时启用多个。一些目标继承其他目标的服务,并启动新服务。systemd 提供了一些模仿 sysvinit 运行级别的目标,仍可以使用旧的 telinit 运行级别 命令切换。

获取当前目标

不要使用 runlevel 命令了:

1
$ systemctl list-units --type=target

创建新目标

在 Fedora 中,运行级别 0、1、3、5、6 都被赋予特定用途,并且都对应一个 systemd 的目标。然而,移植用户定义的运行级别(2、4)没有什么好方法。要实现类似功能,可以以原有的启动级别为基础,创建一个新的目标 /etc/systemd/system/<新目标>(可以参考 /usr/lib/systemd/system/graphical.target),创建 /etc/systemd/system/<新目标>.wants 目录,向其中加入额外服务的链接(指向 /usr/lib/systemd/system/ 中的单元文件)。

目标表

SysV 运行级别 Systemd 目标 注释
0 runlevel0.target, poweroff.target 中断系统(halt)
1, s, single runlevel1.target, rescue.target 单用户模式
2, 4 runlevel2.target, runlevel4.target, multi-user.target 用户自定义运行级别,通常识别为级别3。
3 runlevel3.target, multi-user.target 多用户,无图形界面。用户可以通过终端或网络登录。
5 runlevel5.target, graphical.target 多用户,图形界面。继承级别3的服务,并启动图形界面服务。
6 runlevel6.target, reboot.target 重启
emergency emergency.target 急救模式(Emergency shell)

切换运行级别/目标

systemd 中,运行级别通过“目标单元”访问。通过如下命令切换:

1
# systemctl isolate graphical.target

该命令对下次启动无影响。等价于telinit 3 或 telinit 5。

修改默认运行级别/目标

开机启动的目标是 default.target,默认链接到 graphical.target (大致相当于原来的运行级别5)。可以通过内核参数更改默认运行级别:

  • systemd.unit=multi-user.target (大致相当于级别3)
  • systemd.unit=rescue.target (大致相当于级别1)

另一个方法是修改 default.target。可以通过 systemctl 修改它:

1
# systemctl set-default multi-user.target

要覆盖已经设置的default.target,请使用 force:

1
# systemctl set-default -f multi-user.target

可以在 systemctl 的输出中看到命令执行的效果:链接 /etc/systemd/system/default.target 被创建,指向新的默认运行级别。
临时文件
/usr/lib/tmpfiles.d/ 和 /etc/tmpfiles.d/ 中的文件描述了 systemd-tmpfiles 如何创建、清理、删除临时文件和目录,这些文件和目录通常存放在 /run 和 /tmp 中。配置文件名称为 /etc/tmpfiles.d/.conf。此处的配置能覆盖 /usr/lib/tmpfiles.d/ 目录中的同名配置。
临时文件通常和服务文件同时提供,以生成守护进程需要的文件和目录。例如 Samba 服务需要目录 /run/samba 存在并设置正确的权限位,就象这样:
/usr/lib/tmpfiles.d/samba.conf
D /run/samba 0755 root root
此外,临时文件还可以用来在开机时向特定文件写入某些内容。比如,要禁止系统从USB设备唤醒,利用旧的 /etc/rc.local 可以用 echo USBE > /proc/acpi/wakeup,而现在可以这么做:
/etc/tmpfiles.d/disable-usb-wake.conf
w /proc/acpi/wakeup - - - - USBE
详情参见systemd-tmpfiles(8) 和 tmpfiles.d(5)。

注意: 该方法不能向 /sys 中的配置文件添加参数,因为 systemd-tmpfiles-setup 有可能在相关模块加载前运行。这种情况下,需要首先通过 modinfo <模块名> 确认需要的参数,然后在 /etc/modprobe.d 目录下的配置文件[broken link: invalid section]中修改配置参数。另外,还可以使用 udev 规则,在设备就绪时设置相应属性。

定时器

一个定时器是一个以 .timer 为结尾的单元配置文件并包含由 systemd 控制和监督的信息。systemd/Timers (简体中文)

注意: 定时器很大程度上可取代 cron。systemd/Timers (简体中文)#替代 cron

挂载

因为 systemd 替代了 System V init, 所以也负责按 /etc/fstab 定义挂载目录。除此之外,还实现了以 x-systemd. 开头的挂载选项. Fstab#Automount with systemd 包含了使用此扩展的 automounting (按需挂载)。完整扩展请参考 [2]。

日志

systemd 提供了自己的日志系统(logging system),称为 journal。使用 systemd 日志,无需额外安装日志服务(syslog)。读取日志的命令:

1
# journalctl

默认情况下(当 Storage= 在文件 /etc/systemd/journald.conf 中被设置为 auto),日志记录将被写入 /var/log/journal/。该目录是 systemd 软件包的一部分。若被删除,systemd 不会自动创建它,直到下次升级软件包时重建该目录。如果该目录缺失,systemd 会将日志记录写入 /run/systemd/journal。这意味着,系统重启后日志将丢失。
提示: 如果 /var/log/journal/ 位于 btrfs 文件系统,应该考虑对这个目录禁用写入时复制,方法参阅Btrfs#Copy-on-Write (CoW)。
Systemd 日志事件提示信息的记录分级方式符合经典的 BSD syslog 协议风格(维基百科,RFC 5424)。详情请参阅 Facility、Priority level等章节,用例请参阅 Filtering output[broken link: invalid section]。

Facility

A syslog facility code is used to specify the type of program that is logging the message RFC 5424 Section 6.2.1.
Facility code Keyword Description Info
0 kern kernel messages
1 user user-level messages
2 mail mail system Archaic POSIX still supported and sometimes used system, for more mail(1))
3 daemon system daemons All deamons, including systemd and its subsystems
4 auth security/authorization messages Also watch for different facility 10
5 syslog messages generated internally by syslogd As it standartized for syslogd, not used by systemd (see facility 3)
6 lpr line printer subsystem (archaic subsystem)
7 news network news subsystem (archaic subsystem)
8 uucp UUCP subsystem (archaic subsystem)
9 clock daemon systemd-timesyncd
10 authpriv security/authorization messages Also watch for different facility 4
11 ftp FTP daemon
12 - NTP subsystem
13 - log audit
14 - log alert
15 cron scheduling daemon
16 local0 local use 0 (local0)
17 local1 local use 1 (local1)
18 local2 local use 2 (local2)
19 local3 local use 3 (local3)
20 local4 local use 4 (local4)
21 local5 local use 5 (local5)
22 local6 local use 6 (local6)
23 local7 local use 7 (local7)
So, useful facilities to watch: 0,1,3,4,9,10,15.

Priority level

A syslog severity code (in systemd called priority) is used to mark the importance of a message RFC 5424 Section 6.2.1.
Value Severity Keyword Description Examples
0 Emergency emerg System is unusable Severe Kernel BUG, systemd dumped core.
This level should not be used by applications.
1 Alert alert Should be corrected immediately Vital subsystem goes out of work. Data loss.
kernel: BUG: unable to handle kernel paging request at ffffc90403238ffc.
2 Critical crit Critical conditions Crashes, coredumps. Like familiar flash:
systemd-coredump[25319]: Process 25310 (plugin-containe) of user 1000 dumped core
Failure in the system primary application, like X11.
3 Error err Error conditions Not severe error reported:
kernel: usb 1-3: 3:1: cannot get freq at ep 0x84,
systemd[1]: Failed unmounting /var.,
libvirtd[1720]: internal error: Failed to initialize a valid firewall backend).
4 Warning warning May indicate that an error will occur if action is not taken. A non-root file system has only 1GB free.
org.freedesktop. Notifications[1860]: (process:5999): Gtk-WARNING **: Locale not supported by C library. Using the fallback ‘C’ locale.
5 Notice notice Events that are unusual, but not error conditions. systemd[1]: var.mount: Directory /var to mount over is not empty, mounting anyway. gcr-prompter[4997]: Gtk: GtkDialog mapped without a transient parent. This is discouraged.
6 Informational info Normal operational messages that require no action. lvm[585]: 7 logical volume(s) in volume group “archvg” now active.
7 Debug debug Information useful to developers for debugging the application. kdeinit5[1900]: powerdevil: Scheduling inhibition from “:1.14” “firefox” with cookie 13 and reason “screen”.

If issue you are looking for, was not found on according level, search it on couple of priority levels above and below. This rules are recommendations. Some errors considered a normal occasion for program so they marked low in priority by developer, and on the contrary, sometimes too many messages plaques too high priorities for them, but often it’s an arguable situation. And often you really should solve an issue, also to understand architecture and adopt best practices.

Examples:

  • Info message:

    pulseaudio[2047]: W: [pulseaudio] alsa-mixer.c: Volume element Master has 8 channels. That’s too much! I can’t handle that!

It is an warning or error by definition.

  • Plaguing alert message:

    sudo[21711]: user : a password is required ; TTY=pts/0 ; PWD=/home/user ; USER=root ; COMMAND=list /usr/bin/pacman –color auto -Sy
    The reason - user was manually added to sudoers file, not to wheel group, which is arguably normal action, but sudo produced an alert on every occasion.

过滤输出

journalctl可以根据特定字段过滤输出。如果过滤的字段比较多,需要较长时间才能显示出来。
示例:
显示本次启动后的所有日志:

1
# journalctl -b

不过,一般大家更关心的不是本次启动后的日志,而是上次启动时的(例如,刚刚系统崩溃了)。可以使用 -b 参数:

  • journalctl -b -0 显示本次启动的信息
  • journalctl -b -1 显示上次启动的信息
  • journalctl -b -2 显示上上次启动的信息 journalctl -b -2
  • 只显示错误、冲突和重要告警信息
    1
    # journalctl -p err..alert
    也可以使用数字, journalctl -p 3..1。If single number/keyword used, journalctl -p 3 - all higher priority levels also included.
  • 显示从某个日期 ( 或时间 ) 开始的消息:
    1
    # journalctl --since="2012-10-30 18:17:16"
  • 显示从某个时间 ( 例如 20分钟前 ) 的消息:
    1
    # journalctl --since "20 min ago"
  • 显示最新信息
    1
    # journalctl -f
  • 显示特定程序的所有消息:
    1
    # journalctl /usr/lib/systemd/systemd
  • 显示特定进程的所有消息:
    1
    # journalctl _PID=1
  • 显示指定单元的所有消息:
    1
    # journalctl -u netcfg
  • 显示内核环缓存消息r:
    1
    2
    3
    # journalctl -k
    Show auth.log equivalent by filtering on syslog facility:
    # journalctl -f -l SYSLOG_FACILITY=10
    详情参阅journalctl(1)、systemd.journal-fields(7),以及 Lennert 的这篇博文。

日志大小限制

如果按上面的操作保留日志的话,默认日志最大限制为所在文件系统容量的 10%,即:如果 /var/log/journal 储存在 50GiB 的根分区中,那么日志最多存储 5GiB 数据。可以修改配置文件指定最大限制。如限制日志最大 50MiB:

1
2
/etc/systemd/journald.conf
SystemMaxUse=50M

还可以通过配置片段而不是全局配置文件进行设置:

1
2
3
/etc/systemd/journald.conf.d/00-journal-size.conf
[Journal]
SystemMaxUse=50M

详情参见 journald.conf(5).

配合 syslog 使用

systemd 提供了 socket /run/systemd/journal/syslog,以兼容传统日志服务。所有系统信息都会被传入。要使传统日志服务工作,需要让服务链接该 socket,而非 /dev/log(官方说明)。Arch 软件仓库中的 syslog-ng 已经包含了需要的配置。
journald.conf 使用 no 转发socket . 为了使 syslog-ng 配合 journald , 你需要在 /etc/systemd/journald.conf 中设置 ForwardToSyslog=yes . 参阅 Syslog-ng#Overview 了解更多细节.
如果你选择使用 rsyslog , 因为 rsyslog 从日志中 直接 传出消息,所以不再必要改变那个选项..
设置开机启动 syslog-ng:

systemctl enable syslog-ng

这里有一份很不错的 journalctl 指南。

手动清理日志

/var/log/journal 存放着日志, rm 应该能工作. 或者使用journalctl,
例如:

  • 清理日志使总大小小于 100M:
    1
    # journalctl --vacuum-size=100M
  • 清理最早两周前的日志.
    1
    # journalctl --vacuum-time=2weeks
    参阅 journalctl(1) 获得更多信息.

Journald in conjunction with syslog

Compatibility with a classic, non-journald aware syslog implementation can be provided by letting systemd forward all messages via the socket /run/systemd/journal/syslog. To make the syslog daemon work with the journal, it has to bind to this socket instead of /dev/log (official announcement).
As of systemd 216 the default journald.conf for forwarding to the socket was changed to ForwardToSyslog=no to avoid system overhead, because rsyslog or syslog-ng (since 3.6) pull the messages from the journal by itself.
See Syslog-ng#Overview and Syslog-ng#syslog-ng and systemd journal, or rsyslog respectively, for details on configuration.

转发 journald 到 /dev/tty12

建立一个 drop-in directory[broken link: invalid section] /etc/systemd/journald.conf.d 然后在其中建立 fw-tty12.conf :

1
2
3
4
5
/etc/systemd/journald.conf.d/fw-tty12.conf
[Journal]
ForwardToConsole=yes
TTYPath=/dev/tty12
MaxLevelConsole=info

然后重新启动 systemd-journald.

查看特定位置的日志

有时你希望查看另一个系统上的日志.例如从 Live 环境修复现存的系统.
这种情况下你可以挂载目标系统 ( 例如挂载到 /mnt ),然后用 -D/–directory 参数指定目录,像这样:

1
$ journalctl -D /mnt/var/log/journal -xe

Tips and tricks

Enable installed units by default
Tango-view-fullscreen.pngThis article or section needs expansion.Tango-view-fullscreen.png
Reason: How does it work with instantiated units? (Discuss in Talk:Systemd (简体中文)#)
Arch Linux ships with /usr/lib/systemd/system-preset/99-default.preset containing disable *. This causes systemctl preset to disable all units by default, such that when a new package is installed, the user must manually enable the unit.
If this behavior is not desired, simply create a symlink from /etc/systemd/system-preset/99-default.preset to /dev/null in order to override the configuration file. This will cause systemctl preset to enable all units that get installed—regardless of unit type—unless specified in another file in one systemctl preset’s configuration directories. User units are not affected. See the manpage for systemd.preset for more information.
Note: Enabling all units by default may cause problems with packages that contain two or more mutually exclusive units. systemctl preset is designed to be used by distributions and spins or system administrators. In the case where two conflicting units would be enabled, you should explicitly specify which one is to be disabled in a preset configuration file as specified in the manpage for systemd.preset.

疑难解答

寻找错误

这个例子中的失败的服务是 systemd-modules-load :

  1. 通过 systemd 寻找启动失败的服务:
    1
    2
    $ systemctl --state=failed
    systemd-modules-load.service loaded failed failed Load Kernel Modules
  2. 我们发现了启动失败的 systemd-modules-load 服务. 我们想知道更多信息:
    1
    2
    3
    4
    5
    6
    7
    $ systemctl status systemd-modules-load
    systemd-modules-load.service - Load Kernel Modules
    Loaded: loaded (/usr/lib/systemd/system/systemd-modules-load.service; static)
    Active: failed (Result: exit-code) since So 2013-08-25 11:48:13 CEST; 32s ago
    Docs: man:systemd-modules-load.service(8).
    man:modules-load.d(5)
    Process: 15630 ExecStart=/usr/lib/systemd/systemd-modules-load (code=exited, status=1/FAILURE)
    如果没列出 Process ID, 通过 systemctl 重新启动失败的服务 ( 例如 systemctl restart systemd-modules-load )
  3. 现在得到了 PID ,你就可以进一步探查错误的详细信息了.通过下列的命令收集日志,PID 参数是你刚刚得到的 Process ID (例如 15630):
    1
    2
    3
    4
    $ journalctl -b _PID=15630
    -- Logs begin at Sa 2013-05-25 10:31:12 CEST, end at So 2013-08-25 11:51:17 CEST. --
    Aug 25 11:48:13 mypc systemd-modules-load[15630]: Failed to find module 'blacklist usblp'
    Aug 25 11:48:13 mypc systemd-modules-load[15630]: Failed to find module 'install usblp /bin/false'
  4. 我们发现有些内核模块的配置文件不正确,因此在 /etc/modules-load.d/ 中检查一下:
    1
    2
    3
    4
    5
    6
    7
    8
    $ ls -Al /etc/modules-load.d/
    ...
    -rw-r--r-- 1 root root 79 1. Dez 2012 blacklist.conf
    -rw-r--r-- 1 root root 1 2. Mär 14:30 encrypt.conf
    -rw-r--r-- 1 root root 3 5. Dez 2012 printing.conf
    -rw-r--r-- 1 root root 6 14. Jul 11:01 realtek.conf
    -rw-r--r-- 1 root root 65 2. Jun 23:01 virtualbox.conf
    ...
  5. 错误消息 Failed to find module ‘blacklist usblp’ 也许和 blacklist.conf 相关. 让我们注释掉第三步发现的错误的选项:
    1
    2
    3
    /etc/modules-load.d/blacklist.conf
    # blacklist usblp
    # install usblp /bin/false
  6. 最后重新启动 systemd-modules-load 服务:
    $ systemctl start systemd-modules-load
    如果服务成功启动,不会有任何输出.如果你还是遇到了错误,回到步骤三,获得新的 PID 来跟踪日志并解决错误.
    可以像这样确认服务成功启动:
    1
    2
    3
    4
    5
    6
    7
    8
    $ systemctl status systemd-modules-load
    systemd-modules-load.service - Load Kernel Modules
    Loaded: loaded (/usr/lib/systemd/system/systemd-modules-load.service; static)
    Active: active (exited) since So 2013-08-25 12:22:31 CEST; 34s ago
    Docs: man:systemd-modules-load.service(8)
    man:modules-load.d(5)
    Process: 19005 ExecStart=/usr/lib/systemd/systemd-modules-load (code=exited, status=0/SUCCESS)
    Aug 25 12:22:31 mypc systemd[1]: Started Load Kernel Modules.
    参阅 #诊断启动问题 一节获得更多探查错误的方法.

诊断启动问题

使用如下内核参数引导: systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M
更多有关调试的信息,参见该文。
诊断一个特定服务
如果某个 systemd 服务的工作状况不合你的预期因此你希望调试的话,设置 SYSTEMD_LOG_LEVEL 环境变量 为 debug . 例如以调试模式运行 systemd-networkd 服务:

systemctl stop systemd-networkd

SYSTEMD_LOG_LEVEL=debug /lib/systemd/systemd-networkd

或者等价的,临时编辑系统单元文件,例如:
/lib/systemd/system/systemd-networkd.service
[Service]

Environment=SYSTEMD_LOG_LEVEL=debug
….
如果经常需要调试信息,以一般方法添加环境变量.
关机/重启十分缓慢
如果关机特别慢(甚至跟死机了一样),很可能是某个拒不退出的服务在作怪。systemd 会等待一段时间,然后再尝试杀死它。请阅读这篇文章,确认你是否是该问题受害者。
短时进程无日志记录
若 journalctl -u foounit.service 没有显示某个短时进程的任何输出,那么改用 PID 试试。例如,若 systemd-modules-load.service 执行失败,那么先用 systemctl status systemd-modules-load 查询其 PID(比如是123),然后检索该 PID 相关的日志 journalctl -b _PID=123。运行时进程的日志元数据(诸如 _SYSTEMD_UNIT 和 _COMM)被乱序收集在 /proc 目录。要修复该问题,必须修改内核,使其通过套接字连接来提供上述数据,该过程类似于 SCM_CREDENTIALS。
禁止在程序崩溃时转储内存
要使用老的内核转储,创建下面文件:
/etc/sysctl.d/49-coredump.conf
kernel.core_pattern = core
kernel.core_uses_pid = 0
然后运行:

/usr/lib/systemd/systemd-sysctl

同样可能需要执行“unlimit”设置文件大小:
$ ulimit -c unlimited
更多信息请参阅 sysctl.d 和 /proc/sys/kernel 文档。
启动的时间太长
不少用户用了 systemd-analyze 命令以后报告启动的时间比预计的要长,通常会说 systemd-analyze 分析结果表示 NetworkManager 占据了太多的启动的时间.
有些用户的问题是 /var/log/journal 文件夹似乎过大.这也许也会对像systemctl status 或 journalctl 的命令有影响.一种解决方案是删除其中的文件 (但最好将它们备份到某处) 然后限制日志文件的大小.
systemd-tmpfiles-setup.service 在启动时启动失败
从 systemd 219 开始, /usr/lib/tmpfiles.d/systemd.conf 指定 /var/log/journal 的 ACL 属性和目录, 因此日志所在的文件系统上要启用ACL.
参阅 Access Control Lists#Enabling ACL 获得如何包含 /var/log/journal 启动 ACL 的详细信息.
不能设定在开机时启动软链接到 /etc/systemd/system 的服务
如果 /etc/systemd/system/foo.service 是个符号链接, 运行 systemctl enable foo.service 时可能遇到这样的错误:
Failed to issue method call: No such file or directory
这是 systemd 的 设计选择 ,可以通过输入绝对路径来规避这个错误:

systemctl enable /absolute/path/foo.service

启动时显示的 systemd 版本和安装版本不一致
需要 重新生成 initramfs。
提示: 可以使用 pacman 钩子在更新 systemd时重新生成 initramfs。参考 这个帖子 和 Pacman#Hooks.

原文: 如何拯救一台glibc被干掉的Linux服务器?

首先如果 libc.so.6 没有被删除, 直接使用LD_PRELOAD就可以恢复
LD_PRELOAD=/lib64/libc-2.12.so ln -s libc-2.12.so libc.so.6

如果彻底被删除, 下面的方法可以一试

glibc被卸载,负责加载所有.so的ld.so也就没了,因此运行几乎所有外部命令时都会得到一句『找不到ld-linux-x-y-z.so.2』的出错提示。比如ls,比如cp,以及所有动态链接的命令。

这是一台放置于另外一个大洲的客户IDC的物理服务器。我说不行就光盘引导修复,但不知道什么原因他们又连不上服务器的HP iLO工具。

干着急也不是办法。万幸的是rpm –force的小伙子的ssh登录shell还连着。我说那不行就只能你自己一个byte一个byte先敲一个static linked的binary出来,这是可以运行的。

话说完,我就大概想到该怎么办了。

  1. 用bash的内部命令 printf ‘\xaa\xbb\xcc’ > file 可以生成任意内容的文件
  2. 另外找台同配置的Linux,用xxd或hexdump配合一点点脚本,或者直接用python写个小脚本,把ld.so文件转储成若干条printf ‘…’ >> file的命令(考虑到bash单行命令的长度限制,我没有尝试只生成一条命令)
  3. copy 2)中生成的命令,paste到出事的Linux shell中运行
  4. 这样至少ld.so能用,接下来可以按图索骥恢复其他.so
    Tada! 我感觉自己重新发明了scp。

然而这样行不通。printf重定向生成的文件不带可执行位,无法被执行,只是把出错信息变成了permission denied而已。

别忘了chmod也不能用哦。

所以往上面手动恢复glibc这条路看来是行不通了。

既然动态链接的命令都不能用,那就只能上静态链接了。到http://www.busybox.net下载了静态链接的1.16.0版(越旧的版本越好——因为越小)的busybox,不到900KB,用上面的办法,转存到出事的Linux上。

刚才不是说了没有可执行位吗?busybox又怎样?

这次,我是把busybox直接写入到

1
printf '...' > /bin/cp

覆盖系统原有的带x位的cp文件,用旧瓶装新酒,我终于获得了一个可执行的busybox!
别忘了,argv[0]为cp时,busybox就是在做cp的事情!

因此接下来再

1
2
3
4
5
6
cp cp ln
ln -s cp chmod
ln -s cp ls
ln -s cp wget
ln -s cp sh
...

printf和busybox拯救世界!

再传送一份静态连接的dropbear上去,起一个备用的ssh server(别忘了把账号的登录shell改成busybox版sh),总算可以松一口气,继续后面的灾难恢复了。

PS:
测试一个简单的hello world程序可以通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
import sys

'''
#include<stdio.h>

int main()
{
printf("Hello World!\n");
}

gcc -o hello hello.c
'''

# only test,
result = []
outfile = 'out.sh'
fpath = '/home/opc/hello'

with open(fpath, 'rb') as f:
bt = f.read()

diglist = list(bt)
for dig in diglist:
if sys.version_info < (3, 0):
dig = int(dig.encode('hex'), 16)
if dig > 31 and dig < 127: #ascii码里面这些字符串可见
s = str('\\') + oct(dig)[-3:].replace('o','0')
else:
s = str('\\x') + hex(dig)[-2:].replace('x','0')
result.append(s)
with open(outfile,'w') as f:
for i in range(0, len(result), 1000): #每次打印1000个字符1k大小,1M大小文件就需要1000次操作了-_-!!
print('printf \'', ''.join(result[i:i+1000]), '\' >> recovery_file', sep='') # 最后一个分片大一点没关系
f.write('printf \'' + ''.join(result[i:i+1000]) + '\' >> recovery_file\n')

列出当前数据库所有表
\dt

列出表名
SELECT tablename FROM pg_tables;
WHERE tablename NOT LIKE ‘pg%’
AND tablename NOT LIKE ‘sql_%’
ORDER BY tablename;

列出数据库名
\l

SELECT datname FROM pg_database;

切换数据库
\c 数据库名

1、通过命令行查询
\d 数据库 —— 得到所有表的名字
\d 表名 —— 得到表结构
2、通过SQL语句查询
“select * from pg_tables” —— 得到当前db中所有表的信息(这里pg_tables是系统视图)
“select tablename from pg_tables where schemaname=’public’” —— 得到所有用户自定义表的名字(这里”tablename”字段是表的名字,”schemaname”是schema的名字。用户自定义的表,如果未经特殊处理,默认都是放在名为public的schema下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
General
\copyright show PostgreSQL usage and distribution terms
\g [FILE] or ; execute query (and send results to file or |pipe)
\h [NAME] help on syntax of SQL commands, * for all commands
\q quit psql

Query Buffer
\e [FILE] [LINE] edit the query buffer (or file) with external editor
\ef [FUNCNAME [LINE]] edit function definition with external editor
\p show the contents of the query buffer
\r reset (clear) the query buffer
\s [FILE] display history or save it to file
\w FILE write query buffer to file

Input/Output
\copy ... perform SQL COPY with data stream to the client host
\echo [STRING] write string to standard output
\i FILE execute commands from file
\o [FILE] send all query results to file or |pipe
\qecho [STRING] write string to query output stream (see \o)

Informational
(options: S = show system objects, + = additional detail)
\d[S+] list tables, views, and sequences
\d[S+] NAME describe table, view, sequence, or index
\da[S] [PATTERN] list aggregates
\db[+] [PATTERN] list tablespaces
\dc[S] [PATTERN] list conversions
\dC [PATTERN] list casts
\dd[S] [PATTERN] show comments on objects
\ddp [PATTERN] list default privileges
\dD[S] [PATTERN] list domains
\det[+] [PATTERN] list foreign tables
\des[+] [PATTERN] list foreign servers
\deu[+] [PATTERN] list user mappings
\dew[+] [PATTERN] list foreign-data wrappers
\df[antw][S+] [PATRN] list [only agg/normal/trigger/window] functions
\dF[+] [PATTERN] list text search configurations
\dFd[+] [PATTERN] list text search dictionaries
\dFp[+] [PATTERN] list text search parsers
\dFt[+] [PATTERN] list text search templates
\dg[+] [PATTERN] list roles
\di[S+] [PATTERN] list indexes
\dl list large objects, same as \lo_list
\dL[S+] [PATTERN] list procedural languages
\dn[S+] [PATTERN] list schemas
\do[S] [PATTERN] list operators
\dO[S+] [PATTERN] list collations
\dp [PATTERN] list table, view, and sequence access privileges
\drds [PATRN1 [PATRN2]] list per-database role settings
\ds[S+] [PATTERN] list sequences
\dt[S+] [PATTERN] list tables
\dT[S+] [PATTERN] list data types
\du[+] [PATTERN] list roles
\dv[S+] [PATTERN] list views
\dE[S+] [PATTERN] list foreign tables
\dx[+] [PATTERN] list extensions
\l[+] list all databases
\sf[+] FUNCNAME show a function's definition
\z [PATTERN] same as \dp

Formatting
\a toggle between unaligned and aligned output mode
\C [STRING] set table title, or unset if none
\f [STRING] show or set field separator for unaligned query output
\H toggle HTML output mode (currently off)
\pset NAME [VALUE] set table output option
(NAME := {format|border|expanded|fieldsep|footer|null|
numericlocale|recordsep|tuples_only|title|tableattr|pager})
\t [on|off] show only rows (currently off)
\T [STRING] set HTML <table> tag attributes, or unset if none
\x [on|off] toggle expanded output (currently off)

Connection
\c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo}
connect to new database (currently "postgres")
\encoding [ENCODING] show or set client encoding
\password [USERNAME] securely change the password for a user
\conninfo display information about current connection

Operating System
\cd [DIR] change the current working directory
\timing [on|off] toggle timing of commands (currently off)
\! [COMMAND] execute command in shell or start interactive shell

Variables
\prompt [TEXT] NAME prompt user to set internal variable
\set [NAME [VALUE]] set internal variable, or list all if no parameters
\unset NAME unset (delete) internal variable

Large Objects
\lo_export LOBOID FILE
\lo_import FILE [COMMENT]
\lo_list
\lo_unlink LOBOID large object operations

查询curl耗时

1
2
curl -o /dev/null -s -w %{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}"\n" "http://www.taobao.com"  
0.014::0.015::0.018::0.019::1516256.00
1
2
3
4
5
6
7
8
9
-o:把curl 返回的html、js 写到垃圾回收站[ /dev/null] 
-s:去掉所有状态

-w:按照后面的格式写出rt
time_namelookup:DNS 解析域名[www.taobao.com]的时间
time_commect:client和server端建立TCP 连接的时间
time_starttransfer:从client发出请求;到web的server 响应第一个字节的时间
time_total:client发出请求;到web的server发送会所有的相应数据的时间
speed_download:下周速度 单位 byte/s

解释

1
2
3
4
5
6
7
8
0.014: DNS 服务器解析www.taobao.com 的时间单位是s   
0.015: client发出请求,到c/s 建立TCP 的时间;里面包括DNS解析的时间
0.018: client发出请求;到s响应发出第一个字节开始的时间;包括前面的2个时间
0.019: client发出请求;到s把响应的数据全部发送给client;并关闭connect的时间
1516256.00 :下周数据的速度

1. 建立TCP连接到server返回client第一个字节的时间:0.018s - 0.015s = 0.003s
2. server把响应数据发送给client的时间:0.019s - 0.018 = 0.01s

构造header

在一些个例中,或许你想要在一个HTTP请求中覆盖掉默认的HTTP头或者添加一个新的自定义头部字段。例如,你或许想要重写“HOST”字段来测试一个负载均衡,或者通过重写”User-Agent”字符串来假冒特定浏览器以解决一些访问限制的问题。

为了解决所有这些问题,curl提供了一个简单的方法来完全控制传出HTTP请求的HTTP头。你需要的这个参数是“-H” 或者 “–header”。

为了定义多个HTTP头部字段,”-H”选项可以在curl命令中被多次指定。

例如:以下命令设置了3个HTTP头部字段。也就是说,重写了“HOST”字段,并且添加了两个字段(”Accept-Language” 和 “Cookie”)

1
$ curl -H 'Host: 157.166.226.25' -H 'Accept-Language: es' -H 'Cookie: ID=1234' http://cnn.com

对于”User-Agent”, “Cookie”, “Host”这类标准的HTTP头部字段,通常会有另外一种设置方法。curl命令提供了特定的选项来对这些头部字段进行设置:

-A (or –user-agent): 设置 “User-Agent” 字段.
-b (or –cookie): 设置 “Cookie” 字段.
-e (or –referer): 设置 “Referer” 字段.

例如,以下两个命令是等效的。这两个命令同样都对HTTP头的”User-Agent”字符串进行了更改。

1
2
$ curl -H "User-Agent: my browser" http://cnn.com
$ curl -A "my browser" http://cnn.com

post请求

下载文件

Redis使用config命令,可以对配置项参数热修改,不必重启。

Redis最好不要重启,重启一次会引发如下问题:

  1. 如果数据很多(例如几个G),读起来很慢;
  2. 重启风险很大,Redis有内存陷阱
  3. 重启会引发读快照,读AOF文件

使用config get *获得所有的配置项的key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
127.0.0.1:6379> CONFIG GET *
1) "dir"
2) "/var/lib/redis"
3) "dbfilename"
4) "dump.rdb"
5) "requirepass"
6) (nil)
7) "masterauth"
8) (nil)
9) "maxmemory"
10) "0"
11) "maxmemory-policy"
12) "volatile-lru"
13) "maxmemory-samples"
14) "3"
15) "timeout"
16) "300"
17) "appendonly"
18) "no"
19) "no-appendfsync-on-rewrite"
20) "no"
21) "appendfsync"
22) "everysec"
23) "save"
24) "900 1 300 10 60 10000"
25) "slave-serve-stale-data"
26) "yes"
27) "hash-max-zipmap-entries"
28) "512"
29) "hash-max-zipmap-value"
30) "64"
31) "list-max-ziplist-entries"
32) "512"
33) "list-max-ziplist-value"
34) "64"
35) "set-max-intset-entries"
36) "512"
37) "slowlog-log-slower-than"
38) "10000"
39) "slowlog-max-len"
40) "64"

更改redis持久化设置

1
2
127.0.0.1:6379> CONFIG SET save "9000 10 3000 100 600 100000"
OK

再次查看redis配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
127.0.0.1:6379> CONFIG GET *
1) "dir"
2) "/var/lib/redis"
3) "dbfilename"
4) "dump.rdb"
5) "requirepass"
6) (nil)
7) "masterauth"
8) (nil)
9) "maxmemory"
10) "0"
11) "maxmemory-policy"
12) "volatile-lru"
13) "maxmemory-samples"
14) "3"
15) "timeout"
16) "300"
17) "appendonly"
18) "no"
19) "no-appendfsync-on-rewrite"
20) "no"
21) "appendfsync"
22) "everysec"
23) "save"
24) "9000 10 3000 100 600 100000"
25) "slave-serve-stale-data"
26) "yes"
27) "hash-max-zipmap-entries"
28) "512"
29) "hash-max-zipmap-value"
30) "64"
31) "list-max-ziplist-entries"
32) "512"
33) "list-max-ziplist-value"
34) "64"
35) "set-max-intset-entries"
36) "512"
37) "slowlog-log-slower-than"
38) "10000"
39) "slowlog-max-len"
40) "64"