firefoxbug 发布的文章

Hadoop HDFS 心跳时间

datenode以固定周期向namenode发送心跳,namenode如果在一段时间内没有收到心跳,就会标记datenode为宕机。 此段时间的计算公式是:

timeout  = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval

默认 heartbeat.recheck.interval 是5分钟,dfs.heartbeat.interval是3秒,所以DN挂了后,NN要确定DN为DEAR需要10min30s,也就是630S自动标识为dead。

<property>
<name>dfs.heartbeat.interval</name>
<value>3</value> 
<description>Determines datanode heartbeat interval in seconds.</description> 
</property>

<property>
<name>dfs.heartbeat.recheck.interval</name>
<value>20000</value>
<description>Determines when machines are marked dead 单位:毫秒!!!</description> 
</property>

- 阅读剩余部分 -

Hadoop Volume 配置

volume的配置就是在 hdfs-site.xml 下

<property>
    <name>dfs.datanode.data.dir</name>
    <value>/sda1,/sda/disk1</value>
</property>

我今早是新加了一个volume,就是(所有机器都是)

drwx------ 4 hadoop hadoop  4096 Apr  2 13:33 /sda1
drwx------ 4 admin admin  4096 Apr  2 13:33 /sda/disk1

- 阅读剩余部分 -

python解析配置文件

项目中经常需要解析配置文件,最简单的就是有很多个section,然后每个section里面都是很多option,每一项option的组成都是key=value,怎么解析这个配置文件?python有内置的库可以解决,比如下面是一个配置文件的demo

#WatchDir 配置文件
#配置的value的时候除了第一项就先别加单引号或者双引号了

[monitor]
#监控路径
WatchPath='/var/log/'

#数据写到本地磁盘cache时间间隔,单位:S
Interval=10


#是否以守护进程方式运行
Daemon=False

#mysql配置
[mysql]
mysql_host = 127.0.0.1
mysql_username = root
mysql_password = 12345678
mysql_port = 3306
mysql_dbname = db_a
mysql_table = tb_b

- 阅读剩余部分 -

Hadoop slaves文件解析

slaves文件里面记录的是集群里所有DataNode的主机名,到底它是怎么作用的呢?slaves文件只作用在NameNode上面,比如我在slaves里面配置了

host1
host2
host3 

三台机器,这时候如果突然间新增了一台机器,比如是host4,会发现在NN上host4也自动加入到集群里面了,HDFS的磁盘容量上来了,这下子不是出问题了?假如host4不是集群的机器,是别人的机器,然后配置的时候指向了NN,这时候NN没有做判断岂不是把数据也有可能写到host4上面?这对数据安全性影响很大。所以可以在hdfs-site.xml里面加限制。

<property>
    <name>dfs.hosts</name>
    <value>/home/hadoop-2.0.0-cdh4.5.0/etc/hadoop/slaves</value>
</property> 

这相当于是一份对于DN的白名单,只有在白名单里面的主机才能被NN识别。配置了这个之后,就能排除阿猫阿狗的DN了。其实slaves文件里不一定要写主机名,最终的都是通过IP来判断,完全可以写一个IP就行。 我还尝试了配置了上面的dfs.hosts项之后,然后在slaves删除一个节点,然后 $ hadoop-daemon.sh stop namenode $ hadoop-daemon.sh start namenode 这时候NN就拒绝了那个被删除了的DN数据,而NN会自动把DN上丢失的数据重新备份,通过其他的备份来copy,这里是很智能的过程。

Ganglia监控Hadoop

$ vim hadoop-metrics2.properties

#*.sink.file.class=org.apache.hadoop.metrics2.sink.FileSink
# default sampling period, in seconds
#*.period=10

*.sink.ganglia.class=org.apache.hadoop.metrics2.sink.ganglia.GangliaSink31  
*.sink.ganglia.period=10  
  
*.sink.ganglia.slope=jvm.metrics.gcCount=zero,jvm.metrics.memHeapUsedM=both  
*.sink.ganglia.dmax=jvm.metrics.threadsBlocked=70,jvm.metrics.memHeapUsedM=40  
  
