Elasticsearch 2.2.0节点类型介绍

Nock 发表了文章 • 0 个评论 • 157 次浏览 • 2016-12-06 20:37 • 来自相关话题

摘要

在Elasticsearch中节点可以分为主(master)节点,数据(data)节点,客户端节点和部落节点,每种类型的节点有不同的使用方法,对于一个大的集群中,合理的配置这些属性,对集群的健壮性和性能有很大的帮助。
 

节点类型

当我们启动Elasticsearch的实例,就会启动至少一个节点。相同集群名的多个节点的连接就组成了一个集群,在默认情况下,集群中的每个节点都可以处理http请求和集群节点间的数据传输,集群中所有的节点都知道集群中其他所有的节点,可以将客户端请求转发到适当的节点。节点有以下类型:
主(master)节点:在一个节点上当node.master设置为True(默认)的时候,它有资格被选作为主节点,控制整个集群。数据(data)节点:在一个节点上node.data设置为True(默认)的时候。该节点保存数据和执行数据相关的操作,如增删改查,搜索,和聚合。客户端节点:当一个节点的node.master和node.data都设置为false的时候,它既不能保持数据也不能成为主节点,该节点可以作为客户端节点,可以响应用户的情况,并把相关操作发送到其他节点。部落节点: 当一个节点配置tribe.*的时候,它是一个特殊的客户端,它可以连接多个集群,在所有连接的集群上执行搜索和其他操作。
 
默认情况下,节点配置是一个主节点和一个数据节点。这是非常方便的小集群,但随着集群的发展,分离主节点和数据节点将变得很重要。
 
大家知道Elasticsearch的data node除了放数据以外,也可以兼任master和client的角色,多数同学会将这些角色混入到data node。然而对于一个规模较大,用户较多的集群,master和client在一些极端使用情况下可能会有性能瓶颈甚至内存溢出,从而使得共存的data node故障。data node的故障恢复涉及到数据的迁移,对集群资源有一定消耗,容易造成数据写入延迟或者查询减慢。如果将master和client独立出来,一旦出现问题,重启后几乎是瞬间就恢复的,对用户几乎没有任何影响。另外将这些角色独立出来的以后,也将对应的计算资源消耗从data node剥离出来,更容易掌握data node资源消耗与写入量和查询量之间的联系,便于做容量管理和规划。
 

主(Master)节点说明

主节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的。默认情况下任何一个集群中的节点都有可能被选为主节点。索引数据和搜索查询等操作会占用大量的cpu,内存,io资源,为了确保一个集群的稳定,分离主节点和数据节点是一个比较好的选择。
 
虽然主节点也可以协调节点,路由搜索和从客户端新增数据到数据节点,但最好不要使用这些专用的主节点。一个重要的原则是,尽可能做尽量少的工作。创建一个独立的主节点只需在配置文件中添加如下内容:
node.master: true
node.data: false为了防止数据丢失,配置discovery.zen.minimum_master_nodes设置是至关重要的(默认为1),每个主节点应该知道形成一个集群的最小数量的主资格节点的数量。解释如下:
 
假设我们有一个集群。有3个主资格节点,当网络发生故障的时候,有可能其中一个节点不能和其他节点进行通信了。这个时候,当discovery.zen.minimum_master_nodes设置为1的时候,就会分成两个小的独立集群,当网络好的时候,就会出现数据错误或者丢失数据的情况。当discovery.zen.minimum_master_nodes设置为2的时候,一个网络中有两个主资格节点,可以继续工作,另一部分,由于只有一个主资格节点,则不会形成一个独立的集群,这个时候当网络回复的时候,节点又会从新加入集群。设置这个值的原则是:
(master_eligible_nodes / 2)+ 1这个参数也可以动态设置:
PUT localhost:9200/_cluster/settings
{
"transient": {
"discovery.zen.minimum_master_nodes": 2
}
}

数据节点说明

数据节点主要是存储索引数据的节点,主要对文档进行增删改查操作,聚合操作等。数据节点对cpu,内存,io要求较高,在优化的时候需要监控数据节点的状态,当资源不够的时候,需要在集群中添加新的节点。数据节点的配置如下:
node.master: false
node.data: true数据节点路径设置,每一个主节点和数据节点都需要知道分片,索引,元数据的物理存储位置,path.data默认位为 $ES_HOME/data,可以通过配置文件 elasticsearch.yml进行修改,例如:
path.data: /data/es/data/这个设置也可以在命令行上执行,例如:
./bin/elasticsearch --path.data /data/es/data这个路径最好进行单独配置,这样Elasticsearch的目录和数据的目录就会分开。当删除了Elasticsearch主目录的时候,不会影响到数据。通过rpm安装默认是分开的。
 
数据目录可以被多个节点共享,甚至可以属于不同的集群,为了防止多个节点共享相同的数据路径,可以在配置文件elasticsearch.yml中添加:node.max_local_storage_nodes: 1
 
注意:在相同的数据目录不要运行不同类型的节点(例如:master, data, client)这很容易导致意外的数据丢失。
 

客户端节点说明

当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。独立的客户端节点在一个比较大的集群中是非常有用的,他协调主节点和数据节点,客户端节点加入集群可以得到集群的状态,根据集群的状态可以直接路由请求。

警告:添加太多的客户端节点对集群是一种负担,因为主节点必须等待每一个节点集群状态的更新确认!客户节点的作用不应被夸大 , 数据节点也可以起到类似的作用。配置如下:
node.master: false
node.data: false

部落节点说明

部落节点可以跨越多个集群,它可以接收每个集群的状态,然后合并成一个全局集群的状态,它可以读写所有节点上的数据,部落节点在elasticsearch.yml中的配置如下:
tribe:
t1:
cluster.name: cluster_one
t2:
cluster.name: cluster_twoT1和T2是任意的名字代表连接到每个集群。上面的示例配置两集群连接,名称分别是T1和T2。默认情况下部落节点通过广播可以做为客户端连接每一个集群。大多数情况下,部落节点可以像单节点一样对集群进行操作。
 
注意:以下操作将和单节点操作不同,
如果两个集群的名称相同,部落节点只会连接其中一个。由于没有主节点,当设置local为true的是,主节点的读操作会被自动的执行,例如:集群统计,集群健康度。主节点级别的写操作将被拒绝,这些应该是在一个集群进行。部落节点可以通过块(block)设置所有的写操作和所有的元数据操作,例如:
tribe:
blocks:
write: true
metadata: true部落节点可以也可以在选中的索引块中进行配置,例如:
tribe:
blocks:
write.indices: hk*,ldn*
metadata.indices: hk*,ldn*当多个集群有相同的索引名的时候,默认情况下,部落的节点将选择其中一个。这可以通过tribe.on_conflict setting进行配置,可以设置排除那些索引或者指定固定的部落名称。 查看全部
elasticsearch.png


摘要


在Elasticsearch中节点可以分为主(master)节点,数据(data)节点,客户端节点和部落节点,每种类型的节点有不同的使用方法,对于一个大的集群中,合理的配置这些属性,对集群的健壮性和性能有很大的帮助。
 


节点类型


当我们启动Elasticsearch的实例,就会启动至少一个节点。相同集群名的多个节点的连接就组成了一个集群,在默认情况下,集群中的每个节点都可以处理http请求和集群节点间的数据传输,集群中所有的节点都知道集群中其他所有的节点,可以将客户端请求转发到适当的节点。节点有以下类型:
  • 主(master)节点:在一个节点上当node.master设置为True(默认)的时候,它有资格被选作为主节点,控制整个集群。
  • 数据(data)节点:在一个节点上node.data设置为True(默认)的时候。该节点保存数据和执行数据相关的操作,如增删改查,搜索,和聚合。
  • 客户端节点:当一个节点的node.master和node.data都设置为false的时候,它既不能保持数据也不能成为主节点,该节点可以作为客户端节点,可以响应用户的情况,并把相关操作发送到其他节点。
  • 部落节点: 当一个节点配置tribe.*的时候,它是一个特殊的客户端,它可以连接多个集群,在所有连接的集群上执行搜索和其他操作。

 
默认情况下,节点配置是一个主节点和一个数据节点。这是非常方便的小集群,但随着集群的发展,分离主节点和数据节点将变得很重要。
 
大家知道Elasticsearch的data node除了放数据以外,也可以兼任master和client的角色,多数同学会将这些角色混入到data node。然而对于一个规模较大,用户较多的集群,master和client在一些极端使用情况下可能会有性能瓶颈甚至内存溢出,从而使得共存的data node故障。data node的故障恢复涉及到数据的迁移,对集群资源有一定消耗,容易造成数据写入延迟或者查询减慢。如果将master和client独立出来,一旦出现问题,重启后几乎是瞬间就恢复的,对用户几乎没有任何影响。另外将这些角色独立出来的以后,也将对应的计算资源消耗从data node剥离出来,更容易掌握data node资源消耗与写入量和查询量之间的联系,便于做容量管理和规划。
 


主(Master)节点说明


主节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的。默认情况下任何一个集群中的节点都有可能被选为主节点。索引数据和搜索查询等操作会占用大量的cpu,内存,io资源,为了确保一个集群的稳定,分离主节点和数据节点是一个比较好的选择
 
虽然主节点也可以协调节点,路由搜索和从客户端新增数据到数据节点,但最好不要使用这些专用的主节点。一个重要的原则是,尽可能做尽量少的工作。创建一个独立的主节点只需在配置文件中添加如下内容:
node.master: true 
node.data: false
为了防止数据丢失,配置discovery.zen.minimum_master_nodes设置是至关重要的(默认为1),每个主节点应该知道形成一个集群的最小数量的主资格节点的数量。解释如下:
 
假设我们有一个集群。有3个主资格节点,当网络发生故障的时候,有可能其中一个节点不能和其他节点进行通信了。这个时候,当discovery.zen.minimum_master_nodes设置为1的时候,就会分成两个小的独立集群,当网络好的时候,就会出现数据错误或者丢失数据的情况。当discovery.zen.minimum_master_nodes设置为2的时候,一个网络中有两个主资格节点,可以继续工作,另一部分,由于只有一个主资格节点,则不会形成一个独立的集群,这个时候当网络回复的时候,节点又会从新加入集群。设置这个值的原则是:
(master_eligible_nodes / 2)+ 1
这个参数也可以动态设置:
PUT localhost:9200/_cluster/settings
{
"transient": {
"discovery.zen.minimum_master_nodes": 2
}
}


数据节点说明


数据节点主要是存储索引数据的节点,主要对文档进行增删改查操作,聚合操作等。数据节点对cpu,内存,io要求较高,在优化的时候需要监控数据节点的状态,当资源不够的时候,需要在集群中添加新的节点。数据节点的配置如下:
node.master: false 
node.data: true
数据节点路径设置,每一个主节点和数据节点都需要知道分片,索引,元数据的物理存储位置,path.data默认位为 $ES_HOME/data,可以通过配置文件 elasticsearch.yml进行修改,例如:
path.data:  /data/es/data/
这个设置也可以在命令行上执行,例如:
./bin/elasticsearch --path.data /data/es/data
这个路径最好进行单独配置,这样Elasticsearch的目录和数据的目录就会分开。当删除了Elasticsearch主目录的时候,不会影响到数据。通过rpm安装默认是分开的。
 
