elasticsearch的索引如何才能做到平滑切换

空心菜 回复了问题 2 人关注 1 个回复 4993 次浏览 2015-09-18 23:22 来自相关话题

elasticsearch配置文件详解

OpenSkill 发表了文章 0 个评论 3363 次浏览 2015-09-18 11:26 来自相关话题

elasticsearch的config文件夹里面有两个配置文件:elasticsearch.yml和logging.yml,第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来记录日志的,所以logging.yml里的设置按普通log4 ...查看全部
es1.jpg
elasticsearch的config文件夹里面有两个配置文件:elasticsearch.yml和logging.yml,第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来记录日志的,所以logging.yml里的设置按普通log4j配置文件来设置就行了。
下面主要讲解下elasticsearch.yml这个文件中可配置的东西:

cluster.name: elasticsearch
配置es的集群名称,默认是elasticsearch,es会自动发现在同一网段下的es,如果在同一网段下有多个集群,就可以用这个属性来区分不同的集群。

node.name: "Franz Kafka"
节点名,默认随机指定一个name列表中名字,该列表在es的jar包中config文件夹里name.txt文件中,其中有很多作者添加的有趣名字。

node.master: true
指定该节点是否有资格被选举成为node,默认是true,es是默认集群中的第一台机器为master,如果这台机挂了就会重新选举master。

node.data: true
指定该节点是否存储索引数据,默认为true。

index.number_of_shards: 5
设置默认索引分片个数,默认为5片。

index.number_of_replicas: 1
设置默认索引副本个数,默认为1个副本。

path.conf: /path/to/conf
设置配置文件的存储路径,默认是es根目录下的config文件夹。

path.data: /path/to/data
设置索引数据的存储路径,默认是es根目录下的data文件夹,可以设置多个存储路径,用逗号隔开,例:
path.data: /path/to/data1,/path/to/data2

path.work: /path/to/work
设置临时文件的存储路径,默认是es根目录下的work文件夹。

path.logs: /path/to/logs
设置日志文件的存储路径,默认是es根目录下的logs文件夹

path.plugins: /path/to/plugins
设置插件的存放路径,默认是es根目录下的plugins文件夹

bootstrap.mlockall: true
设置为true来锁住内存。因为当jvm开始swapping时es的效率会降低,所以要保证它不swap,可以把ES_MIN_MEM和ES_MAX_MEM两个环境变量设置成同一个值,并且保证机器有足够的内存分配给es。同时也要允许elasticsearch的进程可以锁住内存,linux下可以通过`ulimit -l unlimited`命令。

network.bind_host: 192.168.0.1
设置绑定的ip地址,可以是ipv4或ipv6的,默认为0.0.0.0。


network.publish_host: 192.168.0.1
设置其它节点和该节点交互的ip地址,如果不设置它会自动判断,值必须是个真实的ip地址。

network.host: 192.168.0.1
这个参数是用来同时设置bind_host和publish_host上面两个参数。

transport.tcp.port: 9300
设置节点间交互的tcp端口,默认是9300。

transport.tcp.compress: true
设置是否压缩tcp传输时的数据,默认为false,不压缩。

http.port: 9200
设置对外服务的http端口,默认为9200。

http.max_content_length: 100mb
设置内容的最大容量,默认100mb

http.enabled: false
是否使用http协议对外提供服务,默认为true,开启。

gateway.type: local
gateway的类型,默认为local即为本地文件系统,可以设置为本地文件系统,分布式文件系统,hadoop的HDFS,和amazon的s3服务器,其它文件系统的设置方法下次再详细说。

gateway.recover_after_nodes: 1
设置集群中N个节点启动时进行数据恢复,默认为1。

gateway.recover_after_time: 5m
设置初始化数据恢复进程的超时时间,默认是5分钟。

gateway.expected_nodes: 2
设置这个集群中节点的数量,默认为2,一旦这N个节点启动,就会立即进行数据恢复。

cluster.routing.allocation.node_initial_primaries_recoveries: 4
初始化数据恢复时,并发恢复线程的个数,默认为4。

cluster.routing.allocation.node_concurrent_recoveries: 2
添加删除节点或负载均衡时并发恢复线程的个数,默认为4。

