分类 Linux系统运维 下的文章

Linux chroot使用

什么是 chroot

chroot,即 change root directory (更改 root 目录)。在 linux 系统中,系统默认的目录结构都是以 /,即是以根 (root) 开始的。而在使用 chroot 之后,系统的目录结构将以指定的位置作为 / 位置。
chroot是Linux很早的一项“类docker”技术,也能够将打包好的Kernel镜像通过chroot方式加载到内存里,看上去和普通的kernel没有区别。

如何使用chroot

本文内容主要包括

  • 在宿主机(centos-A)上搭建一个Nginx服务
  • 打包宿主机(centos-A)的OS镜像
  • 在服务机(ubuntu-B)采用chroot方式加载打包好的镜像

- 阅读剩余部分 -

while进行批量ssh操作的问题

现在有这样一个场景,本机到一批机器的ssh key都已经打通,想用while循环到这批机器上执行命令,看下面的shell代码

#!/bin/sh

while read ip
do
    echo "ssh connecting to $ip"
    ssh $ip 'ls'
done < data

执行后会发现,只有一台机器成功ssh,并且执行了命令。很奇怪,再来看一段代码

#!/bin/sh

while read ip
do
    echo "ssh connecting to $ip"
    read
done < data

data文件里面有10个ip,但是实际echo却只有5个echo

ssh connecting to 192.168.1.1
ssh connecting to 192.168.1.2
ssh connecting to 192.168.1.3
ssh connecting to 192.168.1.4
ssh connecting to 192.168.1.5

如何解释以上的现象呢?问题还是while的重定向,在while进行重定向的时候,实际是一次把所有的内容都读取了,然后每次调用read的时候读取到换行或者EOF就结束。第二个例子在while循环里的read会从buffer里读取去,然后程序就没有block住,直接往下走了。

再来解释第一个代码,ssh的时候存在一个“尝试从终端读入的操作”,所以会把buffer后面的内容(第一个ip以外的剩余内容)都读入,这就导致只有一个ssh执行。

ssh利用key登录

ssh登录的时候,如果key不通,则会提示输入密码。

$ ssh -l firefoxbug www.firefoxbug.com
firefoxbug@www.firefoxbug.com's password:

当ssh key不通时候直接如何直接报错?ssh的时候可以指定BatchMode=yes

$ ssh -o BatchMode=yes -l firefoxbug www.firefoxbug.com
Permission denied (publickey,gssapi-with-mic,password).

mysql常用sql语句

### mysql密码初始化

	# /etc/init.d/mysqld stop
	# mysqld_safe --user=mysql --skip-grant-tables --skip-networking &
	# mysql -u root mysql
	mysql> use mysql;
	mysql> UPDATE user SET Password=PASSWORD('hello') where USER='root';
	mysql> FLUSH PRIVILEGES;
	mysql> quit
	# /etc/init.d/mysqld restart
	# mysql -uroot -p
	Enter password: <输入新设的密码newpassword>
	mysql>

- 阅读剩余部分 -

Ganglia配置

ganglia工作原理 ganglia主要有两个角色,gmond(ganglia monitor daemons)和gmetad(ganglia metadata daemons)。gmond是agent,需要在被监控的每台机器上部署,负责采集所在机器的系统状态,信息都是存储在内存里面的。

ganglia-icm ganglia有一种工作模式是组播,顾名思义,以组播的形式发出自己采集到的信息。这时候集群内所有配置成组播的都可以接收数据,也就是说在组播的情形下,集群内的数据都是共享并且一致的(和路由协议很像),gmetad的功能就是从采集集群内所有系统状态信息,在组播的工作模式下,gmetad可以从任一台gmond上采集集群信息。但是组播的局限性就是在于集群要在一个网段内,并且网络负载提高。 ganglia还有一种工作模式是单播,每个agent上的gmond采集好各自的信息,然后通过udp汇总到一台gmond上,然后这台gmond汇总所有来自其他gmond的信息并且联合本机信息也发送给ganglia,单播的模式就是push,gmetad等待从gmond中心节点上过来的信息。 gmetad会把从gmond收集到的信息写入rrdtool里面,rrdtool是一个环形数据库,用来存储集群信息,然后在ganglia-web可以去读取rrdtool,并且绘图呈现给前端。

