秦悦明的运维笔记

读<卓有成效的管理者>

1. 序言

很难形容这书写的如何如何,但是我觉得里面的话很有道理,一些经验值得学习,当然我干管理的经验并不多,主要是在驻云期间的经历。管理很大程度上面跟企业文化也有很直接的关系,我们知道硅谷的it很牛,但其实硅谷的企业文化也是很先进的。

2.有效的管理者知道他们的时间用在什么地方。

目前我还不是一个有效的管理者,对时间用在哪里记忆的不准确。

3. 有效的管理者重视对外界的贡献,“别人期望我做出什么成果?”

这条也没被我重视,其实往往你做的事情和boss期望我做的事情存在着鸿沟。

4.有效的管理者善于利用长处。

知道自己擅长什么,不会把工作建立在自己的短处上,也绝不会做自己做不了的事。可以对比一下社会上某些管理者喜欢提的木桶原理,觉得你缺少哪一环就应该赶紧补上,其实越是大的企业或者是组织,越能包容员工的缺点,他们只需要利用员工某个方面的特长就行了,不需要那种没啥特点的通才。

5.有效的管理者集中精力与少数重要的领域。

do one thing at a time。
计算机可能很方便的进行并行操作,但人很难,切换的效率太慢了。大块时间对于决策很重要,碎片时间能干的事情有限。

6. 最后,有效的管理者必须善于做有效的决策。

真正不可或缺的决策数量并不多,但一定是根本性的决策,他们需要的是正确的战略,而不是眼花缭乱的战术。

7. 后记

里面有很多干货,需要慢慢体会,不仅对管理者有效,而且对知识工作者同样有效,适合多看几遍。我工作过6家工作,大公司小公司都有,感觉大公司正规一点,毕竟这东西需要经验的累积,写了很多,都删了,过去都过去了,将来慢慢努力吧,管理大师不是一天铸就的,当然每个人不需要都往管理层去处,我内心很佩服30多岁还是码代码的程序员,国外的架构师都是有超过20年编码经历的老司机,领导力不是所属下属多了你就是个合格的领导了,真正的管理者应该像德鲁克描述的那样卓有成效!

zabbix模块编程

1.module简介

其实就是一个动态扩展库,可以动态的被agent加载,用来扩展agent本身没有的功能,你可以把一些item写进去,用c语言来高效实现。
源码自带了一个dummy模块,很好的一个例子,代码注释非常明确。

2.module用法

在config文件里面写入

1
LoadModule=xx.so

重启agent即可加载,一般是有如下日志:

1
2
16784:20170603:142839.965 using configuration file: /etc/zabbix/zabbix_agentd.conf
16784:20170603:142839.965 loaded modules: tcpcount.so

说明已经加载完成。以自带的dummy为例,我们先是在dummy目录下make,

1
2
3
4
#make
gcc -fPIC -shared -o dummy.so dummy.c -I../../../include
#ls
dummy.c dummy.so Makefile README

然后是加载模块,默认要放到/usr/lib64/zabbix/modules/下面:

1
LoadModule=dummy.so

进行测试:

1
2
# zabbix_get -s 127.0.0.1 -k dummy.ping
1
1
2
#zabbix_get -s 127.0.0.1 -k dummy.echo[qym]
qym
1
2
# zabbix_get -s 127.0.0.1 -k dummy.random[1,1000]
486

3. 编码

其实上面三个例子已经给了很好的诠释,首先是定义函数

1
int zbx_module_dummy_ping(AGENT_REQUEST *request, AGENT_RESULT *result)

函数返回SYSINFO_RET_OK或者SYSINFO_RET_FAIL. result用SET_XXX_RESULT来设置,比如ping返回1

1
SET_UI64_RESULT(result, 1);

echo返回字符串:

1
SET_STR_RESULT(result, strdup(param));

参数怎么获取呢,很简单有个get_rparam宏:

1
2
3
param1 = get_rparam(request, 0);
param2 = get_rparam(request, 1);

基本的骨架都有了,照着改改就行了。我写了个tcp count的模块,跟netstat的实现原理差不多,就是解析/proc/net/tcp下面的信息,
主要用的是sscanf这个函数,每行解析就可以了,实现上面跟https://github.com/mutz0623/zabbix_TCP-state-count-module类似,但是我只统计服务器端指定port的连接数,而且他的sscanf实现略有些笨拙,可以简化。
核心代码如下:

1
2
3
4
5
6
7
while ((read = getline(&line, &len, fp)) != -1){
int st;
sscanf(line, "%*d: %*08x:%04x %*08x:%*04x %02x",&port,&st);
if(port == dport && st == dst)
c++;
}

可以根据st ,也就是tcp状态信息字段来count,st的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum {
TCP_ESTABLISHED = 1,
TCP_SYN_SENT,
TCP_SYN_RECV,
TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
TCP_TIME_WAIT,
TCP_CLOSE,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_LISTEN,
TCP_CLOSING, /* Now a valid state */
TCP_MAX_STATES /* Leave at the end! */
};

一般主要是TCP_ESTABLISHED和TCP_TIME_WAIT比较常见,配合模板使用,效果杠杠的。

zabbix获取最大值

1. 目的

zabbix获取某些groups的某个item的最大值。

2. 思路