indices.recovery.max_size_per_sec: 0
设置数据恢复时限制的带宽,如入100mb,默认为0,即无限制。

indices.recovery.concurrent_streams: 5
设置这个参数来限制从其它分片恢复数据时最大同时打开并发流的个数,默认为5。

discovery.zen.minimum_master_nodes: 1
设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)

discovery.zen.ping.timeout: 3s
设置集群中自动发现其它节点时ping连接超时时间,默认为3秒,对于比较差的网络环境可以高点的值来防止自动发现时出错。

discovery.zen.ping.multicast.enabled: false
设置是否打开多播发现节点,默认是true。

discovery.zen.ping.unicast.hosts: ["host1", "host2:port", "host3[portX-portY]"]
设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。

下面是一些查询时的慢日志参数设置
index.search.slowlog.level: TRACE
index.search.slowlog.threshold.query.warn: 10s
index.search.slowlog.threshold.query.info: 5s
index.search.slowlog.threshold.query.debug: 2s
index.search.slowlog.threshold.query.trace: 500ms

index.search.slowlog.threshold.fetch.warn: 1s
index.search.slowlog.threshold.fetch.info: 800ms
index.search.slowlog.threshold.fetch.debug:500ms
index.search.slowlog.threshold.fetch.trace: 200ms

docker run bash failed

空心菜 回复了问题 2 人关注 1 个回复 5496 次浏览 2015-09-17 00:18 来自相关话题

openstack nova集成docker

Geek小A 发表了文章 0 个评论 4628 次浏览 2015-09-16 19:31 来自相关话题

    docker已经可以作为compute driver来使用,脱离了原来HEAT的模式,可以做到真正地使用nova来启动容器.这里记录一下openstack Kilo + docker 1.8的集成过程.所有组件环境基于centos7.  架 ...查看全部
opdock1.png

    docker已经可以作为compute driver来使用,脱离了原来HEAT的模式,可以做到真正地使用nova来启动容器.这里记录一下openstack Kilo + docker 1.8的集成过程.所有组件环境基于centos7. 
架构图如下: 
openstack1.png


安装docker


    在compute node节点上安装docker,强烈建议安装docker-engine 1.8,需要linux3.1的kernal版本,拥有较高的生产稳定性,并且有启动用户组,旧版的docker-io是没有用户组,集成的时候docker.sock的权限每次都是手工修改很不方便.
# curl -sSL https://get.docker.com/ | sh
# usermod -aG docker nova
# systemctl enable docker.service
# systemctl start docker.service


安装novadocker


直接从github上clone安装
# pip install -e git+https://github.com/stackforge/nova-docker#egg=novadocker
# cp -R src/etc/nova/rootwrap.d /etc/nova/
# chmod -R root.nova /etc/nova/rootwrap.d
# cd src/novadocker/
# python setup.py install


配置nova调用docker驱动


# vi /etc/nova/nova.conf
compute_driver = novadocker.virt.docker.DockerDriver


配置glance支持容器格式


# vi /etc/glance/glance-api.conf (修改后重启glance-api服务)
container_formats = ami,ari,aki,bare,ovf,docker


Fix bug设置


    由于novadocker开发的版本是基于nova比较新的版本,在现在发行的版本中使用会有一个BUG,下面是修复记录.
    
1.重启openstack-nova-compute服务时提示没有找到oslo_log模块
# pip install oslo.log
2.重启openstack-nova-compute服务时提示没有找到hv_type模块
通过代码定位发现目前的版本中模块是nova.compute.hvtype 
修改/usr/lib/python2.7/site-packages/novadocker/virt/docker/driver.py
把from nova.compute import hv_type 改为 from nova.compute import hvtype
3.直接导入driver测试提示报错,CONF没有’my_ip’这个opt配置
通过代码排查发现目前的openstack是使用oslo.config这个模块包来做cfg的导入和导出 
但是在novadocker整个项目里面使用的oslo_config这个独立的模块
修改driver.py, client.py, hostinfo.py, vifs.py模块
from oslo_config import cfg 改为 from oslo.config import cfg
4.直接导入driver测试提示继续报错,没有找到hvtype.DOCKER属性
修改 /usr/lib/python2.7/site-packages/nova/compute/hvtype.py 
在# specific ‘baremetal’ & ‘fake’ then added in.下面增加
DOCKER=’docker’
    此时启动openstack-nova-compute已经正常