数据目录可以被多个节点共享,甚至可以属于不同的集群,为了防止多个节点共享相同的数据路径,可以在配置文件elasticsearch.yml中添加:node.max_local_storage_nodes: 1
 
注意:在相同的数据目录不要运行不同类型的节点(例如:master, data, client)这很容易导致意外的数据丢失。
 


客户端节点说明


当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。独立的客户端节点在一个比较大的集群中是非常有用的,他协调主节点和数据节点,客户端节点加入集群可以得到集群的状态,根据集群的状态可以直接路由请求。

警告:添加太多的客户端节点对集群是一种负担,因为主节点必须等待每一个节点集群状态的更新确认!客户节点的作用不应被夸大 , 数据节点也可以起到类似的作用。配置如下:
node.master: false 
node.data: false


部落节点说明


部落节点可以跨越多个集群,它可以接收每个集群的状态,然后合并成一个全局集群的状态,它可以读写所有节点上的数据,部落节点在elasticsearch.yml中的配置如下:
tribe:
t1:
cluster.name: cluster_one
t2:
cluster.name: cluster_two
T1和T2是任意的名字代表连接到每个集群。上面的示例配置两集群连接,名称分别是T1和T2。默认情况下部落节点通过广播可以做为客户端连接每一个集群。大多数情况下,部落节点可以像单节点一样对集群进行操作。
 
注意:以下操作将和单节点操作不同,
如果两个集群的名称相同,部落节点只会连接其中一个。由于没有主节点,当设置local为true的是,主节点的读操作会被自动的执行,例如:集群统计,集群健康度。主节点级别的写操作将被拒绝,这些应该是在一个集群进行。部落节点可以通过块(block)设置所有的写操作和所有的元数据操作,例如:
tribe:
blocks:
write: true
metadata: true
部落节点可以也可以在选中的索引块中进行配置,例如:
tribe:
blocks:
write.indices: hk*,ldn*
metadata.indices: hk*,ldn*
当多个集群有相同的索引名的时候,默认情况下,部落的节点将选择其中一个。这可以通过tribe.on_conflict setting进行配置,可以设置排除那些索引或者指定固定的部落名称。

Python调用Zabbix API实例

Nock 发表了文章 • 0 个评论 • 134 次浏览 • 2016-12-06 19:59 • 来自相关话题

#!/usr/bin/python
#coding:utf-8


import json
import urllib2
from urllib2 import URLError
import sys,argparse

class zabbix_api:
def __init__(self):
self.url = 'http://192.168.210.13:81/zabbix/api_jsonrpc.php' #修改URL
self.header = {"Content-Type":"application/json"}
#验证信息
def user_login(self):
data = json.dumps({
"jsonrpc": "2.0",
"method": "user.login",
"params": {
"user": "Admin", #修改用户名
"password": "zabbix" #修改密码
},
"id": 0
})

request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "\033[041m 用户认证失败,请检查 !\033[0m", e.code
else:
response = json.loads(result.read())
result.close()
#print response['result']
self.authID = response['result']
return self.authID
#主机查询
def host_get(self,hostName=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "host.get",
"params": {
"output": "extend",
"filter":{
"host":hostName
}
},
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
if hasattr(e, 'reason'):
print 'We failed to reach a server.'
print 'Reason: ', e.reason
elif hasattr(e, 'code'):
print 'The server could not fulfill the request.'
print 'Error code: ', e.code
else:
response = json.loads(result.read())
#print response
result.close()
print "主机数量: \033[31m%s\033[0m"%(len(response['result']))
for host in response['result']:
status={"0":"OK","1":"Disabled"}
available={"0":"Unknown","1":"available","2":"Unavailable"}
#print host
if len(hostName)==0:
print "HostID : %s\t HostName : %s\t Status :\033[32m%s\033[0m \t Available :\033[31m%s\033[0m"%(host['hostid'],host['name'],status[host['status']],available[host['available']])
else:
print "HostID : %s\t HostName : %s\t Status :\033[32m%s\033[0m \t Available :\033[31m%s\033[0m"%(host['hostid'],host['name'],status[host['status']],available[host['available']])
return host['hostid']
#图形查询
def graph_get(self,hostids,graphname=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "graph.get",
"params": {
"output": "extend",
"hostids": hostids,
"sortfield": "name"
},
"auth": self.user_login(),
"id":1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
if hasattr(e, 'reason'):
print 'We failed to reach a server.'
print 'Reason: ', e.reason
elif hasattr(e, 'code'):
print 'The server could not fulfill the request.'
print 'Error code: ', e.code
else:
response = json.loads(result.read())
result.close()
print "图形数量: \033[31m%s\033[0m"%(len(response['result']))
for graph in response['result']:
if len(graphname)==0:
print "graphid : %s\t graphname : %s\t width :\033[32m%s\033[0m \t height :\033[31m%s\033[0m"%(graph['graphid'],graph['name'],graph['width'],graph['height'])
else:
print "graphid : %s\t graphname : %s\t width :\033[32m%s\033[0m \t height :\033[31m%s\033[0m"%(graph['graphid'],graph['name'],graph['width'],graph['height'])
return graph['graphid']
#筛选图查询
def screen_get(self,ScreenName=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "screen.get",
"params": {
"output": "extend",
"selectScreenItems": "extend",
"filter": {
"name": ScreenName
}
},
"auth":self.user_login(),
"id":1
})

request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print 'Error as ', e
else:
response = json.loads(result.read())
result.close()
print "筛选图数量: \033[31m%s\033[0m"%(len(response['result']))
for screen in response['result']:
if len(ScreenName)==0:
print "ScreenID : %s\t ScreenName : %s\t Hsize :\033[32m%s\033[0m \t Vsize :\033[31m%s\033[0m"%(screen['screenid'],screen['name'],screen['hsize'],screen['vsize'])
else:
print "ScreenID : %s\t ScreenName : %s\t Hsize :\033[32m%s\033[0m \t Vsize :\033[31m%s\033[0m"%(screen['screenid'],screen['name'],screen['hsize'],screen['vsize'])
return screen['screenid']
#主机组查询
def hostgroup_get(self, hostgroupName=''):
data = json.dumps({
"jsonrpc":"2.0",
"method":"hostgroup.get",
"params": {
"output": "extend",
"filter": {
"name": hostgroupName
}
},
"auth":self.user_login(),
"id":1
})

request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
#print result.read()
response = json.loads(result.read())
result.close()
#print response()
for group in response['result']:
if len(hostgroupName)==0:
print "hostgroup: \033[31m%s\033[0m \tgroupid : %s" %(group['name'],group['groupid'])
else:
print "hostgroup: \033[31m%s\033[0m \tgroupid : %s" %(group['name'],group['groupid'])
self.hostgroupID = group['groupid']
return group['groupid']
#模版查询
def template_get(self,templateName=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "template.get",
"params": {
"output": "extend",
"filter": {
"name":templateName
}
},
"auth":self.user_login(),
"id":1
})

request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
#print response
for template in response['result']:
if len(templateName)==0:
print "template : \033[31m%s\033[0m\t id : %s" % (template['name'], template['templateid'])
else:
self.templateID = response['result'][0]['templateid']
print "Template Name : \033[31m%s\033[0m "%templateName
return response['result'][0]['templateid']
#主机组创建
def hostgroup_create(self,hostgroupName):
if self.hostgroup_get(hostgroupName):
print "hostgroup \033[42m%s\033[0m is exist !"%hostgroupName
sys.exit(1)
data = json.dumps({
"jsonrpc": "2.0",
"method": "hostgroup.create",
"params": {
"name": hostgroupName
},
"auth": self.user_login(),
"id": 1
})
request=urllib2.Request(self.url,data)

for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "\033[042m 添加主机组:%s\033[0m hostgroupID : %s"%(hostgroupName,response['result']['groupids'])
#筛选图添加
def screen_create(self,ScreenName,hsize,vsize):
if self.screen_get(ScreenName):
print "Screen \033[42m%s\033[0m is exist !"%ScreenName
sys.exit(1)
data = json.dumps({
"jsonrpc": "2.0",
"method": "screen.create",
"params": {
"name": ScreenName,
"hsize": hsize,
"vsize": vsize
},
"auth": self.user_login(),
"id": 1
})
request=urllib2.Request(self.url,data)

for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "\033[042m 添加筛选图:%s\033[0m ScreenName : %s"%(ScreenName,response['result']['screenids'])
#筛选图图形添加
def screen_item_create(self,screenid,resourceid,x,y):
if self.screen_item_create(resourceid):
print "resource \033[042m%s\033[0m is exist !"%resourceid
sys.exit(1)
screen_list=[]
for i in screenid.split(','):
var = {}
var['screenid'] = self.screen_get(i)
screen_list.append(var)
data = json.dumps({
"jsonrpc": "2.0",
"method": "screenitem.create",
"params": {
"screenid": screen_list,
"resourceid": resourceid,
"x": x,
"y": y
},
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])
try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "\033[042m 添加筛选图形:%s\033[0m resourceid : %s"%(resourceid,response['result']['resourceids'])
#主机创建
def host_create(self, hostip, hostgroupName, templateName):
if self.host_get(hostip):
print "\033[041m该主机已经添加!\033[0m"
sys.exit(1)

group_list=[]
template_list=[]
for i in hostgroupName.split(','):
var = {}
var['groupid'] = self.hostgroup_get(i)
group_list.append(var)
for i in templateName.split(','):
var={}
var['templateid']=self.template_get(i)
template_list.append(var)