namenode.sink.ganglia.servers=hadoop_master_ip:8649  
resourcemanager.sink.ganglia.servers=hadoop_master_ip:8649  
  
datanode.sink.ganglia.servers=hadoop_master_ip:8649    
nodemanager.sink.ganglia.servers=hadoop_master_ip:8649    

maptask.sink.ganglia.servers=hadoop_master_ip:8649    
reducetask.sink.ganglia.servers=hadoop_master_ip:8649 

然后分发配置文件,接可以ganglia监控HDFS等基本情况
ganglia2hadoop

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,并且绘图呈现给前端。

- 阅读剩余部分 -

Ganglia安装过程中几个问题

在ganglia安装好,呈现web的过程中。

问题一

RRDs directory '/var/lib/ganglia/rrds' is not readable

解决方案: 1.chown nobody:nobody -R RRDs /var/lib/ganglia 2.chmod 777 -R /var/lib/ganglia 3.vim /etc/php.ini safe_mode = Off 依次执行上面的,就能解决。

问题二 ganglia安装后好,jss无法加载,导致图片都没有呈现。

gangliabug 原因:ganglia web使用graph.php来生成rrd图,调用的函数为passthru,而默认的php.ini限制了passthru的执行。 解决方案: vim /etc/php.ini disable_functions = exec,passthru,popen,proc_open 把这个函数去了就行。

Hadoop invalid shuffle port number

Hadoop2,yarn-site.xml 配置过程中,yarn.nodemanager.aux-services这一项值配置的时候配得不对,结果每次在reducer的时候就挂了,提示错误都是"ContainerLauncherImpl"失败,提示:

* java.lang.IllegalStateException: Invalid shuffle port number -1 returned fo
<property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
</property>
<property>
    <name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
    <value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>

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")

pssh使用

pssh安装

wget http://parallel-ssh.googlecode.com/files/pssh-2.3.1.tar.gz
tar zxvf pssh-2.3.1.tar.gz 
cd pssh-2.3.1/ 
python setup.py install 

远程命令执行

pssh -A -i -H 'username@ip:port' 'execute_cmd'
其中username默认是root,port默认是22,可以省略

$ pssh -A -i -H 'root@117.135.139.195:22' 'ls /' 参数 -A:ssh手动输入登入密码,不然没法登入,除非是免登入机制 参数 -i:把标准输出和错误输出都返回

- 阅读剩余部分 -

Linux read函数深入

之前Linux read函数浅析-高速缓存说到Linux下读写文件都是通过高速缓存区实现的,应用程序要和底层的设备打交道,首先是通过高速缓存区,要是所要读的数据不存在,高速缓存区会帮应用程序代理去“拿”数据,高速缓存区的处理程序会向设备的驱动程序发出读请求,等待数据返回,这里就说说高速缓存区怎么实现和底层设备驱动函数交互。

- 阅读剩余部分 -

Linux read函数浅析-高速缓存

最近一直在看Linux下read()函数的实现,发现确实是复杂,几次想写篇博客来把read()函数讲清楚,可是写着写着就断了思绪,有些地方不是很懂,有些概念太过于模糊。今天还是决定写下,只能大概讲讲read()函数。

高速缓存


首先引入的就是高速缓存,什么是高速缓存?众所周知,磁盘的I/O和内存的I/O两者访问是相差几个数量级的,A进程访问了X文件,Linux为了加速A进程或者其他进程再次访问X文件的时候不再千里迢迢到去磁盘上寻找,于是就设计了高速缓存,把A进程访问过的X文件缓存在内存里面。这么说高速缓存就是内存了?对,高速缓存就是属于物理内存的一部分!Linux设计思想就是尽可能地发挥物理内存的使用。

Linux读写机制


好,我们看看高速缓存怎么发挥作用,A进程要去磁盘上访问磁盘上的X文件,首先会在高速缓存区里面找,找到了就直接返回对应的内容,找不到呢?没办法,得再去磁盘上找,通过设备驱动程序把相应的文件内容读取到高速缓存里,然后A进程从高速缓存里得到数据,返回给用户空间。那么某个进程再去请求X文件的时候就会直接从高速缓存区里返回了,效率就会大大提高。
那么对于写文件呢?A进程要写磁盘文件,那么先把数据写到高速缓存区里面,并不是写了小部分数据就会立马同步到磁盘上的。内核会有一组回写线程,一段时间去把高速缓存区上“脏”的逻辑块写到磁盘上,这里“脏”的意思和虚拟内存页差不多,最简单定义就是内存中某个块和磁盘上对应块不一样就回写(不是页)。