glance导入docker镜像


# docker pull hipache
# docker save hipache | glance image-create --is-public=True --container-format=docker --disk-format=raw --name hipache
    需要注意的是glance导入后的名字一定要和docker images下显示的名字一模一样,否则创建时会提示无法找到镜像


启动容器实例


nova boot --image hipache --flavor 1 --nic net-id=342a0eef-e03d-4fd8-af3c-1ed485bee989 docker
openstack2.png

1.此时启动容器实例报错失败,从nova-compute.log的日志看异常信息是”attach vif error”,具体是无法使用nova-rootwrap来提权进入namespace创建实例的网络接口
google找到的这个BUG的解决是禁用compute节点的selinux
2.继续下一个BUG,日志抛出一个Python异常是没有找到hardware.InstanceInfo模块
进入目录/usr/lib/python2.7/site-packages/nova/virt 
查看hardware.py的代码的确没有找到这个类或者函数,在github上找到nova项目的最新代码可以看到是有的.
openstack3.png

把这个类的代码复制到本地的hardware.py里面
 
3.重启启动一个实例后,异常继续保持 
openstack4.png
异常提示InstanceInfo没有getitem这个内置方法 
根据driver.py里面的调用可以发现get_info调用的时候是hardware.InstanceInfo是返回一个字典
删除刚才在hardware.py复制的代码,重写InstanceInfo
def InstanceInfo(state=None, max_mem_kb=0, mem_kb=0, num_cpu=0,cpu_time_ns=0, id=None):
Info={}
Info['state'] = state
Info['max_mem_kb'] = max_mem_kb
Info['self.mem_kb'] = mem_kb
Info['num_cpu'] = num_cpu
Info['cpu_time_ns'] = cpu_time_ns
Info['id'] = id
return Info
此时启动实例正常无报错
[root@openstack-k ~]# nova list
+--------------------------------------+---------+--------+------------+-------------+-------------------------------------------+
| ID | Name | Status | Task State | Power State | Networks |
+--------------------------------------+---------+--------+------------+-------------+-------------------------------------------+
| c9d7ef23-f0fe-488d-88b1-3b5650901820 | hipache | ACTIVE | - | Running | admin_private=192.168.0.101, 172.24.4.228 |
+--------------------------------------+---------+--------+------------+-------------+-------------------------------------------+
[root@openstack-k ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
14583d5d6308 hipache "supervisord -n" 5 hours ago Up 5 hours nova-c9d7ef23-f0fe-488d-88b1-3b5650901820
[root@openstack-k ~]#
参考连接:
https://wiki.openstack.org/wiki/Docker 
http://docs.docker.com/installation/centos/
https://bugs.launchpad.net/nova-docker/+bug/1480246
https://github.com/openstack/nova/
https://github.com/stackforge/nova-docker
原文链接:原文地址

控制Elasticsearch分片和副本的分配

OpenSkill 发表了文章 1 个评论 19832 次浏览 2015-09-15 00:04 来自相关话题

    ES集群中索引可能由多个分片构成,并且每个分片可以拥有多个副本。通过将一个单独的索引分为多个分片,我们可以处理不能在一个单一的服务器上面运行的大型索引,简单的说就是索引的大小过大,导致效率问题。不能运行的原因可能是内存也可能是存储。由于每个分片可以有多 ...查看全部
    ES集群中索引可能由多个分片构成,并且每个分片可以拥有多个副本。通过将一个单独的索引分为多个分片,我们可以处理不能在一个单一的服务器上面运行的大型索引,简单的说就是索引的大小过大,导致效率问题。不能运行的原因可能是内存也可能是存储。由于每个分片可以有多个副本,通过将副本分配到多个服务器,可以提高查询的负载能力。
 
    为了进行分片和副本的操作,ES需要确定将这些分片和副本放到集群节点的哪个位置,就是需要确定把每个分片和副本分配到哪台服务器/节点上。
 


一、显式控制分配


生产情景:
比如生产环境有三个索引分别为 man、woman、katoey
希望达到的效果:
man索引放置在一些集群节点上
woman索引又单独放置到集群的另外一些集群节点上
katoey索引希望放置在所有放置man索引和woman索引的集群节点上

这么做是因为katoey索引比其他两个索引小很多,因此我们可以将它和其他两个索引一起分配。
但是基于ES默认算法的处理方法,我们不能确定分片和副本的存放位置,但是ES允许我们对其做相应的控制!

1、指定节点的参数
epei1.png

    如上图所示,我们将ES集群划分为两个"空间"。当然你也可以叫做区域,随便命名。我们将左边的三台ES节点服务器放置到zone_one的空间上面,将右边的三台ES节点服务器放到zone_two的空间上。
 
配置
    为了做到我们需要的效果,我们需要将如下属性配置到左边三台ES集群节点服务器的elasticsearch.yml配置文件中
node.zone: zone_one
    将如下属性配置到右边的三台ES集群节点服务器elasticsearch.yml配置文件中
node.zone: zone_two
 
索引创建
    当所有节点配置文件属性配置完成后,我们就可以根据空间名称,我们就可以创建索引放到指定的空间。
    首先我们运行如下命令,来创建man索引:
# curl -XPOST "http://ESnode:9200/man'
# curl -XPUT "http://ESnode:9200/man/_settings' -d '{
"index.routing.allocation.include.zone" : "zone_one"
}'
    第一条命令是创建man索引;第二条命令是发送到_settings REST端点,用来指定这个索引的其他配置信息。我们将index.routing.allocation.include.zone属性设置为zone_one值,就是我们所希望的把man索引放置到node.zone属性值为zone_one的ES集群节点服务器上。
 
    同样对woman索引我们做类似操作:
# curl -XPOST "http://ESnode:9200/woman'
# curl -XPUT "http://ESnode:9200/woman/_settings' -d '{
"index.routing.allocation.include.zone" : "zone_two"
}'
    不同的是,这次指定woman索引放置在node.zone属性值为zone_two的ES集群节点服务器上
 
    最后我们需要将katoey索引放置到上面所有的ES集群节点上面,配置设置命令如下:
# curl -XPOST "http://ESnode:9200/katoey"
# curl -XPUT "http://ESnode:9200/katoey/_settings" -d '{
"index.routing.allocation.include.zone" : "zone_one,zone_two"
}'

 2、分配时排除节点
    跟我们上面操作为索引指定放置节点位置一样,我们也可以在索引分配的时候排除某些节点。参照之前的例子,我们新建一个people索引,但是不希望people索引放置到zone_one的ES集群节点服务器上,我们可以运行如下命令操作:
# curl -XPOST "http://EScode:9200/people"
# curl -XPUT "http://EScode:9200/people/_settings" -d '{
"index.routing.allocation.exclude.zone" : "zone_one"
}'
    请注意,在这里我们使用的是index.routing.allocation.exclude.zone属性而不是index.routing.allocation.include.zone属性。
 
使用IP地址进行分配配置
    除了在节点的配置中添加一些特殊的属性参数外,我们还可以使用IP地址来指定你将分片和副本分配或者不分配到哪些节点上面。为了做到这点,我们应该使用_ip属性,把zone换成_ip就好了。例如我们希望lucky索引分配到IP地址为10.0.1.110和10.0.1.119的节点上,我们可以运行如下命令设置:
# curl -XPOST "http://ESnode:9200/lucky"
# curl -XPUT "http://ESnode:9200/lucky/_settings" -d '{
"index.routing.allocation.include._ip" "10.0.1.110,10.0.1.119"
}'


二、集群范围内分配


    除了索引层面指定分配活着排除分配之外(上面我们所做的都是这两种情况),我们还可以指定集群中所有索引的分配。例如,我们希望将所有的新索引分配到IP地址为10.0.1.112和10.0.1.114的节点上,我们可以运行如下命令设置:
# curl -XPUT "http://ESnode:9200/_cluster/settings" -d '{
"transient" : {
"cluster.routing.allocation.include._ip" "10.0.1.112,10.0.1.114"
}
}'
    集群级别的控制后续还会分享transient和persistent属性介绍
 