data = json.dumps({
"jsonrpc":"2.0",
"method":"host.create",
"params":{
"host": hostip,
"interfaces": [
{
"type": 1,
"main": 1,
"useip": 1,
"ip": hostip,
"dns": "",
"port": "10050"
}
],
"groups": group_list,
"templates": template_list,
},
"auth": self.user_login(),
"id":1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "添加主机 : \033[42m%s\031[0m \tid :\033[31m%s\033[0m" % (hostip, response['result']['hostids'])
#关闭主机
def host_disable(self,hostip):
data=json.dumps({
"jsonrpc": "2.0",
"method": "host.update",
"params": {
"hostid": self.host_get(hostip),
"status": 1
},
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])
try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print '----主机现在状态------------'
print self.host_get(hostip)
#删除主机
def host_delete(self,hostid):
hostid_list=[]
#print type(hostid)
for i in hostid.split(','):
var = {}
var['hostid'] = self.host_get(i)
hostid_list.append(var)
data=json.dumps({
"jsonrpc": "2.0",
"method": "host.delete",
"params": hostid_list,
"auth": self.user_login(),
"id": 1
})

request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except Exception,e:
print e
else:

result.close()
print "主机 \033[041m %s\033[0m 已经删除 !"%hostid
#删除筛选图
def screen_delete(self,screenid):
screenid_list=[]
for i in screenid.split(','):
var = {}
var['screenid'] = self.screen_get(i)
screenid_list.append(var)
data=json.dumps({
"jsonrpc": "2.0",
"method": "screen.delete",
"params": screenid_list,
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])
try:
result = urllib2.urlopen(request)
except Exception,e:
print e
else:
result.close()
print "筛选图 \033[041m %s\033[0m 已经删除 !"%screenid


if __name__ == "__main__":
zabbix=zabbix_api()
parser=argparse.ArgumentParser(description='zabbix api ',usage='%(prog)s [options]')
parser.add_argument('-H','--host',nargs='?',dest='listhost',default='host',help='查询主机')
parser.add_argument('-Z','--graph',nargs='?',dest='listgraph',default='graph',help='查询图形')
parser.add_argument('-G','--group',nargs='?',dest='listgroup',default='group',help='查询主机组')
parser.add_argument('-T','--template',nargs='?',dest='listtemp',default='template',help='查询模板信息')
parser.add_argument('-S','--screen',nargs='?',dest='listscreen',default='screen',help='查询筛选图')
parser.add_argument('-A','--add-group',nargs=1,dest='addgroup',help='添加主机组')
parser.add_argument('-C','--add-host',dest='addhost',nargs=3,metavar=('192.168.2.1', 'test01,test02', 'Template01,Template02'),help='添加主机,多个主机组或模板使用分号')
parser.add_argument('-B','--create-screenitem',dest='addscreenitem',nargs=4,metavar=('38', '365', '0', '0'),help='添加筛选图图形')
parser.add_argument('-J','--add-screen',nargs=3,dest='addscreen',help='添加筛选图')
parser.add_argument('-d','--disable',dest='disablehost',nargs=1,metavar=('192.168.2.1'),help='禁用主机')
parser.add_argument('-D','--delete',dest='deletehost',nargs='+',metavar=('192.168.2.1'),help='删除主机,多个主机之间用分号')
parser.add_argument('-P','--delete-screen',dest='deletescreen',nargs='+',metavar=('38'),help='删除筛选图,多个筛选图之间用分号')
parser.add_argument('-v','--version', action='version', version='%(prog)s 1.0')
if len(sys.argv)==1:
print parser.print_help()
else:
args=parser.parse_args()

if args.listhost != 'host' :
if args.listhost:
zabbix.host_get(args.listhost)
else:
zabbix.host_get()
if args.listgraph != 'graph':
if args.listgraph:
zabbix.graph_get(args.listgraph)
else:
zabbix.graph_get()
if args.listgroup !='group':
if args.listgroup:
zabbix.hostgroup_get(args.listgroup)
else:
zabbix.hostgroup_get()
if args.listtemp != 'template':
if args.listtemp:
zabbix.template_get(args.listtemp)
else:
zabbix.template_get()
if args.listscreen != 'screen':
if args.listscreen:
zabbix.screen_get(args.listscreen)
else:
zabbix.screen_get()
if args.addgroup:
zabbix.hostgroup_create(args.addgroup[0])
if args.addhost:
zabbix.host_create(args.addhost[0], args.addhost[1], args.addhost[2])
if args.addscreen:
zabbix.screen_create(args.addscreen[0],args.addscreen[1],args.addscreen[2])
if args.addscreenitem:
zabbix.screen_item_create(args.addscreenitem[0],args.addscreenitem[1],args.addscreenitem[2],args.addscreenitem[3])
if args.disablehost:
zabbix.host_disable(args.disablehost)
if args.deletehost:
zabbix.host_delete(args.deletehost[0])
if args.deletescreen:
zabbix.screen_delete(args.deletescreen[0]) 查看全部
#!/usr/bin/python 
#coding:utf-8


import json
import urllib2
from urllib2 import URLError
import sys,argparse

class zabbix_api:
def __init__(self):
self.url = 'http://192.168.210.13:81/zabbix/api_jsonrpc.php' #修改URL
self.header = {"Content-Type":"application/json"}
#验证信息
def user_login(self):
data = json.dumps({
"jsonrpc": "2.0",
"method": "user.login",
"params": {
"user": "Admin", #修改用户名
"password": "zabbix" #修改密码
},
"id": 0
})

request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "\033[041m 用户认证失败,请检查 !\033[0m", e.code
else:
response = json.loads(result.read())
result.close()
#print response['result']
self.authID = response['result']
return self.authID
#主机查询
def host_get(self,hostName=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "host.get",
"params": {
"output": "extend",
"filter":{
"host":hostName
}
},
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
if hasattr(e, 'reason'):
print 'We failed to reach a server.'
print 'Reason: ', e.reason
elif hasattr(e, 'code'):
print 'The server could not fulfill the request.'
print 'Error code: ', e.code
else:
response = json.loads(result.read())
#print response
result.close()
print "主机数量: \033[31m%s\033[0m"%(len(response['result']))
for host in response['result']:
status={"0":"OK","1":"Disabled"}
available={"0":"Unknown","1":"available","2":"Unavailable"}
#print host
if len(hostName)==0:
print "HostID : %s\t HostName : %s\t Status :\033[32m%s\033[0m \t Available :\033[31m%s\033[0m"%(host['hostid'],host['name'],status[host['status']],available[host['available']])
else:
print "HostID : %s\t HostName : %s\t Status :\033[32m%s\033[0m \t Available :\033[31m%s\033[0m"%(host['hostid'],host['name'],status[host['status']],available[host['available']])
return host['hostid']
#图形查询
def graph_get(self,hostids,graphname=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "graph.get",
"params": {
"output": "extend",
"hostids": hostids,
"sortfield": "name"
},
"auth": self.user_login(),
"id":1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
if hasattr(e, 'reason'):
print 'We failed to reach a server.'
print 'Reason: ', e.reason
elif hasattr(e, 'code'):
print 'The server could not fulfill the request.'
print 'Error code: ', e.code
else:
response = json.loads(result.read())
result.close()
print "图形数量: \033[31m%s\033[0m"%(len(response['result']))
for graph in response['result']:
if len(graphname)==0:
print "graphid : %s\t graphname : %s\t width :\033[32m%s\033[0m \t height :\033[31m%s\033[0m"%(graph['graphid'],graph['name'],graph['width'],graph['height'])
else:
print "graphid : %s\t graphname : %s\t width :\033[32m%s\033[0m \t height :\033[31m%s\033[0m"%(graph['graphid'],graph['name'],graph['width'],graph['height'])
return graph['graphid']
#筛选图查询
def screen_get(self,ScreenName=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "screen.get",
"params": {
"output": "extend",
"selectScreenItems": "extend",
"filter": {
"name": ScreenName
}
},
"auth":self.user_login(),
"id":1
})

request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print 'Error as ', e
else:
response = json.loads(result.read())
result.close()
print "筛选图数量: \033[31m%s\033[0m"%(len(response['result']))
for screen in response['result']:
if len(ScreenName)==0:
print "ScreenID : %s\t ScreenName : %s\t Hsize :\033[32m%s\033[0m \t Vsize :\033[31m%s\033[0m"%(screen['screenid'],screen['name'],screen['hsize'],screen['vsize'])
else:
print "ScreenID : %s\t ScreenName : %s\t Hsize :\033[32m%s\033[0m \t Vsize :\033[31m%s\033[0m"%(screen['screenid'],screen['name'],screen['hsize'],screen['vsize'])
return screen['screenid']
#主机组查询
def hostgroup_get(self, hostgroupName=''):
data = json.dumps({
"jsonrpc":"2.0",
"method":"hostgroup.get",
"params": {
"output": "extend",
"filter": {
"name": hostgroupName
}
},
"auth":self.user_login(),
"id":1
})

request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
#print result.read()
response = json.loads(result.read())
result.close()
#print response()
for group in response['result']:
if len(hostgroupName)==0:
print "hostgroup: \033[31m%s\033[0m \tgroupid : %s" %(group['name'],group['groupid'])
else:
print "hostgroup: \033[31m%s\033[0m \tgroupid : %s" %(group['name'],group['groupid'])
self.hostgroupID = group['groupid']
return group['groupid']
#模版查询
def template_get(self,templateName=''):
data = json.dumps({
"jsonrpc": "2.0",
"method": "template.get",
"params": {
"output": "extend",
"filter": {
"name":templateName
}
},
"auth":self.user_login(),
"id":1
})

request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
#print response
for template in response['result']:
if len(templateName)==0:
print "template : \033[31m%s\033[0m\t id : %s" % (template['name'], template['templateid'])
else:
self.templateID = response['result'][0]['templateid']
print "Template Name : \033[31m%s\033[0m "%templateName
return response['result'][0]['templateid']
#主机组创建
def hostgroup_create(self,hostgroupName):
if self.hostgroup_get(hostgroupName):
print "hostgroup \033[42m%s\033[0m is exist !"%hostgroupName
sys.exit(1)
data = json.dumps({
"jsonrpc": "2.0",
"method": "hostgroup.create",
"params": {
"name": hostgroupName
},
"auth": self.user_login(),
"id": 1
})
request=urllib2.Request(self.url,data)

for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "\033[042m 添加主机组:%s\033[0m hostgroupID : %s"%(hostgroupName,response['result']['groupids'])
#筛选图添加
def screen_create(self,ScreenName,hsize,vsize):
if self.screen_get(ScreenName):
print "Screen \033[42m%s\033[0m is exist !"%ScreenName
sys.exit(1)
data = json.dumps({
"jsonrpc": "2.0",
"method": "screen.create",
"params": {
"name": ScreenName,
"hsize": hsize,
"vsize": vsize
},
"auth": self.user_login(),
"id": 1
})
request=urllib2.Request(self.url,data)

for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "\033[042m 添加筛选图:%s\033[0m ScreenName : %s"%(ScreenName,response['result']['screenids'])
#筛选图图形添加
def screen_item_create(self,screenid,resourceid,x,y):
if self.screen_item_create(resourceid):
print "resource \033[042m%s\033[0m is exist !"%resourceid
sys.exit(1)
screen_list=[]
for i in screenid.split(','):
var = {}
var['screenid'] = self.screen_get(i)
screen_list.append(var)
data = json.dumps({
"jsonrpc": "2.0",
"method": "screenitem.create",
"params": {
"screenid": screen_list,
"resourceid": resourceid,
"x": x,
"y": y
},
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])
try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "\033[042m 添加筛选图形:%s\033[0m resourceid : %s"%(resourceid,response['result']['resourceids'])
#主机创建
def host_create(self, hostip, hostgroupName, templateName):
if self.host_get(hostip):
print "\033[041m该主机已经添加!\033[0m"
sys.exit(1)

group_list=[]
template_list=[]
for i in hostgroupName.split(','):
var = {}
var['groupid'] = self.hostgroup_get(i)
group_list.append(var)
for i in templateName.split(','):
var={}
var['templateid']=self.template_get(i)
template_list.append(var)

data = json.dumps({
"jsonrpc":"2.0",
"method":"host.create",
"params":{
"host": hostip,
"interfaces": [
{
"type": 1,
"main": 1,
"useip": 1,
"ip": hostip,
"dns": "",
"port": "10050"
}
],
"groups": group_list,
"templates": template_list,
},
"auth": self.user_login(),
"id":1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print "添加主机 : \033[42m%s\031[0m \tid :\033[31m%s\033[0m" % (hostip, response['result']['hostids'])
#关闭主机
def host_disable(self,hostip):
data=json.dumps({
"jsonrpc": "2.0",
"method": "host.update",
"params": {
"hostid": self.host_get(hostip),
"status": 1
},
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])
try:
result = urllib2.urlopen(request)
except URLError as e:
print "Error as ", e
else:
response = json.loads(result.read())
result.close()
print '----主机现在状态------------'
print self.host_get(hostip)
#删除主机
def host_delete(self,hostid):
hostid_list=[]
#print type(hostid)
for i in hostid.split(','):
var = {}
var['hostid'] = self.host_get(i)
hostid_list.append(var)
data=json.dumps({
"jsonrpc": "2.0",
"method": "host.delete",
"params": hostid_list,
"auth": self.user_login(),
"id": 1
})

request = urllib2.Request(self.url,data)
for key in self.header:
request.add_header(key, self.header[key])

try:
result = urllib2.urlopen(request)
except Exception,e:
print e
else:

result.close()
print "主机 \033[041m %s\033[0m 已经删除 !"%hostid
#删除筛选图
def screen_delete(self,screenid):
screenid_list=[]
for i in screenid.split(','):
var = {}
var['screenid'] = self.screen_get(i)
screenid_list.append(var)
data=json.dumps({
"jsonrpc": "2.0",
"method": "screen.delete",
"params": screenid_list,
"auth": self.user_login(),
"id": 1
})
request = urllib2.Request(self.url, data)
for key in self.header:
request.add_header(key, self.header[key])
try:
result = urllib2.urlopen(request)
except Exception,e:
print e
else:
result.close()
print "筛选图 \033[041m %s\033[0m 已经删除 !"%screenid


if __name__ == "__main__":
zabbix=zabbix_api()
parser=argparse.ArgumentParser(description='zabbix api ',usage='%(prog)s [options]')
parser.add_argument('-H','--host',nargs='?',dest='listhost',default='host',help='查询主机')
parser.add_argument('-Z','--graph',nargs='?',dest='listgraph',default='graph',help='查询图形')
parser.add_argument('-G','--group',nargs='?',dest='listgroup',default='group',help='查询主机组')
parser.add_argument('-T','--template',nargs='?',dest='listtemp',default='template',help='查询模板信息')
parser.add_argument('-S','--screen',nargs='?',dest='listscreen',default='screen',help='查询筛选图')
parser.add_argument('-A','--add-group',nargs=1,dest='addgroup',help='添加主机组')
parser.add_argument('-C','--add-host',dest='addhost',nargs=3,metavar=('192.168.2.1', 'test01,test02', 'Template01,Template02'),help='添加主机,多个主机组或模板使用分号')
parser.add_argument('-B','--create-screenitem',dest='addscreenitem',nargs=4,metavar=('38', '365', '0', '0'),help='添加筛选图图形')
parser.add_argument('-J','--add-screen',nargs=3,dest='addscreen',help='添加筛选图')
parser.add_argument('-d','--disable',dest='disablehost',nargs=1,metavar=('192.168.2.1'),help='禁用主机')
parser.add_argument('-D','--delete',dest='deletehost',nargs='+',metavar=('192.168.2.1'),help='删除主机,多个主机之间用分号')
parser.add_argument('-P','--delete-screen',dest='deletescreen',nargs='+',metavar=('38'),help='删除筛选图,多个筛选图之间用分号')
parser.add_argument('-v','--version', action='version', version='%(prog)s 1.0')
if len(sys.argv)==1:
print parser.print_help()
else:
args=parser.parse_args()

if args.listhost != 'host' :
if args.listhost:
zabbix.host_get(args.listhost)
else:
zabbix.host_get()
if args.listgraph != 'graph':
if args.listgraph:
zabbix.graph_get(args.listgraph)
else:
zabbix.graph_get()
if args.listgroup !='group':
if args.listgroup:
zabbix.hostgroup_get(args.listgroup)
else:
zabbix.hostgroup_get()
if args.listtemp != 'template':
if args.listtemp:
zabbix.template_get(args.listtemp)
else:
zabbix.template_get()
if args.listscreen != 'screen':
if args.listscreen:
zabbix.screen_get(args.listscreen)
else:
zabbix.screen_get()
if args.addgroup:
zabbix.hostgroup_create(args.addgroup[0])
if args.addhost:
zabbix.host_create(args.addhost[0], args.addhost[1], args.addhost[2])
if args.addscreen:
zabbix.screen_create(args.addscreen[0],args.addscreen[1],args.addscreen[2])
if args.addscreenitem:
zabbix.screen_item_create(args.addscreenitem[0],args.addscreenitem[1],args.addscreenitem[2],args.addscreenitem[3])
if args.disablehost:
zabbix.host_disable(args.disablehost)
if args.deletehost:
zabbix.host_delete(args.deletehost[0])
if args.deletescreen:
zabbix.screen_delete(args.deletescreen[0])

2016运维世界大会深圳站PPT分享

回复

OpenSkill 发起了问题 • 1 人关注 • 0 个回复 • 174 次浏览 • 2016-12-05 18:24 • 来自相关话题

学习新技术的10个技巧

Nock 发表了文章 • 0 个评论 • 197 次浏览 • 2016-12-05 14:23 • 来自相关话题

我们住在一个非常令人兴奋的时代。 从来没有教育如此便宜地提供给群众(如果不是免费的)。 这种媒介本身从教室设置,博客,截屏和完整的大学课程,作为一组视频和互动论坛做了构造转变。 坐拥如此众多的学习资源,我们没有任何理由不去好好利用。随之而来的问题便是如何在这知识的海洋中选择自己的前进方向。在这篇文章中,我将简要概括一些技术学习的建议,希望可以给你带来一些启发。
 
** 尽管我的建议主要涉及的是软件开发方面,但是这些原则在其他领域也同样适用。

1、克服惯性(Overcoming Inertia)





万事开头难,克服惯性是学习新技术的第一步。举个日常生活中惯性存在的简单例子,当我们看电视的时候会因为遥控器不在身边而懒得换台。幸运的是有很多的小技巧可以调动我们的积极性,帮助我们克服惯性。对于我来说,微习惯是一个很好用的小技巧。与其被手头的任务吓到,不如将任务细分为一个个具体的微任务,然后挑选其中的一个开始做起。就“拿到遥控器”这个例子来说,首先扭动你的脚趾,向前伸出,然后推动整个人离开沙发。下一步,身体滑到地上,用脚拿到遥控器,然后起身。通过完成一个个的微任务,你会发现自己克服了惯性,并且这项任务不再显得难以完成。这个方法可以被应用到学习新技能的过程中。关键就是将大块任务细分为微任务。
 
把你需要学习的知识做分解,就像我们看出一样,我们通常会去看书目录,通过目录定位到具体的知识内容,而我们学习一门新技术把知识分解,就像写书之前我得先把书的目录定好一样,这样我们就可以有明确的学习方向,各个击破。

2、关注大牛(Watch the Pros)





学习新技能的第一步是明确要学什么。最初你会有强大的激情,希望把一些学好,这种原始的学习欲望非常重要,这种欲望可以在你的学习低潮期给你提供动力。你想学的或许是一门新的编程语言、应用框架或者是新的工具,一旦你确定了想要的是什么,就立刻去收集相应的优秀群体所做的一些优质的工作成果。这些可以从YouTube、Vimeo、HackerNews、各种博客,甚至是你的微博好友那里获取。关注别人做了些什么可以给你强大的信心,让你觉得这些其实你自己也是可以做到的,增强自己的自信心。
 
关注大牛不仅仅可以让你感觉到这些东西你也可以做到,同时也可以让你了解最新的技术动态。

3、 建立知识网(Let the Information Flow Begin)





当你对自己要学习的东西建立了信心之后,接下来要做的就是做一块海绵,然后开始疯狂地吸收知识。从Google搜索关键词“beginner tutorials”开始吧,搜索一些跟你要学习的知识相关的入门教程。如你所知,Nettuts+上面有成千上百的各种教程供你选择,StackOverflow上面也有很多学习资源。此外,Quora也是一些不错的选择。通过浏览这些网上的资源之后,如果想要集中精力学习某一方面,这时就需要阅读一些相关的书籍了,个人推荐在Amazon上面寻找一些评分较高的专业书籍来提高自己。 
 
在国内你可以通过豆瓣找到评分较高的技术书籍,这样你可以更深入的学习,完善自己的知识脉路和知识点。

4、多听多看(Listen and Watch)





随着你对技术的深入挖掘,你可能会想利用更多其他形式的学习资料,比如podcasts,screencasts等等。我的建议是多用 iTunesU,这上面有很多很专业的知识可以让你对于特定的领域进行深入的探索。

目前,有很多的网站都有提供在线教育服务。王婆卖瓜,这里要首推我们自己的Tuts+ Premium。想要学习PHP或者JavaScript?这里有你最需要的资料。另外,你也可以在下面几个网站上找到自己需要的教程:
UdemyCodeCademyCodeSchool
此外,你也可以看一些免费的会议视频材料,比如YouTube上面的Google IO,以及Confreaks!
 
国内的话你可以到实验楼、慕课、极客学院、腾讯课堂等在线视频和学习的网站,去提高自己的技术能力。

5、行动起来(Time for Action)





现在你已经看了一波又一波的教程以及视频资料,并且对于想学的技术已经有了一个相当深入的了解,接下来做些什么呢?没错,是时候理论联系实际了,实践是检验真理的唯一标准。

用你所掌握的技术做一个个人的小项目,设计一些简单的功能并且实现他们。毫无疑问,你会遇到很多的绊脚石,当遇到它们的时候,在StackOverflow或者Google上面搜索之,解决之。你已经踏上一条成为某一领域专家的旅程,遇到的困难挫折越多,你会变得越睿智。有句老话说得好,“专家是犯错最多的人”,这意味着他们尝试了很多疯狂的事情来探索这门技术的极限,最后,对于这门技术是如何运作的就可以知根知底。拥有这种洞察力之后,他们便可以随心所欲的运用这项技术去按照自己的意愿完成想做的事情(当然,是做好的事情)。

6、写博客(Blogging)





在你进行你的探险之旅的时候,实时记录下你的成长以及犯下的错误大有裨益。在技术领域,博客是最简单易得并且受欢迎的表达载体。当你准备落笔的时候,你会强迫自己整理思路,并且对积累下来的零散的知识片段进行结构梳理。说不定,通过互联网的分享,你的经历和分享会给别人的成长带来帮助。

如果你想走的更远(比如想像Nettuts+上面的职业作者一样),你也可以制作属于自己的screencasts。总的来说,写博客能够提升你的个人沟通能力,这与你学到的技术同样重要。

7、感知技术动向(Feel the Pulse)





社交网络已经广泛应用于人们的日常交流以及发现新鲜事物。Twitter和Facebook是信息的主要来源,与此同时,有很多的网站提供更专注的资讯,如前面提到过的Quora网站,这上面有很多涉及面很广的一些话题供人们评论。在这上面可以找到很多知名大牛的建议以及观点。

浏览StackOverflow上面的众多话题是一个很有意思的过程,你可以看到他人如何探索某种技术的极限。事实上,在人们利用技术做一些疯狂的甚至是荒诞的事情的时候,技术也随之不断的成熟起来。

因此,如果你想要感受到技术的脉搏,并且想确认它是否值得学下去,在StackOverflow上面试着搜索一些话题,看看这个讨论社区的广度与深度。最值得看的是投票最多以及热门话题。你也可以尝试在GitHub上面进行搜索。

8、 参加聚会以及会议(Meetups and Conferences)





尽管社交网络很棒,但是没有任何事物可以取代面对面的交流。在你住的附近参加一些小组聚会,在这里你可以找到志同道合的伙伴。你可以知道他人在做的一些有趣的项目,同时也可以在他人的帮助下解决一些自己遇到的难题!同样的,技术会议对于分享经验以及增长技术大有帮助!
 
技术会议不仅可以增加你的人脉,同事可以可以扩充你对知识的视野,当然也可以让你的知名度更大,让更多的人认识到你是一个大牛。

9、常逛GitHub





GitHub是全世界开源项目的标志性建筑物。它是知识以及优质代码的宝库。当你对某项技术自我感觉良好的时候,下一步便是在GitHub中浏览寻找有趣的项目。阅读开源代码,尽可能多的阅读。这样做的话,你能够学到很多东西,比如说:
如何管理规模较大的项目项目中应用的有趣的库代码规范以及代码全局设计文档风格测试规范解决诡异问题的方法,以及发现项目中有问题的地方

所有的这些知识都在等待着你去挖掘。有趣的是,这些知识的通过一个简单的标签就可以得到,那就是“好奇心”。

10. 专注学习(Concentrated Learning)





如果你担心上述的学习过程太迟缓,那么你也可以尝试一下快速学习模式。你或许听说过“24小时学会某某某”,但是这种方式不是我所推荐的。我认为更合理的是用几周的时间去学习。你可以尝试一下类似"七周学会七种语言"或者"七周学会七种数据库"等学习方法。尽管这些讲的是语言以及数据库方面的学习,但是你在学习其他技术的时候也可以运用这种思维。
 
有一个不太相同的学习风格是“困难学习模式”,这种观点的前提是没有人可以真正掌握一门技术,除非每天都练习。所以,想要成为专家,你就需要不停地进行练习。异曲同工的是你可以查看Katas和Koans,他鼓励的使用你学的知识来解决问题。这些可以让你更好地入门以及接受那些陌生的概念,勇敢走出自己的舒适区,开始学习新知识!
 
学习一门交叉的技能(Learn an Orthogonal Skill)
编程是一项左脑的运动,它利用的是大脑的分析能力,一步一步地寻找解决问题的方法。为了发挥右脑的功能,你可以尝试从事一些创造性的活动,比如说画画、3D建模、折纸、乐器甚至是制作家庭相册等。事实上,编程同样需要大量的创造力。或许你曾经遇到过类似的事情,你在睡梦中找到了问题的解决方案。这是因为你的右脑处理问题的方式很不同,它可以从各种地方获得信息。敏捷开发权威人士Andy Hunt就这个话题写了一本书《程序员的思维修炼》。如果你想点燃你的每一个神经元,建议你开始学习一门交叉的技能。
 

总结

获得新的技能总是令人兴奋。 这是一个新的经验的开始,将塑造你的思维。 但首先,你必须克服你的惯性。 一旦你这样做,你的旅程从网络的每个方面吸收知识开始。 我希望上面介绍的过程为你走过这条漫长的道路提供了一些想法。

作者:Pavan Podila
英文地址:https://code.tutsplus.com/articles/10-tips-for-learning-a-new-technology--net-31631 查看全部
我们住在一个非常令人兴奋的时代。 从来没有教育如此便宜地提供给群众(如果不是免费的)。 这种媒介本身从教室设置,博客,截屏和完整的大学课程,作为一组视频和互动论坛做了构造转变。 坐拥如此众多的学习资源,我们没有任何理由不去好好利用。随之而来的问题便是如何在这知识的海洋中选择自己的前进方向。在这篇文章中,我将简要概括一些技术学习的建议,希望可以给你带来一些启发。
 
** 尽管我的建议主要涉及的是软件开发方面,但是这些原则在其他领域也同样适用。


1、克服惯性(Overcoming Inertia)


inertia.jpg

万事开头难,克服惯性是学习新技术的第一步。举个日常生活中惯性存在的简单例子,当我们看电视的时候会因为遥控器不在身边而懒得换台。幸运的是有很多的小技巧可以调动我们的积极性,帮助我们克服惯性。对于我来说,微习惯是一个很好用的小技巧。与其被手头的任务吓到,不如将任务细分为一个个具体的微任务,然后挑选其中的一个开始做起。就“拿到遥控器”这个例子来说,首先扭动你的脚趾,向前伸出,然后推动整个人离开沙发。下一步,身体滑到地上,用脚拿到遥控器,然后起身。通过完成一个个的微任务,你会发现自己克服了惯性,并且这项任务不再显得难以完成。这个方法可以被应用到学习新技能的过程中。关键就是将大块任务细分为微任务。
 
把你需要学习的知识做分解,就像我们看出一样,我们通常会去看书目录,通过目录定位到具体的知识内容,而我们学习一门新技术把知识分解,就像写书之前我得先把书的目录定好一样,这样我们就可以有明确的学习方向,各个击破。


2、关注大牛(Watch the Pros)


pros.png

学习新技能的第一步是明确要学什么。最初你会有强大的激情,希望把一些学好,这种原始的学习欲望非常重要,这种欲望可以在你的学习低潮期给你提供动力。你想学的或许是一门新的编程语言、应用框架或者是新的工具,一旦你确定了想要的是什么,就立刻去收集相应的优秀群体所做的一些优质的工作成果。这些可以从YouTube、Vimeo、HackerNews、各种博客,甚至是你的微博好友那里获取。关注别人做了些什么可以给你强大的信心,让你觉得这些其实你自己也是可以做到的,增强自己的自信心。
 
关注大牛不仅仅可以让你感觉到这些东西你也可以做到,同时也可以让你了解最新的技术动态。


3、 建立知识网(Let the Information Flow Begin)


begin.png

当你对自己要学习的东西建立了信心之后,接下来要做的就是做一块海绵,然后开始疯狂地吸收知识。从Google搜索关键词“beginner tutorials”开始吧,搜索一些跟你要学习的知识相关的入门教程。如你所知,Nettuts+上面有成千上百的各种教程供你选择,StackOverflow上面也有很多学习资源。此外,Quora也是一些不错的选择。通过浏览这些网上的资源之后,如果想要集中精力学习某一方面,这时就需要阅读一些相关的书籍了,个人推荐在Amazon上面寻找一些评分较高的专业书籍来提高自己。 
 
在国内你可以通过豆瓣找到评分较高的技术书籍,这样你可以更深入的学习,完善自己的知识脉路和知识点。


4、多听多看(Listen and Watch)


ListenWatch.png

随着你对技术的深入挖掘,你可能会想利用更多其他形式的学习资料,比如podcasts,screencasts等等。我的建议是多用 iTunesU,这上面有很多很专业的知识可以让你对于特定的领域进行深入的探索。

目前,有很多的网站都有提供在线教育服务。王婆卖瓜,这里要首推我们自己的Tuts+ Premium。想要学习PHP或者JavaScript?这里有你最需要的资料。另外,你也可以在下面几个网站上找到自己需要的教程:

此外,你也可以看一些免费的会议视频材料,比如YouTube上面的Google IO,以及Confreaks
 
国内的话你可以到实验楼、慕课、极客学院、腾讯课堂等在线视频和学习的网站,去提高自己的技术能力。


5、行动起来(Time for Action)


action.png

现在你已经看了一波又一波的教程以及视频资料,并且对于想学的技术已经有了一个相当深入的了解,接下来做些什么呢?没错,是时候理论联系实际了,实践是检验真理的唯一标准。

用你所掌握的技术做一个个人的小项目,设计一些简单的功能并且实现他们。毫无疑问,你会遇到很多的绊脚石,当遇到它们的时候,在StackOverflow或者Google上面搜索之,解决之。你已经踏上一条成为某一领域专家的旅程,遇到的困难挫折越多,你会变得越睿智。有句老话说得好,“专家是犯错最多的人”,这意味着他们尝试了很多疯狂的事情来探索这门技术的极限,最后,对于这门技术是如何运作的就可以知根知底。拥有这种洞察力之后,他们便可以随心所欲的运用这项技术去按照自己的意愿完成想做的事情(当然,是做好的事情)。


6、写博客(Blogging)


bloger.png

在你进行你的探险之旅的时候,实时记录下你的成长以及犯下的错误大有裨益。在技术领域,博客是最简单易得并且受欢迎的表达载体。当你准备落笔的时候,你会强迫自己整理思路,并且对积累下来的零散的知识片段进行结构梳理。说不定,通过互联网的分享,你的经历和分享会给别人的成长带来帮助。

如果你想走的更远(比如想像Nettuts+上面的职业作者一样),你也可以制作属于自己的screencasts。总的来说,写博客能够提升你的个人沟通能力,这与你学到的技术同样重要。


7、感知技术动向(Feel the Pulse)


pulse.png

社交网络已经广泛应用于人们的日常交流以及发现新鲜事物。Twitter和Facebook是信息的主要来源,与此同时,有很多的网站提供更专注的资讯,如前面提到过的Quora网站,这上面有很多涉及面很广的一些话题供人们评论。在这上面可以找到很多知名大牛的建议以及观点。

浏览StackOverflow上面的众多话题是一个很有意思的过程,你可以看到他人如何探索某种技术的极限。事实上,在人们利用技术做一些疯狂的甚至是荒诞的事情的时候,技术也随之不断的成熟起来。

因此,如果你想要感受到技术的脉搏,并且想确认它是否值得学下去,在StackOverflow上面试着搜索一些话题,看看这个讨论社区的广度与深度。最值得看的是投票最多以及热门话题。你也可以尝试在GitHub上面进行搜索。


8、 参加聚会以及会议(Meetups and Conferences)


meetup.png

尽管社交网络很棒,但是没有任何事物可以取代面对面的交流。在你住的附近参加一些小组聚会,在这里你可以找到志同道合的伙伴。你可以知道他人在做的一些有趣的项目,同时也可以在他人的帮助下解决一些自己遇到的难题!同样的,技术会议对于分享经验以及增长技术大有帮助!
 
技术会议不仅可以增加你的人脉,同事可以可以扩充你对知识的视野,当然也可以让你的知名度更大,让更多的人认识到你是一个大牛。


9、常逛GitHub


github.png

GitHub是全世界开源项目的标志性建筑物。它是知识以及优质代码的宝库。当你对某项技术自我感觉良好的时候,下一步便是在GitHub中浏览寻找有趣的项目。阅读开源代码,尽可能多的阅读。这样做的话,你能够学到很多东西,比如说:
  • 如何管理规模较大的项目
  • 项目中应用的有趣的库
  • 代码规范以及代码全局设计
  • 文档风格
  • 测试规范
  • 解决诡异问题的方法,以及发现项目中有问题的地方


所有的这些知识都在等待着你去挖掘。有趣的是,这些知识的通过一个简单的标签就可以得到,那就是“好奇心”。


10. 专注学习(Concentrated Learning)


learning.png

如果你担心上述的学习过程太迟缓,那么你也可以尝试一下快速学习模式。你或许听说过“24小时学会某某某”,但是这种方式不是我所推荐的。我认为更合理的是用几周的时间去学习。你可以尝试一下类似"七周学会七种语言"或者"七周学会七种数据库"等学习方法。尽管这些讲的是语言以及数据库方面的学习,但是你在学习其他技术的时候也可以运用这种思维。
 
有一个不太相同的学习风格是“困难学习模式”,这种观点的前提是没有人可以真正掌握一门技术,除非每天都练习。所以,想要成为专家,你就需要不停地进行练习。异曲同工的是你可以查看Katas和Koans,他鼓励的使用你学的知识来解决问题。这些可以让你更好地入门以及接受那些陌生的概念,勇敢走出自己的舒适区,开始学习新知识!
 
学习一门交叉的技能(Learn an Orthogonal Skill)
编程是一项左脑的运动,它利用的是大脑的分析能力,一步一步地寻找解决问题的方法。为了发挥右脑的功能,你可以尝试从事一些创造性的活动,比如说画画、3D建模、折纸、乐器甚至是制作家庭相册等。事实上,编程同样需要大量的创造力。或许你曾经遇到过类似的事情,你在睡梦中找到了问题的解决方案。这是因为你的右脑处理问题的方式很不同,它可以从各种地方获得信息。敏捷开发权威人士Andy Hunt就这个话题写了一本书《程序员的思维修炼》。如果你想点燃你的每一个神经元,建议你开始学习一门交叉的技能。
 


总结


获得新的技能总是令人兴奋。 这是一个新的经验的开始,将塑造你的思维。 但首先,你必须克服你的惯性。 一旦你这样做,你的旅程从网络的每个方面吸收知识开始。 我希望上面介绍的过程为你走过这条漫长的道路提供了一些想法。


作者:Pavan Podila
英文地址:https://code.tutsplus.com/articles/10-tips-for-learning-a-new-technology--net-31631


运维如何写出不耍流氓的Shell脚本

小白菜 发表了文章 • 2 个评论 • 160 次浏览 • 2016-12-02 22:33 • 来自相关话题

声明

大家都是文明人,尤其是做运维的,那叫一个斯文啊。怎么能耍流氓呢?赶紧看看,编写 SHELL 脚本如何能够不耍流氓。

Mysql备份脚本案例

1、不记录日志的 SHELL 脚本就是耍流氓!
我们经常在工作中会遇到一个苦恼的事情,一个 Shell 脚本到底干了什么,什么时候开始执行,什么时候结束的。尤其是数据库备份,我们想知道我们的 MySQL 数据库备份时间。所以给脚本加日志显得尤为重要。那么我们的脚本应该有一个日志的函数,专门用于记录日志:#!/bin/bash

# Shell Env
SHELL_NAME="shell_template.sh"
SHELL_DIR="/opt/shell"
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"
LOCK_FILE="/tmp/${SHELL_NAME}.lock"

#Write Log
shell_log(){
LOG_INFO=$1
echo "$(date "+%Y-%m-%d") $(date "+%H-%M-%S") : ${SHELL_NAME} : ${LOG_INFO}" >> ${SHELL_LOG}
}

shell_log "shell beginning, Write log test"
shell_log "shell success, Write log test"


上面的脚本我编写了一个日志函数shell_log,每次记录日志,我们直接执行shell_log把日志内容当作第一个参数传给它就可以了,赶紧试试。[root@LinuxNode2 shell]# cat shell_template.sh.log
2016-08-27 06-01-19 : shell_template.sh :shell beginning ,write log test
2016-08-27 06-01-19 : shell_template.sh :shell success ,write log test
2、直接就能执行的Shell脚本很容易耍流氓?
一个脚本直接就能执行?难道不是直接就能执行吗?试想,你临时编写了一个特别重要的脚本,干的事情可能有破坏性,一不小心被别人./执行了怎么办呢?而且很多时候我们一个脚本的功能可能有多个,所以我们有必要让用户可以选择进行执行。#!/bin/bash

# Shell Env
SHELL_NAME="shell_template.sh"
SHELL_DIR="/opt/shell"
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"
LOCK_FILE="/tmp/${SHELL_NAME}.lock"

#Write Log 
shell_log(){
    LOG_INFO=$1
    echo "$(date "+%Y-%m-%d") $(date "+%H-%M-%S") : ${SHELL_NAME} : ${LOG_INFO}" >> ${SHELL_LOG}
}

# Shell Usage
shell_usage(){
    echo $"Usage: $0 {backup}"
}


# Backup MySQL All Database with mysqldump or innobackupex
mysql_backup(){
    shell_log "mysql backup start"
    shell_log "mysql backup stop"
}

# Main Function
main(){
    case $1 in
        backup)
            mysql_backup
            ;;
        *)
            shell_usage;
    esac
}

#Exec
main $1


上面的脚本我们编写了shell_usage函数,用来告诉用户,这个脚本的使用方法。同时,我要强调一下,像编写Shell, 我们经常是面向过程的,建议以函数为单位,这样脚本非常的清晰可读。赶紧执行以下看看效果吧。[root@LinuxNode2 shell]# ./shell_template.sh
Usage: ./shell_template.sh {backup}
3、不加锁的Shell脚本就是让别人耍流氓
你编写的脚本能多个人同时执行吗?如果不能,那么如果多个人一起执行会怎么样呢?想想是不是有点冒冷汗。所以,不要给我们的其它小伙伴留下陷阱。不过如果你公司就你一个运维,真的不用怕吗?试想如果是定时任务再运行这个脚本,上一次没有运行完毕,然后到时间又运行了?然后,然后,然后,后果好可怕。#!/bin/bash

# Shell Env
SHELL_NAME="shell_template.sh"
SHELL_DIR="/opt/shell"
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"
LOCK_FILE="/tmp/${SHELL_NAME}.lock"

#Write Log
shell_log(){
LOG_INFO=$1
echo "$(date "+%Y-%m-%d") $(date "+%H-%M-%S") : ${SHELL_NAME} : ${LOG_INFO}" >> ${SHELL_LOG}
}

# Shell Usage
shell_usage(){
echo $"Usage: $0 {backup}"
}

shell_lock(){
touch ${LOCK_FILE}
}

shell_unlock(){
rm -f ${LOCK_FILE}
}

# Backup MySQL All Database with mysqldump or innobackupex
mysql_backup(){
if [ -f "$LOCK_FILE" ];then
shell_log "${SHELL_NAME} is running"
echo "${SHELL_NAME}" is running && exit
fi
shell_log "mysql backup start"
shell_lock
sleep 10
shell_log "mysql backup stop"
shell_unlock
}

# Main Function
main(){
case $1 in
backup)
mysql_backup
;;
*)
shell_usage;
esac
}

#Exec
main $1我为脚本增加了两个函数shell_lock和shell_unlock非常简单,就是创建一个锁文件。然后再执行的时候先判断锁文件是否存在,如果存在说明有其它用户在执行,就退出。如果没有自己创建锁文件,开始执行,执行完毕删除锁文件。
 
好的,现在你可以赶紧再开一个窗口试试能不能执行这个脚本,或者到/tmp目录下看看是否创建了锁文件。请注意:如果已知的异常退出,一定也要删除这个锁文件。
 

做好事必须留名

对于一个功能脚本来说,貌似还少了点什么。对,就是注释!我们要说明白这个脚本是干啥的。或者以后你离职后,别人看到这个脚本之后,我擦,这么牛掰的脚本是谁写的呢?不要怕,写上你的大名。#######################################################
# $Name: shell_template.sh
# $Version: v1.0
# $Function: Backup MySQL Databases Template Script
# $Author: Jason Zhao
# $organization: https://www.unixhot.com/
# $Create Date: 2016-08-27
# $Description: You know what i mean,hehe
#######################################################当然还有很多编写脚本的技巧,没法一一描述,不过如果能掌握上面的三种技巧,立马感觉编写的脚本有点高大上,有木有?

文章作者:赵班长
分享原文:http://dwz.cn/4JDIFv  查看全部
liumang.jpg


声明


大家都是文明人,尤其是做运维的,那叫一个斯文啊。怎么能耍流氓呢?赶紧看看,编写 SHELL 脚本如何能够不耍流氓。


Mysql备份脚本案例


1、不记录日志的 SHELL 脚本就是耍流氓!
我们经常在工作中会遇到一个苦恼的事情,一个 Shell 脚本到底干了什么,什么时候开始执行,什么时候结束的。尤其是数据库备份,我们想知道我们的 MySQL 数据库备份时间。所以给脚本加日志显得尤为重要。那么我们的脚本应该有一个日志的函数,专门用于记录日志:
#!/bin/bash

# Shell Env
SHELL_NAME="shell_template.sh"
SHELL_DIR="/opt/shell"
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"
LOCK_FILE="/tmp/${SHELL_NAME}.lock"

#Write Log
shell_log(){
LOG_INFO=$1
echo "$(date "+%Y-%m-%d") $(date "+%H-%M-%S") : ${SHELL_NAME} : ${LOG_INFO}" >> ${SHELL_LOG}
}

shell_log "shell beginning, Write log test"
shell_log "shell success, Write log test"


上面的脚本我编写了一个日志函数shell_log,每次记录日志,我们直接执行shell_log把日志内容当作第一个参数传给它就可以了,赶紧试试。
[root@LinuxNode2 shell]# cat shell_template.sh.log
2016-08-27 06-01-19 : shell_template.sh :shell beginning ,write log test
2016-08-27 06-01-19 : shell_template.sh :shell success ,write log test

2、直接就能执行的Shell脚本很容易耍流氓?
一个脚本直接就能执行?难道不是直接就能执行吗?试想,你临时编写了一个特别重要的脚本,干的事情可能有破坏性,一不小心被别人./执行了怎么办呢?而且很多时候我们一个脚本的功能可能有多个,所以我们有必要让用户可以选择进行执行。
#!/bin/bash

# Shell Env
SHELL_NAME="shell_template.sh"
SHELL_DIR="/opt/shell"
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"
LOCK_FILE="/tmp/${SHELL_NAME}.lock"

#Write Log 
shell_log(){
    LOG_INFO=$1
    echo "$(date "+%Y-%m-%d") $(date "+%H-%M-%S") : ${SHELL_NAME} : ${LOG_INFO}" >> ${SHELL_LOG}
}

# Shell Usage
shell_usage(){
    echo $"Usage: $0 {backup}"
}


# Backup MySQL All Database with mysqldump or innobackupex
mysql_backup(){
    shell_log "mysql backup start"
    shell_log "mysql backup stop"
}

# Main Function
main(){
    case $1 in
        backup)
            mysql_backup
            ;;
        *)
            shell_usage;
    esac
}