- 阅读剩余部分 -

Shell单引号和双引号

问题一:

/etc/hosts
192.168.1.1 www.firefoxbug.net

$ awk '{print $1}' /etc/hosts ==>> 打印IP
$ awk "{print $1}" /etc/hosts ==>> 打印整行

这两个打印出来是不一样的,同样是在一个bash下执行。因为$1在双引号里面,是属于弱引用,$1被shell解析了,解析出来是空,可以看看下面的实验。
$ echo $1
$ awk "{print }" /etc/hosts

问题二:

echo '\'' ==>> 等待输入
echo "\"" ==>> 输出"

在单引号的强引用下,所有的转义都已经失效了,所以第一个echo在等待第二个单引号的匹配。

resolv.conf中search作用

reslov.conf中的search主要是用来补全hostname的,有时候域名太长,可以做一个短域名做主机名字,但是DNS解析需要的是FQDN,而在resolv.conf中设置search能进行补全。

vim /etc/hosts
42.120.7.71 www

ping www能通,返回就是42.120.7.71,ping会首先解析hosts
vim /etc/resolv.conf
search firefoxbug.net
nameserver 114.114.114.114

这时候nslookup www
Server:		114.114.114.114
Address:	114.114.114.114#53

Non-authoritative answer:
Name:	www.firefoxbug.net
Address: 42.120.7.71

看到没,search的作用就是补全要访问的短域名

正确的域名解析顺序是:
1. 查找/etc/hosts
2. 根据nameserver查找域名
3. 如果在nameserver查找不到域名就进行search补全,重新走1~2步

shell数组和字典

#!/bin/bash

echo "shell定义字典"
#必须先声明
declare -A dic
dic=([key1]="value1" [key2]="value2" [key3]="value3")

#打印指定key的value
echo ${dic["key1"]}
#打印所有key值
echo ${!dic[*]}
#打印所有value
echo ${dic[*]}

#遍历key值
for key in $(echo ${!dic[*]})
do
        echo "$key : ${dic[$key]}"
done

echo "shell定义数组"

#数组
list=("value1" "value2" "value3")
#打印指定下标
echo ${list[1]}
#打印所有下标
echo ${!list[*]}
#打印数组下标
echo ${list[*]}
#数组增加一个元素
list=("${list[@]}" "value3")

Hadoop HDFS和MapReduce测试

Hadoop的MapReduce应该是属于核心的编程框架,到目前为止我还不是特别懂,只能按照网上的步骤一点实践,就和学一门新语言第一个程序是HelloWorld一样。前文已经介绍了Hadoop的安装,这里就HDFS和MapReduce的测试。

HDFS测试


在HDFS中新建一个文件夹,并把本地文件copy到HDFS新建的文件夹
cd hadoop路径
bin/hadoop dfs -mkdir /tmp/firefoxbug
bin/hadoop dfs -put /opt/run.log /tmp/firefoxbug
bin/hadoop dfs -ls /tmp/firefoxbug

- 阅读剩余部分 -

Elasticsearch集群搭建

之前对于CDN的日志处理模型是从
logstash agent==>>redis==>>logstash index==>>elasticsearch==>>kibana3,对于elasticsearch集群搭建,可以把索引进行分片存储,一个索引可以分成若干个片,分别存储到集群里面,而对于集群里面的负载均衡,副本分配,索引动态均衡(根据节点的增加或者减少)都是elasticsearch自己内部完成的,一有情况就会重新进行分配。
下面先是介绍几个关于elasticsearch的几个名词

- 阅读剩余部分 -

Nginx反向代理和php解析配置

Nginx纯反向代理配置

upstream  firefoxbug{
        ip_hash; 
        server 10.161.171.87:80;
        server 10.160.55.81;
        server 10.160.55.93;
}