三、每个节点上分片和副本数量的控制


    除了指定分片和副本的分配,我们还可以对一个索引指定每个节点上的最大分片数量。例如我们希望ops索引在每个节点上只有一个分片,我们可以运行如下命令:
# curl -XPUT "http://ESnode:9200/ops/_settings" -d '{
"index.routing.allocation.total_shards_per_node" : 1
}'
    这个属性也可以直接配置到elasticsearch.ym配置文件中,或者使用上面命令在活动索引上更新。如果配置不当,导致主分片无法分配的话,集群就会处于red状态。
 


四、手动移动分片和副本


    接下来我们介绍一下节点间手动移动分片和副本。可以使用ElasticSearch提供的_cluster/reroute REST端点进行控制,能够进行下面操作:
    []将一个分片从一个节点移动到另外一个节点[/][]取消对分片的分配[/][]强制对分片进行分配[/]

 
移动分片
    假设我们有两个节点:es_node_one和es_node_two,ElasticSearch在es_node_one节点上分配了ops索引的两个分片,我们现在希望将第二个分片移动到es_node_two节点上。可以如下操作实现:
# curl -XPOST "http://ESnode:9200/_cluster/reroute" -d  '{
"commands" : [ {
"move" : {
"index" : "ops",
"shard" : 1,
"from_node" : "es_node_one",
"to_node" : "es_node_two"
}
}]
}'
    我们通过move命令的index属性指定移动哪个索引,通过shard属性指定移动哪个分片,最终通过from_node属性指定我们从哪个节点上移动分片,通过to_node属性指定我们希望将分片移动到哪个节点。
 
取消分配
    如果希望取消一个正在进行的分配过程,我们通过运行cancel命令来指定我们希望取消分配的索引、节点以及分片,如下所示:
# curl -XPOST "http://ESnode:9200/_cluster/reroute" -d '{
"commands" : [ {
"cancel" : {
"index" : "ops",
"shard" : 0,
"node" : "es_node_one"
}
} ]
}'
    运行上面的命令将会取消es_node_one节上ops索引的第0个分片的分配
 
分配分片
    除了取消和移动分片和副本之外,我们还可以将一个未分配的分片分配到一个指定的节点上。假设ops索引上有一个编号为0的分片尚未分配,并且我们希望ElasticSearch将其分配到es_node_two上,可以运行如下命令操作:
# curl -XPOST "http://ESnode:9200/_cluster/reroute' -d '{
"commands" : [ {
"allocate" : {
"index" : "ops",
"shard" : 0,
"node" : "es_node_two"
}
} ]
}'
一次HTTP请求包含多个命令
    我们可以在一次HTTP请求中包含多个命令,例如:
# curl -XPOST "http://ESnode:9200/_cluster/reroute" -d '{
"commands" : [
{"move" : {"index" : "ops", "shard" : 1, "from_node" : "es_node_one", "to_node" : "es_node_two"}},
{"cancel" : {"index" : "ops", "shard" : 0, "node" : "es_node_one"}}
]
}'

如何改变docker image的存放路径

OpenSkill 回复了问题 2 人关注 1 个回复 5111 次浏览 2015-09-13 18:09 来自相关话题

HDFS高可用方案之QJM

OpenSkill 发表了文章 0 个评论 3576 次浏览 2015-09-12 20:18 来自相关话题

喜欢一个人,可以为TA做任何事,得到不接受却依然心甘情愿鞍前马后,苦苦等候那一线希望。对,这就是备胎,挂在汽车背后,可能一辈子也用不到的那个圆圈状的玩意儿,大部分情况下,它都会默默地挂在那里,等待几千分之一的机会,有个倒霉的轮子兄弟出事了,于是它就能派上用场了 ...查看全部
喜欢一个人,可以为TA做任何事,得到不接受却依然心甘情愿鞍前马后,苦苦等候那一线希望。对,这就是备胎,挂在汽车背后,可能一辈子也用不到的那个圆圈状的玩意儿,大部分情况下,它都会默默地挂在那里,等待几千分之一的机会,有个倒霉的轮子兄弟出事了,于是它就能派上用场了……(摘自豆瓣)
 