#Exec
main $1


上面的脚本我们编写了shell_usage函数,用来告诉用户,这个脚本的使用方法。同时,我要强调一下,像编写Shell, 我们经常是面向过程的,建议以函数为单位,这样脚本非常的清晰可读。赶紧执行以下看看效果吧。
[root@LinuxNode2 shell]# ./shell_template.sh
Usage: ./shell_template.sh {backup}

3、不加锁的Shell脚本就是让别人耍流氓
你编写的脚本能多个人同时执行吗?如果不能,那么如果多个人一起执行会怎么样呢?想想是不是有点冒冷汗。所以,不要给我们的其它小伙伴留下陷阱。不过如果你公司就你一个运维,真的不用怕吗?试想如果是定时任务再运行这个脚本,上一次没有运行完毕,然后到时间又运行了?然后,然后,然后,后果好可怕。
#!/bin/bash

# Shell Env
SHELL_NAME="shell_template.sh"
SHELL_DIR="/opt/shell"
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"
LOCK_FILE="/tmp/${SHELL_NAME}.lock"

#Write Log
shell_log(){
LOG_INFO=$1
echo "$(date "+%Y-%m-%d") $(date "+%H-%M-%S") : ${SHELL_NAME} : ${LOG_INFO}" >> ${SHELL_LOG}
}