server {
    server_name         www.firefoxbug.net firefoxbug.net;
    listen              80;
    gzip                on;


    error_log           /home/logs/www_firefoxbug_net_error.log error;
    access_log          /home/logs/www_firefoxbug_net_access.log;

    ## Bypass For All
    location / {
        proxy_redirect      off;
        proxy_pass          http://firefoxbug; 
        proxy_set_header Host   $host;
        proxy_set_header    X-Real-IP       $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

- 阅读剩余部分 -

OpenCDN流量采集bug修复

OpenCDN节点端Nginx把节点流量信息以下面这种格式输出到管道bandwidth.pipe。

nginx.conf
log_format  bandwidth   '[$time_local] $host $body_bytes_sent $upstream_cache_status';

vhost配置
access_log /usr/local/opencdn/pipe/bandwidth.pipe bandwidth;

在管道的另一段读取流量信息,然后输出到下面的文件里(shell守护)
/usr/local/opencdn/stream/域名/
-| year_month_day_hour_minute
比如
/usr/local/opencdn/stream/www_firefoxbug_net
2013_Sep_30_12_10

管控端采集流量就是通过守护,以http://%s:%s/ocdn/stream?token=%s&domain=%s来抓取流量,处理后导入数据库。

之前OpenCDN产生一个小需求,使用CDN加速的小伙伴们添加了一个域名比如是aaa.com,但是他还加了别名,xxx.aaa.com(可以是二级域名)。OpenCDN节点端会在Nginx的vhost配置server_name加一个aliasname。但是小伙伴访问都是用这个aliasname访问的。而根据上面的逻辑管控端就没有办法采集到aliasname的流量。
怎么办?在节点端加对域名的流量路径加个软链接就可以,那么aliasname访问的流量也会记录到原站点的流量下。

中间还遇到一个小问题

$ mkdir test1
$ ln -s test1 test2
$ [ -L test2 ] ; echo $?
0
$ [ -L test2/ ] ; echo $?
1

为什么测试目录链接文件加/和没加/有区别呢?得@smallfish指点,大概明白了。软链接是新建一个inode节点的,这个inode节点对应的block记录的是原目录的路径,从软链接到原目录路径其实是比正常访问多一层的。我想linux的设计就是加/来区别吧,没加/那么就是读取普通的目录文件一样,加了/就是change到原路径里去了。

Nginx和Apache区别

转载请注明出处:http://www.firefoxbug.com/?p=1932

Nginx的高并发得益于其采用了epoll模型,与传统的服务器程序架构不同,epoll是linux内核2.6以后才出现的。下面通过比较Apache和Nginx工作原理来比较。

传统Apache都是多进程或者多线程来工作,假设是多进程工作(prefork),apache会先生成几个进程,类似进程池的工作原理,只不过这里的进程池会随着请求数目的增加而增加。对于每一个连接,apache都是在一个进程内处理完毕。具体是 recv(),以及根据 URI 去进行磁盘I/O来寻找文件,还有 send()都是阻塞的。其实说白了都是 apche 对于套接字的I/O,读或者写,但是读或者写都是阻塞的,阻塞意味着进程就得挂起进入sleep状态,那么一旦连接数很多,Apache必然要生成更多的进程来响应请求,一旦进程多了,CPU对于进程的切换就频繁了,很耗资源和时间,所以就导致apache性能下了,说白了就是处理不过来这么多进程了。其实仔细想想,如果对于进程每个请求都没有阻塞,那么肯定效率会提高很多。

- 阅读剩余部分 -

Python Mysql 连接断开错误代码2006

我本地用Python连接Mysql,可能是由于写得太多,导致Mysql出现2006错误,出现MySQL server has gone away,应该就是Mysql断开的连接。后来发现只要加Mysql的ping功能就行。

class MySQLHelper:
	def __init__(self,host,user,password,db_name,charset="utf8"):
		self.host = host
		self.user = user
		self.password = password
		self.db_name = db_name
		self.charset = charset
		self.conn = MySQLdb.connect(host=self.host,user=self.user,passwd=self.password,db=self.db_name, charset=self.charset,cursorclass=MySQLdb.cursors.DictCursor)
                self.conn.ping(True)
	def insert_sql_cmd(self,sql_cmd):
		self.cur = self.conn.cursor()
		try :
			self.cur.execute(sql_cmd)
			self.conn.commit()
			self.cur.close()
			return True
		except Exception, e:
			print "[MYSQL ERROR] : %s"%sql_cmd
			print "%s"%(str(e))
			self.cur.close()
			return False

	def update_sql_cmd(self,sql_cmd):
		self.cur = self.conn.cursor()
		try :
			self.cur.execute(sql_cmd)
			self.conn.commit()
			self.cur.close()
			return True
		except Exception, e:
			print "[MYSQL ERROR] : %s"%sql_cmd
			print "%s"%(str(e))
			self.cur.close()
			return False

	def query_sql_cmd(self,sql_cmd):
		try :
			self.cur = self.conn.cursor()
			self.cur.execute(sql_cmd)
			res = self.cur.fetchall()
			self.cur.close()
			return res
		except Exception, e:
			print "[MYSQL ERROR] : %s"%sql_cmd
			print "%s"%(str(e))
			self.cur.close()
			return False

	def close(self):
		self.conn.close()

LVS概述

refer:http://snmlab.cs.nchu.edu.tw/CloudLab/CTSP/Lab7.html

今早X哥告诉我说他需要传10G/S的数据,我顿时就瞎了,他叫我给出下LVS的描述,我总结了下。

NAT


网络环境:LVS调度器两个网卡,一个公网IP,一个内网IP,限制于一个LAN里面。
原理:数据包到最前面的调度器(公网IP),转发到内网的机器群(内网IP),内部服务器相应完成后转发回调度器,调度器回到客户端。
总结:数据包都流经四层,调度器会是瓶颈,进出流量都经过调度器。

- 阅读剩余部分 -

Python socket tcp

Server

#!/usr/bin/python

'''
	tcp socket server
'''

import sys
import socket

HOST = ''  
PORT = 9243
DATA_BUFFER = 4096

# create a TCP socket
try :
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
	print 'Socket created'
except socket.error, msg :
	print 'Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
	sys.exit()

# Bind socket to local host and port
try:
	s.bind((HOST, PORT))
except socket.error , msg:
	print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
	sys.exit()

s.listen(5)			# allow 5 simultaneous

while True:
	# wait for next client to connect
	connection, address = s.accept()		# connection is a new socket
	while True:
		data = connection.recv(DATA_BUFFER) # receive up to 1K bytes
		if data:
			print data
		else:
			break
	connection.close()						# close socket

Client


#!/usr/bin/python

'''
	tcp socket client
'''

import socket  
  
address = ('223.4.238.138', 9243) 
# create a TCP socket
try :
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
	print 'Socket created'
except socket.error, msg :
	print 'Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
	sys.exit()	

# create a TCP socket
try :
	s.connect(address)
	print 'Connect successfully'
except socket.error, msg :
	print 'Failed to Connect . Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
	sys.exit()

s.send('hello world')  

s.close()  

Python 发送HEAD包

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import urllib2
import socket

def send(url):
	request = urllib2.Request(url,)
	try:
		request.get_method = lambda: 'HEAD'
		response = urllib2.urlopen(request)
		msg = response.msg
		print "message : %s"%msg
		headers = response.headers
		print "\n\n%s"%headers
		data = response.read()
		print "data\n%s"%data
	except urllib2.HTTPError,e:
		code = e.code
		print code
	except Exception,e:
		print e

socket.setdefaulttimeout(2)
send("http://74.91.23.207/")

Head方法要求响应与GET请求一样,但是没有响应体(response body)。如果我们只对关于网页或资源的
信息感兴趣,而不想检索资源本身的全部内容,可以使用HEAD命令。HEAD的使用方法与GET相同,只是不返
回Web页的正文内容。