在Hadoop的分布式文件系统HDFS中,NameNode用来保存文件系统的元数据(包含目录结构/数据块位置等),如果NameNode上的数据丢失,HDFS上对应的文件数据就无法找回来了。Hadoop在2.0.0之前的版本,使用SecondaryNameNode备份NameNode的数据,但SecondaryNameNode无法转成NameNode,如果NameNode挂了,整个HDFS就会挂掉,无法实现真正的failover。这篇博文总结了5种Hadoop HA(High Available,高可用)方案,Hadoop2之后官方引入了QJM(Quorum Journal Manager)和NFS用于NameNode的备份和切换。本方将介绍的是QJM方案,它使用第二个NameNode实时同步当前NameNode的数据,相比于SecondaryNameNode,他可以随时切换成为真正的NameNode(一个可转正的高级备胎)。
 
先看看没有HA的HDFS的系统架构(用draw.io画的,尼马这么好的网站也被墙了):
hd21.png

然后有HA方案的系统架构:
hd22.png

以下的实验基于4个节点的Hadoop集群。其中每个节点的运行的进程列表如下:
hd23.png

实验环境中,所有节点的运行环境基本相同:
    []Ubuntu14.04 X64[/][]4G内存[/][]OpenJDK-1.7.0[/][]100Mbps以太网[/]
下面是实现这个系统的流程(官方文档+个人注解+辅助Shell命令)。