# Shell Usage
shell_usage(){
echo $"Usage: $0 {backup}"
}

shell_lock(){
touch ${LOCK_FILE}
}

shell_unlock(){
rm -f ${LOCK_FILE}
}

# Backup MySQL All Database with mysqldump or innobackupex
mysql_backup(){
if [ -f "$LOCK_FILE" ];then
shell_log "${SHELL_NAME} is running"
echo "${SHELL_NAME}" is running && exit
fi
shell_log "mysql backup start"
shell_lock
sleep 10
shell_log "mysql backup stop"
shell_unlock
}

# Main Function
main(){
case $1 in
backup)
mysql_backup
;;
*)
shell_usage;
esac
}

#Exec
main $1
我为脚本增加了两个函数shell_lock和shell_unlock非常简单,就是创建一个锁文件。然后再执行的时候先判断锁文件是否存在,如果存在说明有其它用户在执行,就退出。如果没有自己创建锁文件,开始执行,执行完毕删除锁文件。
 
好的,现在你可以赶紧再开一个窗口试试能不能执行这个脚本,或者到/tmp目录下看看是否创建了锁文件。请注意:如果已知的异常退出,一定也要删除这个锁文件。
 


做好事必须留名


对于一个功能脚本来说,貌似还少了点什么。对,就是注释!我们要说明白这个脚本是干啥的。或者以后你离职后,别人看到这个脚本之后,我擦,这么牛掰的脚本是谁写的呢?不要怕,写上你的大名。
#######################################################
# $Name: shell_template.sh
# $Version: v1.0
# $Function: Backup MySQL Databases Template Script
# $Author: Jason Zhao
# $organization: https://www.unixhot.com/
# $Create Date: 2016-08-27
# $Description: You know what i mean,hehe
#######################################################
当然还有很多编写脚本的技巧,没法一一描述,不过如果能掌握上面的三种技巧,立马感觉编写的脚本有点高大上,有木有?