获取数据无非是两种,一种是通过api,另一张则更暴力,通过database。我之前用api的较多,但是发现这个场景下面直接从database下面获取反而更容易编码。

3. 具体做法

逆向思维,历史数据存在history的几张表里,那个item类型是int,所以放在history_uint下面。现在想想还一部分在trend表里面。
history_uint的数据结构如下:

1
2
3
4
5
6
7
8
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| itemid | bigint(20) unsigned | NO | MUL | NULL | |
| clock | int(11) | NO | | 0 | |
| value | bigint(20) unsigned | NO | | 0 | |
| ns | int(11) | NO | | 0 | |
+--------+---------------------+------+-----+---------+-------+

是根据itemid来存放的,那么怎么通过host group来获取itemid, 自然联系到items这个表,

1
2
3
4
5
6
7
8
9
10
11
12
13
+-----------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+---------------------+------+-----+---------+-------+
| itemid | bigint(20) unsigned | NO | PRI | NULL | |
| type | int(11) | NO | | 0 | |
| snmp_community | varchar(64) | NO | | | |
| snmp_oid | varchar(255) | NO | | | |
| hostid | bigint(20) unsigned | NO | MUL | NULL | |
| name | varchar(255) | NO | | | |
| key_ | varchar(255) | NO | | | |
|
`

select一个row:

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
itemid: 10009
type: 0
snmp_community:
snmp_oid:
hostid: 10001
name: Number of processes
key_: proc.num[]
delay: 60
history: 7
trends: 365
status: 0
value_type: 3
trapper_hosts:
units:
multiplier: 0
delta: 0
snmpv3_securityname:
snmpv3_securitylevel: 0
snmpv3_authpassphrase:
snmpv3_privpassphrase:
formula: 1
error:
lastlogsize: 0
logtimefmt:
templateid: NULL
valuemapid: NULL
delay_flex:
params:
ipmi_sensor:
data_type: 0
authtype: 0
username:
password:
publickey:
privatekey:
mtime: 0
flags: 0
interfaceid: NULL
port:
description: Total number of processes in any state.
inventory_link: 0
lifetime: 0
snmpv3_authprotocol: 0
snmpv3_privprotocol: 0
state: 0
snmpv3_contextname:
evaltype: 0

再看下具体数据,那么大致就了解思路了。可以通过hostid来查itemid 。

然后就是怎么获取hostid了,数据库里面有hosts表,groups表,但是两者并没有直接联系的,关键联系表是hosts_groups,

1
2
3
4
5
6
7
+-------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+-------+
| hostgroupid | bigint(20) unsigned | NO | PRI | NULL | |
| hostid | bigint(20) unsigned | NO | MUL | NULL | |
| groupid | bigint(20) unsigned | NO | MUL | NULL | |
+-------------+---------------------+------+-----+---------+-------+

非常赞,通过groupid能直接找到hostid ,用sql 来表示就是

1
select hostid from hosts_groups where groupid in (a, b ,c);"

因为我是多个group,所以用in来代替等于号。这样我们有了hostid。

再通过查询items表获取itemid, 这里要根据key_来过滤:

1
select itemid from items where key_ like 'emsmob.connect' and hostid=xx

最后有了itemid以后就可以用过history_uint来查最大值:

1
select max(value) from history_uint where itemid=%d and clock>1493598330

这里我加了个clock ,查一个月的数据,不加的话会很慢。加了以后查询一般在10s左右。。还是比较慢。但是比不加要好多了。

clock可以用date命令来找到:

1
date -d "2017-05-01 00:25:30" +%s

把上面所有要素连起来就是完整程序了,再用csv处理一下,输出成csv格式的~

c++队列 queue

1. 队列

类比生活中,就是排队的现象,先进先出。

2. c++中的队列

不用自己实现,stl帮你实现了。只需要:

1
#include <quque>

queue支持下面几种操作.

操作 说明
q.empty() 判断是否为空
q.size() 大小
q.pop() 头部删除元素
q.front() 返回头部的元素
q.push(item) 从尾部添加元素

非常简洁。

3. 计算机中的例子

最经典的莫过于cpu多进程模型了,n个进程,每消耗X的cpu时间,就切换到其他进程去执行,看上去计算机是多进程同时在跑的。

aoj里面有个经典的例子:

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_3_B

我自己的实现是:

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
#include <iostream>
#include <queue>
using namespace std;
struct pp
{
string name;
int time;
};
int main(int argc, char const *argv[])
{
int n, q ;
cin>>n>>q;
queue<pp> que;
for (int i = 0; i < n; ++i)
{
pp x;
cin>>x.name>>x.time;
que.push(x);
}
// debug print it
int now=0;
while(!que.empty())
{
pp a = que.front();
// >100
if (a.time - q>0 )
{
now += q ;
a.time -= q;
// debug
// cout << "name: "<<a.name<< "\ta.spentime: "<< a.time + now<< " \n";
// cout << "now: " << now << endl;
que.pop();
que.push(a);
}
// < 100
else
{
now += a.time;
// cout << "name: "<<a.name<< "\ta.spentime: "<< now + a.time<< " \n";
// cout << "now: " << now << endl;
cout << a.name << " " << now << endl;
que.pop();
}
// cout << "name: " << que.front().name << "\ttime: " << que.front().time<< endl;
// que.pop();
}
return 0;
}

算是一个queue的典型用法了。