[list=1]

  • 安装Hadoop系统
  • 严格按照单节点搭建集群搭建两个步骤,系统建起来完全没压力。我遇到的问题是刚开始在配置文件(salves和core-site.xml等文件)中使用的是ip地址而非主机名,然后在log文件里看到各种无法连接。解决方案是修改主机名并在hosts文件里建立映射关系。
    hostname {new_hostname} # 修改主机名,只有当前Session有效sudo vi /etc/hostname   # 永久修改主机名的方法
    另外,对于64位的系统,最好重新编译源码。

    [list=1]

  • 修改配置文件
  • hdfs-site.xml文件:
          dfs.namenode.name.dir    /data/hadoop/namenode        dfs.datanode.data.dir    /data/hadoop/datanode        dfs.replication    2        dfs.nameservices    mycluster        dfs.ha.namenodes.mycluster    nn1,nn2        dfs.namenode.rpc-address.mycluster.nn1    hd1:8020        dfs.namenode.rpc-address.mycluster.nn2    hd3:8020        dfs.namenode.http-address.mycluster.nn1    hd1:50070        dfs.namenode.http-address.mycluster.nn2    hd3:50070        dfs.namenode.shared.edits.dir    qjournal://hd1:8485;hd2:8485;hd4:8485/mycluster        dfs.client.failover.proxy.provider.mycluster    org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider        dfs.ha.fencing.methods    sshfence        dfs.ha.fencing.ssh.private-key-files    /home/hduser/.ssh/id_rsa        dfs.journalnode.edits.dir    /data/hadoop/journalnode  
      []其中nameservices是集群的命名空间,即使有多个集群,可以共用配置文件,但是要注意某些配置项的顺序。[/][]dfs.ha.namenodes.mycluster中的mycluster是可以任取的,但是要和dfs.nameservices对应。[/][]dfs.namenode.rpc-address.mycluster.nn1参考上一条。[/][]dfs.namenode.shared.edits.dir值的格式是"qjournal://host1:port1;host2:port2;host3:port3/journalId",用来指定对应的JN节点,journalId建议使用和nameservices相同的名称。[/][]dfs.client.failover.proxy.provider.mycluster指定激活NameNode的Java类,目前Hadoop内置的只有上面那个。[/][]dfs.ha.fencing.methods是来用来隔离失效的NameNode的方法,有sshfence和Shell两种方式。sshfence需要配置dfs.ha.fencing.ssh.private-key-files私钥文件,以便交互的过程不需要输入密码。[/][]dfs.journalnode.edits.dir是JN保存数据的文件。[/]
     core-site.xml文件:
                fs.defaultFS        hdfs://mycluster    
      []注意mycluster要和dhfs-site.xml中的dfs.nameservices对应。fs.defaultFS不用端口号。[/]
     

    [list=1]

  • 部署
  • 改好配置文件好,就要将配置文件同步到所有的机器上了。可以用rsync将文件同步到多台机器上。rsync是一个增量同步工具,需要先安装。下面的rsync.sh的功能是将当前目录的所有文件发送到文件或参数对应的机器上。
    $ cat rsync.sh #! /bin/bashdir=`pwd`pdir=`dirname $dir`send(){    echo "Sending to $2:$1"    rsync -avez -e ssh $1 $2:$3}mul_send(){    while read host    do        send $dir $host $pdir    done < $1}[ -f $1 ] && mul_send $1 || send $dir $1 $pdir
    将rsync.sh放在etc/hadoop目录下,进入目录运行
    chmod +x rsync.sh./rsync.sh slaves# or ./rsync.sh hostname
    发送完文件之后,就是启动系统。步骤如下: 启动JNs.在所有JournalNode上运行
    sbin/hadoop-daemon.sh --script hdfs start journalnode
    启动NameNode. 在原NameNode上运行
    bin/hadoop --script hdfs start namenode # NameNode需要已经format。[url=使用上面的rsync.sh文件]/code[/url]将原NameNode(nn1)上的数据复制到第二个NameNode(nn2)。然后在nn2上运行:[code]bin/hdfs namenode -bootstrapStandby
    启动其他节点在NameNode上运行
    sbin/start-dfs.sh

    [list=1]

  • 切换NameNode

  • 手动方式

    上面的NameNode默认以standby的状态启动,这时因为没有active的NameNode,所以是不能在HDFS读写文件,需要将其中的一个转成active状态。比如将nn1(对应前面的配置)转成Active:
    bin/hdfs haadmin -transitionToActive nn1
    然后在NameNode的web页面上部的括号里的standby变成active。
    转成standby的命令是:
    bin/hdfs haadmin -transitionToStandby nn1
     
    自动切换
    在当前NameNode不能使用时自动切换到第二个NameNode上,需要借助于ZooKeeper[url=ZK]/url

    ZK的安装过程和Hadoop差不多,就是下载文件、修改配置、复制到所有机器、启动。具体步骤在这里。

    配置文件conf/zoo.conf:
    tickTime=2000
    dataDir=/data/hadoop/zookeeper
    clientPort=2181
    initLimit=5
    syncLimit=2
    server.1=hd2:2888:3888
    server.2=hd3:2888:3888
    server.3=hd4:2888:3888
    hd2,hd3,hd4是主机名,至少需要三台,这个在一台机挂了整个系统还能用,ZK的数量一般是奇数,为什么为奇数可以参考这里。
     
    然后要在hdfs-site.xml上添加配置:

    dfs.ha.automatic-failover.enabled
    true


    ha.zookeeper.quorum
    hd2:2181,hd3:2181,hd4:2181
    然后就是在NameNode的机器上初始化NameNode在ZK的状态了:
    bin/hdfs zkfc -formatZK
    重启HDFS或手动启动DFSZKFailoverController(ZKFC):
    sbin/stop-dfs.sh # 重启hdfs
    sbin/start-dfs.sh
    sbin/hadoop-daemon.sh start zkfc # 启动ZKFC
    在该HA方案中,每一个NameNode都有一个对应的ZKFC。ZKFC会随NameNode启动。
     
    测试
     
    在当前NameNode运行jps看NameNode的进程ID,然后kill掉。通过Web页面( http://hdx:50070 ),可以看到standby的NameNode几乎在kill的同时转成active了。
    转载地址:原文地址

    Docker镜像无法删除

    空心菜 回复了问题 2 人关注 1 个回复 5263 次浏览 2015-09-10 11:09 来自相关话题

    HDFS中Datanode存在大量没有删除的Block磁盘被占满案例分析

    OpenSkill 发表了文章 0 个评论 7164 次浏览 2015-09-09 00:09 来自相关话题

    最近发现hdfs中,有的datanode节点,磁盘发生告警,然后分析了一下。 然后上网搜索了一下为什么,分析如下:   查看对应datanode的数据目录,发现确实有很多的数据块(量非常大,都超过了实际hdfs中的数据块总量 ...查看全部
    最近发现hdfs中,有的datanode节点,磁盘发生告警,然后分析了一下。
    然后上网搜索了一下为什么,分析如下:
     
    查看对应datanode的数据目录,发现确实有很多的数据块(量非常大,都超过了实际hdfs中的数据块总量)
     
    这时候,猜测应该是有很多需要被删除的数据块没有被删除。猜测可能是NameNode和DataNode之间的通讯出现异常导致。于是查看NameNode和DataNode日志,发现并没有任何异常信息,只是发现NameNode定时对其中的三台机器发出了删除指令
    BLOCK[i] ask 192.168.200.8:50010 to delete  blk_7080908721303033545_7530145 BLOCK[/i] ask 192.168.200.9:50010 to delete  blk_-6550808355677895247_7465333 BLOCK* ask 192.168.200.7:50010 to delete  blk_2415291932316966347_7460687

    按照网上的方法,通过dfsadmin证实了,确实是有大量的block在等待删除
    hadoop dfsadmin -metasave meta.txt
    然后到logs目录下查看meta.txt文件结果如下:
    Metasave: Blocks 572428 waiting deletion from 8 datanodes.
    显示有几十万的block等待删除
     
    没有办法,只好从源码着手。在FSNameSystem.java文件里面找到了最终问题的所在:
    public int computeDatanodeWork() throws IOException {
    int workFound = 0;
    int blocksToProcess = 0;
    int nodesToProcess = 0;
    // blocks should not be replicated or removed if safe mode is on
    if (isInSafeMode())
    return workFound;
    synchronized(heartbeats) {
    blocksToProcess = (int)(heartbeats.size()
    * ReplicationMonitor.REPLICATION_WORK_MULTIPLIER_PER_ITERATION);
    nodesToProcess = (int)Math.ceil((double)heartbeats.size()
    * ReplicationMonitor.INVALIDATE_WORK_PCT_PER_ITERATION / 100);

    }

    workFound = computeReplicationWork(blocksToProcess);

    // Update FSNamesystemMetrics counters
    synchronized (this) {
    pendingReplicationBlocksCount = pendingReplications.size();
    underReplicatedBlocksCount = neededReplications.size();
    scheduledReplicationBlocksCount = workFound;
    corruptReplicaBlocksCount = corruptReplicas.size();
    }

    workFound += computeInvalidateWork(nodesToProcess);

    return workFound;
    }
    computeInvalidateWork就是用于计算这次需要删除的数据块。但是并不是每次都把所有的节点都处理一遍,而是每次只处理nodesToProcess个节点,而这个数量决定于datanode的总数(heartbeats.size,我这儿是8)和一个系数(INVALIDATE_WORK_PCT_PER_ITERATION,写死的32)。
     
    也就是说每次只处理

    8*32% = 3(这就解释了为啥每次只删除三台数据节点上的数据块。)

    再查看节点选择部分:
    ……
    private Map> recentInvalidateSets =
    new TreeMap>();

    ……
    String firstNodeId = recentInvalidateSets.keySet().iterator().next();

    ……
    发现是通过iterator遍历的,然后悲剧的发现recentInvalidateSets用的是TreeMap,也就是说是有序的……

    所以只要这三个节点有数据需要删除,就不会删除到其他节点
     
    这时候,发现这个问题是调整的时候,修改了一个配置项(dfs.replication.interval,默认是3秒,我修改成了30秒)导致的,当时修改的初衷是防止过早出现数据块复制。但是修改这个配置项以后,数据块副本数检查的间隔拉长了,导致30秒内,有几台机器一直有数据块需要删除,从而无法删除其他节点上的数据块,最终导致磁盘空间无法释放。因为INVALIDATE_WORK_PCT_PER_ITERATION是系统写死的,所以只能通过把dfs.replication.interval改回来,暂时解决这个问题。
     

    Docker not support swap limit capabilities

    Ansible 回复了问题 2 人关注 1 个回复 4954 次浏览 2015-09-07 01:57 来自相关话题