文章作者:赵班长
分享原文http://dwz.cn/4JDIFv 


分享个基于sendclound的邮件群发软件 大家提点意见

回复

Nappywu 发起了问题 • 1 人关注 • 0 个回复 • 207 次浏览 • 2016-11-25 15:51 • 来自相关话题

Nginx适配PC和手机后如何做rewrite重定向?

mark 回复了问题 • 2 人关注 • 2 个回复 • 206 次浏览 • 2016-11-24 09:56 • 来自相关话题

Centos7下使用Harpoxy负载均衡Apache

koyo 发表了文章 • 0 个评论 • 199 次浏览 • 2016-11-21 18:41 • 来自相关话题

 

什么是HAProxy

HAProxy是一个免费的,快速和可靠的解决方案提供高可用性、负载均衡,并为TCP代理和基于http的应用程序。特别适合高流量网站和高并发网站。
 

环境说明

操作系统:Centos 7
主机分布:1 haproxy server, 3 client 
IP & Hostname :
192.168.0.50 server.rootworld.in
192.168.0.51 web1.rootworld.in
192.168.0.52 web2.rootworld.in
192.168.0.53 web3.rootworld.in
1、在客户端机器上安装web服务器
 
WEB1
[root@web1 ~]# yum install httpd -y
[root@web1 ~]# systemctl enable httpd.service
[root@web1 ~]# systemctl start httpd.service
WEB2
[root@web2 ~]# yum install httpd -y
[root@web2 ~]# systemctl enable httpd.service
[root@web2 ~]# systemctl start httpd.service
WEB3
[root@web3 ~]# yum install httpd -y
[root@web3 ~]# systemctl enable httpd.service
[root@web3 ~]# systemctl start httpd.service
2、检查您的web服务器工作正常。
 
