2014年4月

zookeeper应用场景之分布式锁

zookeeper应用场景有关于分布式集群配置文件同步问题的描述,设想一下如果有100台机器同时对同一台机器上某个文件进行修改,如何才能保证文本不会被写乱,这就是最简单的分布式锁,本文介绍利用zk实现分布式锁。下面是写锁的实现步骤

分布式写锁

create一个PERSISTENT类型的znode,/Locks/write_lock

  1. 客户端创建SEQUENCE|EPHEMERAL类型的znode,名字是lockid开头,创建的znode是/Locks/write_lock/lockid0000000001
  2. 调用getChildren()不要设置Watcher获取/Locks/write_lock下的znode列表
  3. 判断自己步骤2创建znode是不是znode列表中最小的一个,如果是就代表获得了锁,如果不是往下走
  4. 调用exists()判断步骤2自己创建的节点编号小1的znode节点(也就是获取的znode节点列表中最小的znode),并且设置Watcher,如果exists()返回false,执行步骤3
  5. 如果exists()返回true,那么等待zk通知,从而在回掉函数里返回执行步骤3

- 阅读剩余部分 -

zookeeper应用场景之配置文件同步

zookeeper应用场景有关于分布式集群配置文件同步问题的描述,本文介绍如何把zk应用到配置文件分发的场景。

假设有三个角色

  • trigger:发布最新的配置文件数据,发送指令和数据给zk_agent,实现是下面的trigger.py
  • zk_agent:接收来自trigger.py触发的指令和数据,并且把数据更新到zk service上,从而触发zk_app来获取最新的配置数据,实现是下面的zk_agent.py
  • zk_app:部署在每台worker上的注册监听zk中配置文件所在znode的变化,从而获取最新的配置文件,应用到worker中,实现是下面的zk_app.py

- 阅读剩余部分 -

zookeeper中Watcher和Notifications

zookeeper中Watcher和Notifications

传统polling远程service服务

传统远程的service往往是这样服务的,服务提供者在远程service注册自己的服务,服务调用者不断去远程service轮询看看是否服务提供者有没有提供服务或者更新服务。所以有弊端,就是延时比较高,而且因为很多不必要的空轮询带来高的负载和网络损耗,这种模式到zk里面就应该是这样。

- 阅读剩余部分 -

zookeeper集群安装配置

之前介绍了zookeeper基本原理,这篇文章讲zk集群安装

zk service节点列表

192.168.1.1
192.168.1.2
192.168.1.3

zk安装包下载


[192.168.1.1]$ wget http://archive.apache.org/dist/hadoop/zookeeper/zookeeper-3.3.1/zookeeper-3.3.1.tar.gz
sudo tar -zxvf /home/wanghua.wh/zookeeper-3.3.1.tar.gz -C /usr/local/
[192.168.1.1]$ sudo mkdir /usr/local/zookeeper
[192.168.1.1]$ sudo mv /usr/local/zookeeper-3.3.1/ /usr/local/zookeeper
[192.168.1.1]$ cd /usr/local/zookeeper/conf
[192.168.1.1]$ cp zoo_sample.cfg zoo.cfg

- 阅读剩余部分 -

zookeeper基本原理

zookeeper介绍

前文介绍了zookeeper的应用场景,本文介绍下zookeeper工作原理。

zk service网络结构

zookeeper的工作集群可以简单分成两类,一个是Leader,唯一一个,其余的都是follower,如何确定Leader是通过内部选举确定的。

image

Leader和各个follower是互相通信的,对于zk系统的数据都是保存在内存里面的,同样也会备份一份在磁盘上。对于每个zk节点而言,可以看做每个zk节点的命名空间是一样的,也就是有同样的数据(下面的树结构)

  • 如果Leader挂了,zk集群会重新选举,在毫秒级别就会重新选举出一个Leaer
  • 集群中除非有一半以上的zk节点挂了,zk service才不可用

- 阅读剩余部分 -

zookeeper应用场景

分布式系统的运行是很复杂的,因为涉及到了网络通信还有节点失效等不可控的情况。下面介绍在最传统的master-workers模型,主要可以会遇到什么问题,传统方法是怎么解决以及怎么用zookeeper解决。

Master节点管理

集群当中最重要的是Master,所以一般都会设置一台Master的Backup。