高速缓存实现


对于块设备而言,比如磁盘,最小的访问单位都是扇区,一般一个扇区是512字节,Linux抽象了一层块的概念,平时说的I/O块和逻辑块都是这个意思,一个块必然是扇区的整数倍,一般都是1K。在内核0.11里面,高速缓存区都是这些块组成的,统一用buffer_head进行描述,所有的块都组成双向链表。每个设备号+逻辑块号还通过指定的HASH算法构成自己的链表,访问X文件会在inode节点里提供设备号,接下来需要的是逻辑块号的获取是通过提供的文件偏移地址算出来的,就可以在对应的设备号+逻辑块号HASH队列里找到相应缓存块,找不到就向底层的驱动程序发出读磁盘请求。块的概念都是面向设备的,也就是驱动程序和设备打交道的最基本单位都是块。而对于应用程序和高速缓存区打交道都是基于页的概念,页是在块纸上又一层抽象,一个页一般是4K,也就是4个块。下面这张图可以详细说明这些概念之间的关系。

buffer

总结


进程要和块设备打交道都是需要经过高速缓存的(也有特殊情况)进程发起读请求,首先会有缓存区页面管理程序接收,它会根据逻辑块号和设备号去高速缓存区找请求的buffer,找到就直接返回;如果找不到,缓存区页面管理程序会向底层的驱动程序发出读指令,等其放回后缓存到高速缓存里,然后返回给应用进程。至于高速缓存区的维护则是由内核维护,淘汰算法也是LRU。

Linux虚拟内存概述

为什么需要虚拟内存?


程序是一系列代码段,数据段的集合,而程序要运行必须是加载到内存里的,但是物理内存就那么大,如何能保证很多个程序都装载进去呢?这里就引进了虚拟内存的概念,虚拟内存基本思想就是,给每个程序都分配一个4G的虚拟的内存,但这部分内存占用的不是物理内存,而是磁盘空间,这部分叫做虚拟存储器,就是安装Linux系统时候的SWAP空间。而对应的物理内存就是物理存储器。
有没有觉得整个过程像开了“空头支票”一样?程序要跑起来,操作系统许诺它给你4G的空间,但却是不能用的,那真要执行的时候怎么办呢?操作系统会把磁盘上的程序代码数据“移”到内存里,把不需要的还会“移”出去到磁盘上,这样看上去就好像可以跑很多进程了。

- 阅读剩余部分 -

Linux系统调用

最近重新开始看操作系统,看得我云里雾里,经典的操作系统书又很难,看不大懂。学校的操作系统课,说实在的,真的好难和自己真正编程结合起来,里面的概念很多,而且很多都是很老的,历史总是这么蛋疼。没办法,只能硬着头皮去看。这次先讲讲系统调用,因为没看过里面的具体源码,但是尽可能让文章偏向实际编程中的应用。

什么叫系统调用


计算机有很多的硬件,比如键盘,鼠标,网卡,磁盘,声卡这些硬件都是我们实际可以触碰到的,但是对于用户应用程序而言是没办法直接操作这些设备的。为什么呢?一是硬件涉及到很多电路实现,让用户自己编写程序去操作是很困难和复杂的。二是编程的人直接操作硬件会有很大的安全隐患,因为这些资源都是很多程序共享的,万一我们写的程序能够直接操作硬件,安全性就不能保障了。所以所有这些设备的上面抽象了一层驱动程序,这些驱动程序会实现很多硬件相关操作,也就是说每个硬件发布商都得提供各自的硬件的驱动程序用于操作硬件。那么应用程序怎么去调用这些驱动程序呢?答案就是通过操作系统的系统调用,我们告诉操作系统我们要对某个硬件做某个操作,操作系统来帮你完成,然后把得到的结果返回给我们。

- 阅读剩余部分 -