3、安装HAProxy Server.
[root@server ~]# yum install haproxy openssl-devel -y
 4、配置HAPorxy的主配置文件/etc/haproxy/haproxy.cfg,修改log日志位置
[root@server ~]# vim /etc/haproxy/haproxy.cfg



 
5、配置启动UDP syslog reception 在/etc/rsyslog.conf配置文件中,并且把Haproxy日志单独放到/var/log目录下。
[root@server ~]# vim /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514



 
6、在/etc/rsyslog.d/目录下配置haproxy.conf文件配置单独的log文件
[root@server ~]# vim /etc/rsyslog.d/haproxy.conf
local2.* /var/log/haproxy.log



 
7、重启syslog服务,更新配置
[root@server ~]# service rsyslog restart
8、按照需求配置/etc/haproxy/haproxy.cfg文件
[root@server ~]# vim /etc/haproxy/haproxy.cfg
9、为均衡器在/etc/haproxy/haproxy.cfg配置前端和后端
# Configuration for HTTP site

listen server 192.168.0.50:80
bind *:80
default_backend LBbackend


backend LBbackend
mode http
server web1 192.168.0.51:80 check
server web1 192.168.0.52:80 check
server web1 192.168.0.53:80 check
stats enable
stats hide-version
stats uri /stats
stats realm Haproxy\ Statistics
stats auth admin:redhat
balance roundrobin
option httpchk
option httpclose
option forwardfor
cookie LB insert



 
10、重启HAProxy服务并启用
[root@server ~]# systemctl enable haproxy.service
[root@server ~]# systemctl restart haproxy.service
[root@server ~]# systemctl status haproxy.service



 
11、验证HAProxy负载均衡器
http://192.168.0.50/











 
12、打开HAProxy监控服务面板
http://192.168.0.50/stats 查看全部
ha-proxy_load-balancing.png

 


什么是HAProxy


HAProxy是一个免费的,快速和可靠的解决方案提供高可用性、负载均衡,并为TCP代理和基于http的应用程序。特别适合高流量网站和高并发网站。
 


环境说明


操作系统:Centos 7
主机分布:1 haproxy server, 3 client 
IP & Hostname
192.168.0.50    server.rootworld.in 
192.168.0.51 web1.rootworld.in
192.168.0.52 web2.rootworld.in
192.168.0.53 web3.rootworld.in

1、在客户端机器上安装web服务器
 
WEB1
[root@web1 ~]# yum install httpd -y
[root@web1 ~]# systemctl enable httpd.service
[root@web1 ~]# systemctl start httpd.service

WEB2
[root@web2 ~]# yum install httpd -y
[root@web2 ~]# systemctl enable httpd.service
[root@web2 ~]# systemctl start httpd.service

WEB3
[root@web3 ~]# yum install httpd -y
[root@web3 ~]# systemctl enable httpd.service
[root@web3 ~]# systemctl start httpd.service

2、检查您的web服务器工作正常。
 
3、安装HAProxy Server.
[root@server ~]# yum install haproxy openssl-devel -y 

 4、配置HAPorxy的主配置文件/etc/haproxy/haproxy.cfg,修改log日志位置
[root@server ~]# vim /etc/haproxy/haproxy.cfg 
logconf.PNG

 
5、配置启动UDP syslog reception 在/etc/rsyslog.conf配置文件中,并且把Haproxy日志单独放到/var/log目录下。
[root@server ~]# vim /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514
rsyslogconf.PNG

 
6、在/etc/rsyslog.d/目录下配置haproxy.conf文件配置单独的log文件
[root@server ~]# vim /etc/rsyslog.d/haproxy.conf
local2.* /var/log/haproxy.log
logro.PNG

 
7、重启syslog服务,更新配置
[root@server ~]# service rsyslog restart

8、按照需求配置/etc/haproxy/haproxy.cfg文件
[root@server ~]# vim /etc/haproxy/haproxy.cfg

9、为均衡器在/etc/haproxy/haproxy.cfg配置前端和后端
# Configuration for HTTP site

listen server 192.168.0.50:80
bind *:80
default_backend LBbackend


backend LBbackend
mode http
server web1 192.168.0.51:80 check
server web1 192.168.0.52:80 check
server web1 192.168.0.53:80 check
stats enable
stats hide-version
stats uri /stats
stats realm Haproxy\ Statistics
stats auth admin:redhat
balance roundrobin
option httpchk
option httpclose
option forwardfor
cookie LB insert
haconfig.PNG

 
10、重启HAProxy服务并启用
[root@server ~]# systemctl enable haproxy.service
[root@server ~]# systemctl restart haproxy.service
[root@server ~]# systemctl status haproxy.service
harestart.PNG

 
11、验证HAProxy负载均衡器
http://192.168.0.50/
web1.PNG

web2.PNG

web3.PNG

 
12、打开HAProxy监控服务面板
 http://192.168.0.50/stats
hagui.PNG

如何清理掉iptables的NAT的POSTROUTING规则

采菊篱下 回复了问题 • 2 人关注 • 1 个回复 • 201 次浏览 • 2016-11-11 18:20 • 来自相关话题

Apche和Nginx 状态页面开启设置

Ansible 发表了文章 • 0 个评论 • 242 次浏览 • 2016-11-09 22:30 • 来自相关话题

Apache Server Status​设置