Backup会定期向Master获取Meta信息并且检测Master的存活性,一旦Master挂了,Backup立马启动,接替Master的工作自己成为Master,分布式的情况多种多样,因为涉及到了网络通信的抖动,针对下面的情况:

  1. Backup检测Master存活性传统的就是定期发包,一旦一定时间段内没有收到响应就判定Master Down了,于是Backup就启动,如果Master其实是没有down,Backup收不到响应或者收到响应延迟的原因是因为网络阻塞的问题呢?Backup也启动了,这时候集群里就有了两个Master,很有可能部分workers汇报给Master,另一部分workers汇报给后来启动的Backup,这下子服务就全乱了。
  2. Backup是定期同步Master中的meta信息,所以总是滞后的,一旦Master挂了,Backup的信息必然是老的,很有可能会影响集群运行状态。

- 阅读剩余部分 -

python中的@装饰器

先看一段代码

#!/usr/bin/python

def test(func):
    func()

@test
def fun():
    print "call fun"

上面的代码没有main()调用或者直接的函数调用,结果还是会输出

call fun

@修饰符有点像函数指针,python解释器发现执行的时候如果碰到@修饰的函数,首先就解析它,找到它对应的函数进行调用,并且会把@修饰下面一行的函数作为一个函数指针传入它对应的函数。有点绕口,这里说的“它对应的函数”就是名字是一样的。下面说下之前代码的解析流程

  1. python解释器发现@test,就去调用test函数
  2. test函数调用预先要指定一个参数,传入的就是@test下面修饰的函数,也就是fun()
  3. test()函数执行,调用fun(),fun()打印“call fun”

再看一段代码

#!/usr/bin/python

def test(func):
    func()
    print "call test over"

def main():
    @test
    def fun():
        print "call fun"
#main()

这样调用的话就不会调用test,只有当main函数调用的时候才会进入到main函数,然后调用test。
来看看正规的用法


def t(func):
    print "in t"
    def _a():
        print "in a"
        return func()
    print "call t over"
    return _a

@t
def hello():
    print "hello"

hello()

输出

in t
call t over
in a
hello

运行流程

  1. 执行hello(),发现有@修饰符,把hello()作为函数指针传入@修饰的函数t()
  2. t()函数执行到return _a,这时候会去调用_a()
  3. _a()函数执行func(),这里的func()就是之前传入了hello()
  4. 执行hello()函数的打印

应用场景:测试函数运行时间

from time import clock

def get_run_time(func):
    def _a():
        start = clock()
        func()
        end = clock()
        print end-start
    return _a

@get_run_time
def hello():
    print "hello\n"

hello()

注意一定要写成这样闭包的形式

### 如何传参数

def t(func):
    print "in t"
    def _a(* args, ** kwds):
        print "in a"
        return func(* args, ** kwds)
    print "call t over"
    return _a

@t
def hello(v):
    print "hello", v

hello("world")

更多用法

[http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html](http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html)

mac下ppk转换成pem

因为默认的putty是ppk认证的,而通过终端ssh的时候需要pem,所以先要mac下通过port安装putty的工具。

$ port install putty
$ puttygen privatekey.ppk -O private-openssh -o privatekey.pem
$ ssh username@ip -i privatekey.pem

mac 安装port和brew

安装homebrew


curl -L http://github.com/mxcl/homebrew/tarball/master | tar xz --strip 1 -C /usr/local

安装MacPort


https://distfiles.macports.org/MacPorts/MacPorts-2.1.2-10.8-MountainLion.pkg 

然后将/opt/local/bin和/opt/local/sbin添加到$PATH搜索路径中 
编辑/etc/profile文件中,加上 
export PATH=/opt/local/bin:$PATH 
export PATH=/opt/local/sbin:$PATH 

Hadoop HDFS Quota配置

hadoop HDFS有以下两种Quota

Name Quotas : 限制某个目录下的文件数量
Space Quotas : 设置某个目录的空间大小

$hadoop fs -count -q /user/hadoop
QUOTA       REMAINING_QUOTA  SPACE_QUOTA  REMAINING_SPACE_QUOTA  DIR_COUNT   FILE_COUNT CONTENT_SIZE FILE_NAME
none        inf               none        inf           		  2            1          180         /user/hadoop

- 阅读剩余部分 -

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

- 阅读剩余部分 -