1、确认apache已经加载了status_module 模块
一般yum安装的apache已经在主配置文件/etc/httpd/conf/httpd.conf 里面已经加载了
LoadModule status_module modules/mod_status.so检验如下:
[root@web1 httpd]# apachectl -M |grep -i 'status'
status_module (shared)
Syntax OK如果是编译安装的apache,那你就可能没有安装了,编译安装的,动态添加如下:
# 进入到apache的源码mod_status.c目录
cd /usr/local/httpd-2.2.3/modules/generators
# 执行编译加载程序
/usr/local/apache/bin/apxs -i -a -c mod_status.c
# 重启httpd服务
service httpd restart最后在用httpd -M检查模块是否已经加载,确认模块已经加载没有问题后,在httpd.conf文件增加相应的配置路径 ,引入mod_status.so的配置段:
ExtendedStatus On
<Location /Server-status>
SetHandler Server-status
Order deny,allow
Deny from all
Allow from 192.168.1.100
</Location>
说明:
Deny from表示禁止的访问地址;Allow from表示允许的地址访问;ExtendedStatus On表示的是待会访问的时候能看到详细的请求信息,另外该设置仅能用于全局设置,不能在特定的虚拟主机中打开或关闭。启用扩展状态信息将会导致服务器运行效率降低。
 状态页的配置到这里就结束了,下面我们来访问一下,看看具体状态页有哪些可以利用的价值数据。
输入网址http://IP:PORT/server-status就可以看到apache状态页了。
Apache Server Status for localhost
Server Version: Apache/2.2.3 (Centos)
Server Built: Nov 9 2016 15:18:56

Current Time: Sunday, 11-Nov-2016 17:44:21 Öйú±ê׼ʱ¼ä
Restart Time: Sunday, 11-Nov-2016 17:36:28 Öйú±ê׼ʱ¼ä
Parent Server Generation: 1
Server uptime: 7 minutes 52 seconds
Total accesses: 0 - Total Traffic: 0 kB
0 requests/sec - 0 B/second -
1 requests currently being processed, 63 idle workers
______________________________________________________________W_
................................................................

Scoreboard Key:"_" Waiting for Connection, "S" Starting up, "R" Reading Request,"W" Sending Reply, "K" Keepalive (read), "D" DNS Lookup,"C" Closing connection, "L" Logging, "G" Gracefully finishing,"I" Idle cleanup of worker, "." Open slot with no current process
Srv PID Acc M SS Req Conn Child Slot Client VHost Request
0-1 4140 0/0/0 W 0 287636364 0.0 0.00 0.00 127.0.0.1 192.168.0.100 GET /c-server-status HTTP/1.1

Srv Child Server number - generation
PID OS process ID
Acc Number of accesses this connection / this child / this slot
M Mode of operation
SS Seconds since beginning of most recent request
Req Milliseconds required to process most recent request
Conn Kilobytes transferred this connection
Child Megabytes transferred this child
Slot Total megabytes transferred this slot参数分析:
字段 说明
Server Version Apache 服务器的版本。
Server Built Apache 服务器编译安装的时间。
Current Time 目前的系统时间。
Restart Time Apache 重新启动的时间。
Parent Server Generation Apache 父程序 (parent process) 的世代编号,就是 httpd 接收到 SIGHUP 而重新启动的次数。
Server uptime Apache 启动后到现在经过的时间。
Total accesses 到目前为此 Apache 接收的联机数量及传输的数据量。
CPU Usage 目前 CPU 的使用情形。
_SWSS.... 所有 Apache process 目前的状态。每一个字符表示一个程序,最多可以显示 256 个程序的状态。
Scoreboard Key 上述状态的说明。以下为每一个字符符号所表示的意义:
* _:等待连结中。
* S:启动中。
* R:正在读取要求。
* W:正在送出回应。
* K:处于保持联机的状态。
* D:正在查找DNS。
* C:正在关闭连结。
* L:正在写入记录文件。
* G:进入正常结束程序中。
* I:处理闲置。
* .:尚无此程序。
Srv 本程序与其父程序的世代编号。
PID 本程序的process id。
Acc 分别表示本次联机、本程序所处理的存取次数。
M 该程序目前的状态。
CPU 该程序所耗用的CPU资源。
SS 距离上次处理要求的时间。
Req 最后一次处理要求所耗费的时间,以千分之一秒为单位。
Conn 本次联机所传送的数据量。
Child 由该子程序所传送的数据量。
Slot 由该 Slot 所传送的数据量。
Client 客户端的地址。
VHost 属于哪一个虚拟主机或本主机的IP。
Request 联机所提出的要求信息。

Nginx 状态页配置

如果你的nginx看到了--with-http_sub_module 这个模块,就代表可以启用status,使用nginx -V 就可以看到你的编译参数,如果没有的话,自行重新编译加上--with-http_sub_module 就好。
 
1、添加nginx status配置
在默认主机里面加上location或者你希望能访问到的主机里面
location /nginx_status {
stub_status on;
access_log off;
allow 10.0.1.xx;
allow 139.59.253.28;
deny all;
}

2、重启nginx
# service nginx restart3、查看status页面
# curl http://127.0.0.1/nginx_status
Active connections: 10132
server accepts handled requests
 11302 11302 11409
Reading: 0 Writing: 7 Waiting: 142第1列:
当前与http建立的连接数,包括等待的客户端连接:10132

第2列:
接受的客户端连接总数目:11302
处理的客户端连接总数目:11302
客户端总的请求数目:11409
总共处理了11302个连接 , 成功创建11302次握手, 总共处理了11409个请求

第3列:
reading — 读取客户端的连接数.
writing — 响应数据到客户端的数量
waiting — 开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接.
 
nginx plus (企业用户)官网(http://demo.nginx.com/status.html#)图示如下: 查看全部
ApachNginxStatus.png


Apache Server Status​设置


1、确认apache已经加载了status_module 模块
一般yum安装的apache已经在主配置文件/etc/httpd/conf/httpd.conf 里面已经加载了
LoadModule status_module modules/mod_status.so
检验如下:
[root@web1 httpd]# apachectl -M |grep -i 'status'
status_module (shared)
Syntax OK
如果是编译安装的apache,那你就可能没有安装了,编译安装的,动态添加如下:
# 进入到apache的源码mod_status.c目录
cd /usr/local/httpd-2.2.3/modules/generators
# 执行编译加载程序
/usr/local/apache/bin/apxs -i -a -c mod_status.c
# 重启httpd服务
service httpd restart
最后在用httpd -M检查模块是否已经加载,确认模块已经加载没有问题后,在httpd.conf文件增加相应的配置路径 ,引入mod_status.so的配置段:
ExtendedStatus On
<Location /Server-status>
SetHandler Server-status
Order deny,allow
Deny from all
Allow from 192.168.1.100
</Location>

说明:
  1. Deny from表示禁止的访问地址;
  2. Allow from表示允许的地址访问;
  3. ExtendedStatus On表示的是待会访问的时候能看到详细的请求信息,另外该设置仅能用于全局设置,不能在特定的虚拟主机中打开或关闭。启用扩展状态信息将会导致服务器运行效率降低。

 状态页的配置到这里就结束了,下面我们来访问一下,看看具体状态页有哪些可以利用的价值数据。
输入网址http://IP:PORT/server-status就可以看到apache状态页了。
Apache Server Status for localhost
Server Version: Apache/2.2.3 (Centos)
Server Built: Nov 9 2016 15:18:56

Current Time: Sunday, 11-Nov-2016 17:44:21 Öйú±ê׼ʱ¼ä
Restart Time: Sunday, 11-Nov-2016 17:36:28 Öйú±ê׼ʱ¼ä
Parent Server Generation: 1
Server uptime: 7 minutes 52 seconds
Total accesses: 0 - Total Traffic: 0 kB
0 requests/sec - 0 B/second -
1 requests currently being processed, 63 idle workers
______________________________________________________________W_
................................................................

Scoreboard Key:"_" Waiting for Connection, "S" Starting up, "R" Reading Request,"W" Sending Reply, "K" Keepalive (read), "D" DNS Lookup,"C" Closing connection, "L" Logging, "G" Gracefully finishing,"I" Idle cleanup of worker, "." Open slot with no current process
Srv PID Acc M SS Req Conn Child Slot Client VHost Request
0-1 4140 0/0/0 W 0 287636364 0.0 0.00 0.00 127.0.0.1 192.168.0.100 GET /c-server-status HTTP/1.1

Srv Child Server number - generation
PID OS process ID
Acc Number of accesses this connection / this child / this slot
M Mode of operation
SS Seconds since beginning of most recent request
Req Milliseconds required to process most recent request
Conn Kilobytes transferred this connection
Child Megabytes transferred this child
Slot Total megabytes transferred this slot
参数分析:
字段 说明
Server Version Apache 服务器的版本。
Server Built Apache 服务器编译安装的时间。
Current Time 目前的系统时间。
Restart Time Apache 重新启动的时间。
Parent Server Generation Apache 父程序 (parent process) 的世代编号,就是 httpd 接收到 SIGHUP 而重新启动的次数。
Server uptime Apache 启动后到现在经过的时间。
Total accesses 到目前为此 Apache 接收的联机数量及传输的数据量。
CPU Usage 目前 CPU 的使用情形。
_SWSS.... 所有 Apache process 目前的状态。每一个字符表示一个程序,最多可以显示 256 个程序的状态。
Scoreboard Key 上述状态的说明。以下为每一个字符符号所表示的意义:
* _:等待连结中。
* S:启动中。
* R:正在读取要求。
* W:正在送出回应。
* K:处于保持联机的状态。
* D:正在查找DNS。
* C:正在关闭连结。
* L:正在写入记录文件。
* G:进入正常结束程序中。
* I:处理闲置。
* .:尚无此程序。
Srv 本程序与其父程序的世代编号。
PID 本程序的process id。
Acc 分别表示本次联机、本程序所处理的存取次数。
M 该程序目前的状态。
CPU 该程序所耗用的CPU资源。
SS 距离上次处理要求的时间。
Req 最后一次处理要求所耗费的时间,以千分之一秒为单位。
Conn 本次联机所传送的数据量。
Child 由该子程序所传送的数据量。
Slot 由该 Slot 所传送的数据量。
Client 客户端的地址。
VHost 属于哪一个虚拟主机或本主机的IP。
Request 联机所提出的要求信息。


Nginx 状态页配置


如果你的nginx看到了--with-http_sub_module 这个模块,就代表可以启用status,使用nginx -V 就可以看到你的编译参数,如果没有的话,自行重新编译加上--with-http_sub_module 就好。
 
1、添加nginx status配置
在默认主机里面加上location或者你希望能访问到的主机里面
 location /nginx_status {
stub_status on;
access_log off;
allow 10.0.1.xx;
allow 139.59.253.28;
deny all;
}

2、重启nginx
# service nginx restart
3、查看status页面
# curl http://127.0.0.1/nginx_status
Active connections: 10132
server accepts handled requests
 11302 11302 11409
Reading: 0 Writing: 7 Waiting: 142
第1列:
当前与http建立的连接数,包括等待的客户端连接:10132

第2列:
接受的客户端连接总数目:11302
处理的客户端连接总数目:11302
客户端总的请求数目:11409
总共处理了11302个连接 , 成功创建11302次握手, 总共处理了11409个请求

第3列:
reading — 读取客户端的连接数.
writing — 响应数据到客户端的数量
waiting — 开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接.
 
nginx plus (企业用户)官网(http://demo.nginx.com/status.html#)图示如下:
NginxStatus.png