云计算大数据

云计算大数据

源码分析Elasticsearch Master选举过程

大数据/云计算Geek小A 发表了文章 • 2 个评论 • 94 次浏览 • 2017-01-05 20:16 • 来自相关话题

ES 有Master节点和Data节点,Master节点什么意思呢? 就是主人节点,这个集群的主人,就是皇帝。ES同一时刻只有一个Master节点。小生一直看古装走火入魔,所谓心里有王朝,眼里就有王朝,看啥啥是王朝。就用王朝解释下集群,皇帝比喻下Master。我们先来看2个配置项。
 
node.master: true  就是皇子,意思是有资格成为Master,成为皇帝的人选,这是天生的,是无字天书,在elasticsearch.yml里写好的。

discovery.zen.minimum_master_nodes: 1 就是几个皇子在场的时候,才能选新皇帝,不然难以服众,容易脑裂(brain split)是吧。
 

Master的职责

只有皇帝才有资格发布圣旨ClusterState(集群状态)。他维护着这个王朝的状态,决定着这个王朝很多重要的大小事物。有一些事情必须皇帝才能执行,比如砍头(删除索引)。但是ES作为P2P集群,Master的职责,还是被弱化了一些。一张图看一下皇帝的工作内容。





 

什么时候选Master

只有在皇帝驾崩,和王朝诞生的时候,才选举Master皇帝,是吧,想让皇帝禅位,除非他死了,或者王朝被推翻了(所有节点重启)

 
节点启动,要加入一个集群的时候
 
//ZenDiscovery
private void innterJoinCluster() {
boolean retry = true;
while (retry) {
if (lifecycle.stoppedOrClosed()) {
return;
}
retry = false;
DiscoveryNode masterNode = findMaster(); //找一个节点出来当皇帝
if (masterNode == null) {
logger.trace("no masterNode returned");
retry = true;
continue;
}
//....
或者节点关闭 Master Gone
private void handleMasterGone(final DiscoveryNode masterNode, final String reason) {
if (lifecycleState() != Lifecycle.State.STARTED) {
return;
}
if (master) {
return;
}
logger.info("master_left [{}], reason [{}]", masterNode, reason);
clusterService.submitStateUpdateTask("zen-disco-master_failed (" + masterNode + ")", Priority.HIGH, new ProcessedClusterStateUpdateTask() {
@Override
public ClusterState execute(ClusterState currentState) {
if (!masterNode.id().equals(currentState.nodes().masterNodeId())) {
return currentState;
}
DiscoveryNodes.Builder nodesBuilder = DiscoveryNodes.newNodesBuilder()
.putAll(currentState.nodes())
.remove(masterNode.id())
.masterNodeId(null);
if (!electMaster.hasEnoughMasterNodes(nodesBuilder.build())) {
return rejoin(ClusterState.builder().state(currentState).nodes(nodesBuilder).build(), "not enough master nodes after master left (reason = " + reason + ")");
}
final DiscoveryNode electedMaster = electMaster.electMaster(nodesBuilder.build()); // 选举Master
 

Master选举

首先必须是皇子(node.master: true),具体哪皇子成为皇帝呢? 看天意啊,最先启动的那个节点。老臣认为。当立嫡长子为太子,成为皇帝啊,这样江山社稷才能稳固啊,(一阵激动)省略上万句。。。好了,演完戏了,看代码。

 
ZenDiscovery模块启动的时候,要加入集群。findMaster 方法里,Ping一堆节点出来,Ping就是发现节点,这里的Ping不是Linux的命令Ping,是向ES的9300端口发送数据的意思。Linux的Ping是可以禁止的,不能因为命令Ping不通机器,就认为相互不能发现节点。Ping有组播MulticastZenPing和单播UnicastZenPing 两种。如果节点少,用单播也可以。组播在一些环境下可能无法相互发现节点,或者被安全软件识别为恶意程序。节点列表确定后。交给 ElectMasterService 去选举,快排后的第一个节点
//ElectMasterService
/**
* Elects a new master out of the possible nodes, returning it. Returns <tt>null</tt>
* if no master has been elected.
*/
public DiscoveryNode electMaster(Iterable<DiscoveryNode> nodes) {
List<DiscoveryNode> sortedNodes = sortedMasterNodes(nodes);
if (sortedNodes == null || sortedNodes.isEmpty()) {
return null;
}
return sortedNodes.get(0);
}

private List<DiscoveryNode> sortedMasterNodes(Iterable<DiscoveryNode> nodes) {
List<DiscoveryNode> possibleNodes = Lists.newArrayList(nodes);
if (possibleNodes.isEmpty()) {
return null;
}
// clean non master nodes
for (Iterator<DiscoveryNode> it = possibleNodes.iterator(); it.hasNext(); ) {
DiscoveryNode node = it.next();
if (!node.masterNode()) {
it.remove();
}
}
CollectionUtil.quickSort(possibleNodes, nodeComparator);
return possibleNodes;
}对了,皇帝上位以后,第一件事情是发布圣旨,昭告天下,以后寡人就是皇帝了。

怎么看,现在谁是皇帝呢?
 
curl http://localhost:9200/_cat/master?v
脑裂问题
 
关于brain split脑裂问题,可以看这个:
如何避免脑裂: http://blog.trifork.com/2013/10/24/how-to-avoid-the-split-brain-problem-in-elasticsearch/  
官方讨论:https://github.com/elasticsearch/elasticsearch/issues/2488 
 
最后,为了让大家对皇帝有个感性的认识,赠图一张,不谢!




原文分享:http://www.codeweblog.com/elasticsearch-%E6%BA%90%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8Bmaster%E9%80%89%E4%B8%BE/  查看全部
ES 有Master节点和Data节点,Master节点什么意思呢? 就是主人节点,这个集群的主人,就是皇帝。ES同一时刻只有一个Master节点。小生一直看古装走火入魔,所谓心里有王朝,眼里就有王朝,看啥啥是王朝。就用王朝解释下集群,皇帝比喻下Master。我们先来看2个配置项。
 
node.master: true  就是皇子,意思是有资格成为Master,成为皇帝的人选,这是天生的,是无字天书,在elasticsearch.yml里写好的。

discovery.zen.minimum_master_nodes: 1 就是几个皇子在场的时候,才能选新皇帝,不然难以服众,容易脑裂(brain split)是吧。
 


Master的职责


只有皇帝才有资格发布圣旨ClusterState(集群状态)。他维护着这个王朝的状态,决定着这个王朝很多重要的大小事物。有一些事情必须皇帝才能执行,比如砍头(删除索引)。但是ES作为P2P集群,Master的职责,还是被弱化了一些。一张图看一下皇帝的工作内容。

Masterkpi.png

 


什么时候选Master


只有在皇帝驾崩,和王朝诞生的时候,才选举Master皇帝,是吧,想让皇帝禅位,除非他死了,或者王朝被推翻了(所有节点重启)

 
节点启动,要加入一个集群的时候
 
//ZenDiscovery
private void innterJoinCluster() {
boolean retry = true;
while (retry) {
if (lifecycle.stoppedOrClosed()) {
return;
}
retry = false;
DiscoveryNode masterNode = findMaster(); //找一个节点出来当皇帝
if (masterNode == null) {
logger.trace("no masterNode returned");
retry = true;
continue;
}
//....

或者节点关闭 Master Gone
private void handleMasterGone(final DiscoveryNode masterNode, final String reason) {
if (lifecycleState() != Lifecycle.State.STARTED) {
return;
}
if (master) {
return;
}
logger.info("master_left [{}], reason [{}]", masterNode, reason);
clusterService.submitStateUpdateTask("zen-disco-master_failed (" + masterNode + ")", Priority.HIGH, new ProcessedClusterStateUpdateTask() {
@Override
public ClusterState execute(ClusterState currentState) {
if (!masterNode.id().equals(currentState.nodes().masterNodeId())) {
return currentState;
}
DiscoveryNodes.Builder nodesBuilder = DiscoveryNodes.newNodesBuilder()
.putAll(currentState.nodes())
.remove(masterNode.id())
.masterNodeId(null);
if (!electMaster.hasEnoughMasterNodes(nodesBuilder.build())) {
return rejoin(ClusterState.builder().state(currentState).nodes(nodesBuilder).build(), "not enough master nodes after master left (reason = " + reason + ")");
}
final DiscoveryNode electedMaster = electMaster.electMaster(nodesBuilder.build()); // 选举Master

 


Master选举


首先必须是皇子(node.master: true),具体哪皇子成为皇帝呢? 看天意啊,最先启动的那个节点。老臣认为。当立嫡长子为太子,成为皇帝啊,这样江山社稷才能稳固啊,(一阵激动)省略上万句。。。好了,演完戏了,看代码。

 
ZenDiscovery模块启动的时候,要加入集群。findMaster 方法里,Ping一堆节点出来,Ping就是发现节点,这里的Ping不是Linux的命令Ping,是向ES的9300端口发送数据的意思。Linux的Ping是可以禁止的,不能因为命令Ping不通机器,就认为相互不能发现节点。Ping有组播MulticastZenPing和单播UnicastZenPing 两种。如果节点少,用单播也可以。组播在一些环境下可能无法相互发现节点,或者被安全软件识别为恶意程序。节点列表确定后。交给 ElectMasterService 去选举,快排后的第一个节点
//ElectMasterService
/**
* Elects a new master out of the possible nodes, returning it. Returns <tt>null</tt>
* if no master has been elected.
*/
public DiscoveryNode electMaster(Iterable<DiscoveryNode> nodes) {
List<DiscoveryNode> sortedNodes = sortedMasterNodes(nodes);
if (sortedNodes == null || sortedNodes.isEmpty()) {
return null;
}
return sortedNodes.get(0);
}

private List<DiscoveryNode> sortedMasterNodes(Iterable<DiscoveryNode> nodes) {
List<DiscoveryNode> possibleNodes = Lists.newArrayList(nodes);
if (possibleNodes.isEmpty()) {
return null;
}
// clean non master nodes
for (Iterator<DiscoveryNode> it = possibleNodes.iterator(); it.hasNext(); ) {
DiscoveryNode node = it.next();
if (!node.masterNode()) {
it.remove();
}
}
CollectionUtil.quickSort(possibleNodes, nodeComparator);
return possibleNodes;
}
对了,皇帝上位以后,第一件事情是发布圣旨,昭告天下,以后寡人就是皇帝了。

怎么看,现在谁是皇帝呢?
 
curl http://localhost:9200/_cat/master?v

脑裂问题
 
关于brain split脑裂问题,可以看这个:
如何避免脑裂: http://blog.trifork.com/2013/10/24/how-to-avoid-the-split-brain-problem-in-elasticsearch/  
官方讨论:https://github.com/elasticsearch/elasticsearch/issues/2488 
 
最后,为了让大家对皇帝有个感性的认识,赠图一张,不谢!
hd.png

原文分享:http://www.codeweblog.com/elasticsearch-%E6%BA%90%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8Bmaster%E9%80%89%E4%B8%BE/ 

消费kafka数据出错Found a message larger than the maximum fetch size

大数据/云计算采菊篱下 回复了问题 • 2 人关注 • 1 个回复 • 92 次浏览 • 2017-01-05 14:18 • 来自相关话题

如何为Kafka集群选择合适的主题和分区数量

大数据/云计算Ansible 发表了文章 • 0 个评论 • 118 次浏览 • 2016-12-26 00:03 • 来自相关话题

这是许多Kafka用户提出的常见问题。 这篇文章的目的是解释几个重要的决定因素,并提供一些简单的公式。
 

更多的分区提供更高的吞吐量

首先要理解的是,主题分区是Kafka中并行性的单位。 在生产者和代理端,对不同分区的写入可以完全并行完成。 因此,昂贵的操作(例如压缩)可以利用更多的硬件资源。 在消费者方面,Kafka总是将一个分区的数据提供给一个消费者线程。 因此,消费者(在消费者组内)的并行度受所消耗的分区的数量的限制。 因此,一般来说,Kafka集群中的分区越多,吞吐量就越高。

用于选择分区数量的粗略公式基于吞吐量。 你衡量整个,你可以在生产单个分区(称之为P)和消费实现(称为C)。 比方说,你的目标吞吐量吨 。 然后,你需要至少有MAX(T / P,T / C)分区。 人们可以在生产者上实现的每分区吞吐量取决于诸如批处理大小,压缩编解码器,确认类型,复制因子等等的配置。然而,一般来说,可以在10秒的MB /如在此所示单个分区的基准 。 消费者吞吐量通常是与应用相关的,因为它对应于消费者逻辑可以如何快速地处理每个消息。 所以,你真的需要测量它。

虽然可以随着时间增加分区的数量,但是如果使用密钥生成消息,则必须小心。 当发布带密钥的消息时,Kafka基于密钥的散列将消息确定性地映射到分区。 这提供了保证具有相同密钥的消息总是路由到同一分区。 此保证对于某些应用可能是重要的,因为分区内的消息总是按顺序递送给消费者。 如果分区的数量改变,则这样的保证可能不再保持。 为了避免这种情况,一种常见的做法是过度分区。 基本上,您可以根据未来的目标吞吐量确定分区数,比如一两年后。 最初,您可以根据您的当前吞吐量只有一个小的Kafka集群。 随着时间的推移,您可以向集群添加更多代理,并按比例将现有分区的一部分移动到新代理(可以在线完成)。 这样,当使用密钥时,您可以跟上吞吐量增长,而不会破坏应用程序中的语义。

除了吞吐量,还有一些其他因素,在选择分区数时值得考虑。 正如你将看到的,在某些情况下,分区太多也可能产生负面影响。
 

更多分区需要打开更多的文件句柄

每个分区映射到broker中文件系统中的目录。 在该日志目录中,每个日志段将有两个文件(一个用于索引,另一个用于实际数据)。 目前,在Kafka中,每个broker打开每个日志段的索引和数据文件的文件句柄。 因此,分区越多,底层操作系统中需要配置打开文件句柄限制的分区越多。 这大多只是一个配置问题。 我们已经看到生产Kafka集群中,运行的每个broker打开的文件句柄数超过30000。
 

更多分区可能是不可用性增加

Kafka支持群集内复制 ,它提供更高的可用性和耐用性。 分区可以有多个副本,每个副本存储在不同的代理上。 其中一个副本被指定为领导者,其余的副本是追随者。 在内部,Kafka自动管理所有这些副本,并确保它们保持同步。 生产者和消费者对分区的请求都在领导副本上提供。 当代理失败时,该代理上具有leader的分区变得暂时不可用。 Kafka将自动将那些不可用分区的领导者移动到其他一些副本以继续服务客户端请求。 这个过程由指定为控制器的Kafka代理之一完成。 它涉及在ZooKeeper中为每个受影响的分区读取和写入一些元数据。 目前,ZooKeeper的操作是在控制器中串行完成的。

在通常情况下,当代理被干净地关闭时,控制器将主动地将领导者一次一个地关闭关闭代理。 单个领导者的移动只需要几毫秒。 因此,从客户的角度来看,在干净的代理关闭期间只有一小窗口的不可用性。

然而,当代理不干净地关闭(例如,kill -9)时,所观察到的不可用性可能与分区的数量成比例。 假设代理具有总共2000个分区,每个具有2个副本。 大致来说,这个代理将是大约1000个分区的领导者。 当这个代理不干净失败时,所有这1000个分区完全不能同时使用。 假设为单个分区选择新的领导需要5毫秒。 对于所有1000个分区,选择新的领导将需要5秒钟。 因此,对于一些分区,它们的观察到的不可用性可以是5秒加上检测故障所花费的时间。

如果一个是不幸的,失败的代理可能是控制器。 在这种情况下,选举新领导者的过程将不会开始,直到控制器故障转移到新的代理。 控制器故障转移自动发生,但需要新控制器在初始化期间从ZooKeeper读取每个分区的一些元数据。 例如,如果Kafka集群中有10,000个分区,并且从ZooKeeper初始化元数据每个分区需要2ms,则可以向不可用性窗口添加20多秒。

一般来说,不洁的故障是罕见的。 但是,如果在这种极少数情况下关心可用性,则可能最好将每个代理的分区数限制为两个到四千个,集群中的分区总数限制到几万个。
 

更多分区可能会增加端到端延迟

Kafka中的端到端延迟由从生产者发布消息到消费者读取消息的时间来定义。 Kafka仅在提交后向消费者公开消息,即,当消息被复制到所有同步副本时。 因此,提交消息的时间可以是端到端等待时间的显着部分。 默认情况下,对于在两个代理之间共享副本的所有分区,Kafka代理仅使用单个线程从另一个代理复制数据。 我们的实验表明,将1000个分区从一个代理复制到另一个代理可以添加大约20毫秒的延迟,这意味着端到端延迟至少为20毫秒。 这对于一些实时应用来说可能太高。

请注意,此问题在较大的群集上减轻。 例如,假设代理上有1000个分区引导,并且在同一个Kafka集群中有10个其他代理。 剩余的10个代理中的每个仅需要从第一代理平均获取100个分区。 因此,由于提交消息而增加的延迟将仅为几毫秒,而不是几十毫秒。

作为一个经验法则,如果你关心的延迟,它可能是一个好主意,每个经纪人的分区数量限制为100 * b * r,其中b是经纪人在kafka集群的数量和r是复制因子。
 

更多分区可能需要更多的内存在客户端

在最新的0.8.2版本,我们汇合到我们平台1.0,我们已经开发出一种更有效的Java生产商。 新生产者的一个好的功能是它允许用户设置用于缓冲传入消息的内存量的上限。 在内部,生产者缓冲每个分区的消息。 在累积了足够的数据或已经过去足够的时间之后,累积的消息从缓冲器中移除并发送到代理。

如果增加分区的数量,消息将在生产者中的更多分区中累积。 所使用的内存总量现在可能超过配置的内存限制。 当这种情况发生时,生产者必须阻止或丢弃任何新的消息,这两者都不是理想的。 为了防止这种情况发生,需要重新配置具有较大内存大小的生产者。

作为经验法则,为了实现良好的吞吐量,应该在生成器中分配至少几十KB的每个分区,并且如果分区的数量显着增加,则调整存储器的总量。

消费者也存在类似的问题。 消费者每个分区获取一批消息。 消费者消耗的分区越多,需要的内存就越多。 然而,这通常只是不是实时的消费者的问题。
 

总结

通常,Kafka集群中的更多分区导致更高的吞吐量。 然而,人们不得不意识到在总体上或每个代理中具有过多分区对可用性和等待时间的潜在影响。 在未来,我们计划改进一些限制,使Kafka在分区数方面更具可扩展性。
 

翻译原文:https://www.confluent.io/blog/how-to-choose-the-number-of-topicspartitions-in-a-kafka-cluster/  
作者:饶俊 查看全部
kafka.png

这是许多Kafka用户提出的常见问题。 这篇文章的目的是解释几个重要的决定因素,并提供一些简单的公式。
 


更多的分区提供更高的吞吐量


首先要理解的是,主题分区是Kafka中并行性的单位。 在生产者和代理端,对不同分区的写入可以完全并行完成。 因此,昂贵的操作(例如压缩)可以利用更多的硬件资源。 在消费者方面,Kafka总是将一个分区的数据提供给一个消费者线程。 因此,消费者(在消费者组内)的并行度受所消耗的分区的数量的限制。 因此,一般来说,Kafka集群中的分区越多,吞吐量就越高。

用于选择分区数量的粗略公式基于吞吐量。 你衡量整个,你可以在生产单个分区(称之为P)和消费实现(称为C)。 比方说,你的目标吞吐量吨 。 然后,你需要至少有MAX(T / P,T / C)分区。 人们可以在生产者上实现的每分区吞吐量取决于诸如批处理大小,压缩编解码器,确认类型,复制因子等等的配置。然而,一般来说,可以在10秒的MB /如在此所示单个分区的基准 。 消费者吞吐量通常是与应用相关的,因为它对应于消费者逻辑可以如何快速地处理每个消息。 所以,你真的需要测量它。

虽然可以随着时间增加分区的数量,但是如果使用密钥生成消息,则必须小心。 当发布带密钥的消息时,Kafka基于密钥的散列将消息确定性地映射到分区。 这提供了保证具有相同密钥的消息总是路由到同一分区。 此保证对于某些应用可能是重要的,因为分区内的消息总是按顺序递送给消费者。 如果分区的数量改变,则这样的保证可能不再保持。 为了避免这种情况,一种常见的做法是过度分区。 基本上,您可以根据未来的目标吞吐量确定分区数,比如一两年后。 最初,您可以根据您的当前吞吐量只有一个小的Kafka集群。 随着时间的推移,您可以向集群添加更多代理,并按比例将现有分区的一部分移动到新代理(可以在线完成)。 这样,当使用密钥时,您可以跟上吞吐量增长,而不会破坏应用程序中的语义。

除了吞吐量,还有一些其他因素,在选择分区数时值得考虑。 正如你将看到的,在某些情况下,分区太多也可能产生负面影响。
 


更多分区需要打开更多的文件句柄


每个分区映射到broker中文件系统中的目录。 在该日志目录中,每个日志段将有两个文件(一个用于索引,另一个用于实际数据)。 目前,在Kafka中,每个broker打开每个日志段的索引和数据文件的文件句柄。 因此,分区越多,底层操作系统中需要配置打开文件句柄限制的分区越多。 这大多只是一个配置问题。 我们已经看到生产Kafka集群中,运行的每个broker打开的文件句柄数超过30000。
 


更多分区可能是不可用性增加


Kafka支持群集内复制 ,它提供更高的可用性和耐用性。 分区可以有多个副本,每个副本存储在不同的代理上。 其中一个副本被指定为领导者,其余的副本是追随者。 在内部,Kafka自动管理所有这些副本,并确保它们保持同步。 生产者和消费者对分区的请求都在领导副本上提供。 当代理失败时,该代理上具有leader的分区变得暂时不可用。 Kafka将自动将那些不可用分区的领导者移动到其他一些副本以继续服务客户端请求。 这个过程由指定为控制器的Kafka代理之一完成。 它涉及在ZooKeeper中为每个受影响的分区读取和写入一些元数据。 目前,ZooKeeper的操作是在控制器中串行完成的。

在通常情况下,当代理被干净地关闭时,控制器将主动地将领导者一次一个地关闭关闭代理。 单个领导者的移动只需要几毫秒。 因此,从客户的角度来看,在干净的代理关闭期间只有一小窗口的不可用性。

然而,当代理不干净地关闭(例如,kill -9)时,所观察到的不可用性可能与分区的数量成比例。 假设代理具有总共2000个分区,每个具有2个副本。 大致来说,这个代理将是大约1000个分区的领导者。 当这个代理不干净失败时,所有这1000个分区完全不能同时使用。 假设为单个分区选择新的领导需要5毫秒。 对于所有1000个分区,选择新的领导将需要5秒钟。 因此,对于一些分区,它们的观察到的不可用性可以是5秒加上检测故障所花费的时间。

如果一个是不幸的,失败的代理可能是控制器。 在这种情况下,选举新领导者的过程将不会开始,直到控制器故障转移到新的代理。 控制器故障转移自动发生,但需要新控制器在初始化期间从ZooKeeper读取每个分区的一些元数据。 例如,如果Kafka集群中有10,000个分区,并且从ZooKeeper初始化元数据每个分区需要2ms,则可以向不可用性窗口添加20多秒。

一般来说,不洁的故障是罕见的。 但是,如果在这种极少数情况下关心可用性,则可能最好将每个代理的分区数限制为两个到四千个,集群中的分区总数限制到几万个。
 


更多分区可能会增加端到端延迟


Kafka中的端到端延迟由从生产者发布消息到消费者读取消息的时间来定义。 Kafka仅在提交后向消费者公开消息,即,当消息被复制到所有同步副本时。 因此,提交消息的时间可以是端到端等待时间的显着部分。 默认情况下,对于在两个代理之间共享副本的所有分区,Kafka代理仅使用单个线程从另一个代理复制数据。 我们的实验表明,将1000个分区从一个代理复制到另一个代理可以添加大约20毫秒的延迟,这意味着端到端延迟至少为20毫秒。 这对于一些实时应用来说可能太高。

请注意,此问题在较大的群集上减轻。 例如,假设代理上有1000个分区引导,并且在同一个Kafka集群中有10个其他代理。 剩余的10个代理中的每个仅需要从第一代理平均获取100个分区。 因此,由于提交消息而增加的延迟将仅为几毫秒,而不是几十毫秒。

作为一个经验法则,如果你关心的延迟,它可能是一个好主意,每个经纪人的分区数量限制为100 * b * r,其中b是经纪人在kafka集群的数量和r是复制因子。
 


更多分区可能需要更多的内存在客户端


在最新的0.8.2版本,我们汇合到我们平台1.0,我们已经开发出一种更有效的Java生产商。 新生产者的一个好的功能是它允许用户设置用于缓冲传入消息的内存量的上限。 在内部,生产者缓冲每个分区的消息。 在累积了足够的数据或已经过去足够的时间之后,累积的消息从缓冲器中移除并发送到代理。

如果增加分区的数量,消息将在生产者中的更多分区中累积。 所使用的内存总量现在可能超过配置的内存限制。 当这种情况发生时,生产者必须阻止或丢弃任何新的消息,这两者都不是理想的。 为了防止这种情况发生,需要重新配置具有较大内存大小的生产者。

作为经验法则,为了实现良好的吞吐量,应该在生成器中分配至少几十KB的每个分区,并且如果分区的数量显着增加,则调整存储器的总量。

消费者也存在类似的问题。 消费者每个分区获取一批消息。 消费者消耗的分区越多,需要的内存就越多。 然而,这通常只是不是实时的消费者的问题。
 


总结


通常,Kafka集群中的更多分区导致更高的吞吐量。 然而,人们不得不意识到在总体上或每个代理中具有过多分区对可用性和等待时间的潜在影响。 在未来,我们计划改进一些限制,使Kafka在分区数方面更具可扩展性。
 


翻译原文:https://www.confluent.io/blog/how-to-choose-the-number-of-topicspartitions-in-a-kafka-cluster/  
作者:饶俊


Druid每个任务内存调整

回复

大数据/云计算采菊篱下 发起了问题 • 1 人关注 • 0 个回复 • 156 次浏览 • 2016-12-08 16:22 • 来自相关话题

Elasticsearch如何防止内存被交换出去

大数据/云计算采菊篱下 回复了问题 • 2 人关注 • 1 个回复 • 138 次浏览 • 2016-12-07 11:00 • 来自相关话题

Elasticsearch 2.2.0节点类型介绍

开源技术Nock 发表了文章 • 0 个评论 • 165 次浏览 • 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进行配置,可以设置排除那些索引或者指定固定的部落名称。

云主机IO性能测试报告

大数据/云计算Nock 发表了文章 • 0 个评论 • 178 次浏览 • 2016-12-01 18:49 • 来自相关话题

不同厂商的云主机在性能、设计、操作方面都存在很大的差异化。
 

吐槽云商

1、阿里云 -- 地主黑势力
阿里的包月包年捆绑式销售,创建完成后你不能及时删除释放主机,只能默默的等到期了,记得我第一次使用阿里云的时候,一口气开了10台云主机,后面我发现我不需要这么多,预算出错,但是阿里告诉我的是你人生中只有一次反悔的机会,我只能删掉一台主机。
 
其他的主机我只能等他默认到期了,如果实在没有多大作用我只能浪费我的银两,然后阿里坐收消费,我就当打赏王坚一个小红包了。
 
2、Ucloud -- 清廉百姓官
Ucloud的业务是我最喜欢的,尤其是喜欢他们的服务和UI设计。在国内做市场,我想你最应该的是调研国内技术人员的操作习惯,然后把云产品的使用达到极简、易使用,而不是黑灯找芝麻。在我的心理Ucloud是国内在云主机的操作和体验上给我的感受是最佳的。 还有就是他们的服务,他们可以一对一的帮你解决问题,耐心的解答,没有阿里那财大气粗的蛮横,不会绑架你。
 
3、Azure -- 没长齐毛的鸟
为什么我说Azure是没有长齐毛的鸟,因为他的产品设计还没有完善,操作困难,可能Azure还没有大力投入做中国市场吧,好多功能都依赖于PowerShell去完成操作,比如挂盘、弹性公网ip的绑定申请等,我想说的是我是个运维,脑子里面记了一大堆命令,我使用你们产品,挂个盘你还得让我去记一大堆命令和规则,我疯了。so.......
 
我使用过Ucloud、阿里云、Azure、Google云、AWS等诸多厂商的云产品服务,具体的其他功能我就不一一对比,下面我就介绍一下,我最近做的IO测试几家厂商的报告。
 

IO测试

测试命令如下:
fio -filename=/data/test.out1 -direct=1 -rw=read -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test1

fio -filename=/data/test.out2 -direct=1 -rw=write -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test2

fio -filename=/data/test.out3 -direct=1 -rw=randread -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test3

fio -filename=/data/test.out4 -direct=1 -rw=randwrite -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test4
测试结果如下:
















上面分别是Ucloud、阿里、Azure、谷歌云的IO测试结果。
 

速率测试

测试命令如下:
dd iflag=direct </data/test.out3 >/dev/null bs=16k count=102400
dd oflag=direct </dev/zero >/data/test2 bs=16k count=102400
测试结果如下:




 

总结

废话不多说,以上的测试结果仅供大家参考,新时代的云运维者,必须要有语言基础了,没有语言基础,就算Ucloud的操作再怎么人性化,你也不能自动化,所以从云时代的趋势来看作为运维者掌握一门语言还是很有必要的了。云平台有很多坑,在没有充分了解厂商的情况下,你会发现云时代的运维更难。 查看全部
不同厂商的云主机在性能、设计、操作方面都存在很大的差异化。
 


吐槽云商


1、阿里云 -- 地主黑势力
阿里的包月包年捆绑式销售,创建完成后你不能及时删除释放主机,只能默默的等到期了,记得我第一次使用阿里云的时候,一口气开了10台云主机,后面我发现我不需要这么多,预算出错,但是阿里告诉我的是你人生中只有一次反悔的机会,我只能删掉一台主机。
 
其他的主机我只能等他默认到期了,如果实在没有多大作用我只能浪费我的银两,然后阿里坐收消费,我就当打赏王坚一个小红包了。
 
2、Ucloud -- 清廉百姓官
Ucloud的业务是我最喜欢的,尤其是喜欢他们的服务和UI设计。在国内做市场,我想你最应该的是调研国内技术人员的操作习惯,然后把云产品的使用达到极简、易使用,而不是黑灯找芝麻。在我的心理Ucloud是国内在云主机的操作和体验上给我的感受是最佳的。 还有就是他们的服务,他们可以一对一的帮你解决问题,耐心的解答,没有阿里那财大气粗的蛮横,不会绑架你。
 
3、Azure -- 没长齐毛的鸟
为什么我说Azure是没有长齐毛的鸟,因为他的产品设计还没有完善,操作困难,可能Azure还没有大力投入做中国市场吧,好多功能都依赖于PowerShell去完成操作,比如挂盘、弹性公网ip的绑定申请等,我想说的是我是个运维,脑子里面记了一大堆命令,我使用你们产品,挂个盘你还得让我去记一大堆命令和规则,我疯了。so.......
 
我使用过Ucloud、阿里云、Azure、Google云、AWS等诸多厂商的云产品服务,具体的其他功能我就不一一对比,下面我就介绍一下,我最近做的IO测试几家厂商的报告。
 


IO测试


测试命令如下:
fio -filename=/data/test.out1 -direct=1 -rw=read -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test1

fio -filename=/data/test.out2 -direct=1 -rw=write -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test2

fio -filename=/data/test.out3 -direct=1 -rw=randread -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test3

fio -filename=/data/test.out4 -direct=1 -rw=randwrite -bs=4k -size=10g -numjobs=4 -runtime=1200 -group_reporting -name=test4

测试结果如下:
Ucloud.png

ali.png

Azure.png

GoogleCloud.png

上面分别是Ucloud、阿里、Azure、谷歌云的IO测试结果。
 


速率测试


测试命令如下:
dd iflag=direct </data/test.out3 >/dev/null bs=16k count=102400
dd oflag=direct </dev/zero >/data/test2 bs=16k count=102400

测试结果如下:
mancloud.png

 


总结


废话不多说,以上的测试结果仅供大家参考,新时代的云运维者,必须要有语言基础了,没有语言基础,就算Ucloud的操作再怎么人性化,你也不能自动化,所以从云时代的趋势来看作为运维者掌握一门语言还是很有必要的了。云平台有很多坑,在没有充分了解厂商的情况下,你会发现云时代的运维更难。

关于Elasticsearch性能优化几个点

大数据/云计算小白菜 发表了文章 • 0 个评论 • 367 次浏览 • 2016-11-13 12:07 • 来自相关话题

Elasticsearch简述

ElasticSearch是现在技术前沿的大数据引擎,常见的组合有ES+Logstash+Kibana作为一套成熟的日志系统,其中Logstash是ETL工具,Kibana是数据分析展示平台。Elasticsearch让人惊艳的是他强大的搜索相关能力和灾备策略,Elastcisearch开放了一些接口供开发者研发自己的插件,Elasticsearch结合中文分词的插件会给Elasticsearch的搜索和分析起到很大的推动作用。ElasticSearch是使用开源全文检索库Apache Lucene进行索引和搜索的,所以Elasticsearch底层是依赖的Lucene。
 
关于Lucene:
Apache Lucene将写入索引的所有信息组织成一种倒排索引(Inverted Index)的结构之中,该结构是种将词项映射到文档的数据结构。其工作方式与传统的关系数据库不同,大致来说倒排索引是面向词项而不是面向文档的。且Lucene索引之中还存储了很多其他的信息,如词向量等等,每个Lucene都是由多个段构成的,每个段只会被创建一次但会被查询多次,段一旦创建就不会再被修改。多个段会在段合并的阶段合并在一起,何时合并由Lucene的内在机制决定,段合并后数量会变少,但是相应的段本身会变大。段合并的过程是非常消耗I/O的,且与之同时会有些不再使用的信息被清理掉。在Lucene中,将数据转化为倒排索引,将完整串转化为可用于搜索的词项的过程叫做分析。文本分析由分析器(Analyzer)来执行,分析其由分词器(Tokenizer),过滤器(Filter)和字符映射器(Character Mapper)组成,其各个功能显而易见。除此之外,Lucene有自己的一套完整的查询语言来帮助我们进行搜索和读写。
 
*注:Elasticsearch中的索引指的是查询/寻址时URI中的一个字段如:[host]:[port(9200)]/[index]/[type]/[ID]?[option],而Lucene中的索引更多地和ES中的分片的概念相对应。
 
Elasticsearch架构设计理念特性如下:
合理的默认配置:只需修改节点中的Yaml配置文件,就可以快速配置。这和Spring4中对配置的简化有相似的地方。分布式工作模式:Elasticsearch强大的Zen发现机制不仅支持组广播也支持点单播,且有“知一点即知天下”之妙。对等架构:节点之间自动备份分片,且使分片本身和样本之间尽量”远离“,可以避免单点故障。且Master节点和Data节点几乎完全等价。易于向集群扩充新节点:大大简化研发或运维将新节点加入集群所需的工作。不对索引中的数据结构增加任何限制:ES支持在一个索引之中存在多种数据类型。准实时:搜索和版本同步,由于ES是分布式应用,一个重大的挑战就是一致性问题,无论索引还是文档数据,然而事实证明ES表现优秀。
 

分片策略

选择合适的分片数和副本数:
ES的分片分为两种,主分片(Primary Shard)和副本(Replicas)。默认情况下,ES会为每个索引创建5个分片,即使是在单机环境下,这种冗余被称作过度分配(Over Allocation),目前看来这么做完全没有必要,仅在散布文档到分片和处理查询的过程中就增加了更多的复杂性,好在ES的优秀性能掩盖了这一点。假设一个索引由一个分片构成,那么当索引的大小超过单个节点的容量的时候,ES不能将索引分割成多份,因此必须在创建索引的时候就指定好需要的分片数量。此时我们所能做的就是创建一个新的索引,并在初始设定之中指定这个索引拥有更多的分片。反之如果过度分配,就增大了Lucene在合并分片查询结果时的复杂度,从而增大了耗时,所以我们得到了以下结论: 我们应该使用最少的分片!
 
主分片,副本和节点最大数之间数量存在以下关系:
节点数 <= 主分片数 *(副本数+1) NodeNum <= PNum * ( Rnum + 1 )这个关系,其实就是保持最好一个数据节点,最好保存一个索引的一个分片(不管主副)。
 
控制分片分配行为:
以上是在创建每个索引的时候需要考虑的优化方法,然而在索引已创建好的前提下,是否就是没有办法从分片的角度提高了性能了呢?当然不是,首先能做的是调整分片分配器的类型,具体是在elasticsearch.yml中设置cluster.routing.allocation.type属性,共有两种分片器even_shard,balanced(默认)。even_shard是尽量保证每个节点都具有相同数量的分片,balanced是基于可控制的权重进行分配,相对于前一个分配器,它更暴漏了一些参数而引入调整分配过程的能力。
 
每次ES的分片调整都是在ES上的数据分布发生了变化的时候进行的,最有代表性的就是有新的数据节点加入了集群的时候。当然调整分片的时机并不是由某个阈值触发的,ES内置十一个裁决者来决定是否触发分片调整,这里暂不赘述。另外,这些分配部署策略都是可以在运行时更新的,更多配置分片的属性也请大家自行Google。
 

路由优化

ES中所谓的路由和IP网络不同,是一个类似于Tag的东西。在创建文档的时候,可以通过字段为文档增加一个路由属性的Tag。ES内在机制决定了拥有相同路由属性的文档,一定会被分配到同一个分片上,无论是主分片还是副本。那么,在查询的过程中,一旦指定了感兴趣的路由属性,ES就可以直接到相应的分片所在的机器上进行搜索,而避免了复杂的分布式协同的一些工作,从而提升了ES的性能。于此同时,假设机器1上存有路由属性A的文档,机器2上存有路由属性为B的文档,那么我在查询的时候一旦指定目标路由属性为A,即使机器2故障瘫痪,对机器1构不成很大影响,所以这么做对灾况下的查询也提出了解决方案。所谓的路由,本质上是一个分桶(Bucketing)操作。当然,查询中也可以指定多个路由属性,机制大同小异。
 

Elasticsearch GC调优

ElasticSearch本质上是个Java程序,所以配置JVM垃圾回收器本身也是一个很有意义的工作。我们使用JVM的Xms和Xmx参数来提供指定内存大小,本质上提供的是JVM的堆空间大小,当JVM的堆空间不足的时候就会触发致命的OutOfMemoryException。这意味着要么内存不足,要么出现了内存泄露。处理GC问题,首先要确定问题的源头,一般有三种方案:
开启ElasticSearch上的GC日志 使用jstat命令生成内存Dump
第一条,在ES的配置文件elasticsearch.yml中有相关的属性可以配置,关于每个属性的用途这里当然说不完。
第二条,jstat命令可以帮助我们查看JVM堆中各个区的使用情况和GC的耗时情况。
第三条,最后的办法就是将JVM的堆空间转储到文件中去,实质上是对JVM堆空间的一个快照。

想了解更多关于JVM本身GC调优方法请参考:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html 

另外,通过修改ES节点的启动参数,也可以调整GC的方式,但是实质上和上述方法是等同的。
 

避免内存交换

这一点很简单,由于操作系统的虚拟内存页交换机制,会给性能带来障碍,如数据写满内存会写入Linux中的Swap分区。

可以通过在elasticsearch.yml文件中的bootstrap.mlockall设置为true来实现,但是需要管理员权限,需要修改操作系统的相关配置文件。
 

控制索引合并

上文提到过,ES中的分片和副本本质上都是Lucene索引,而Lucene索引又基于多个索引段构建(至少一个),索引文件中的绝大多数都是只被写一次,读多次,在Lucene内在机制控制下,当满足某种条件的时候多个索引段会被合并到一个更大的索引段,而那些旧的索引段会被抛弃并移除磁盘,这个操作叫做段合并。 

Lucene要执行段合并的理由很简单充分:索引段粒度越小,查询性能越低且耗费的内存越多。频繁的文档更改操作会导致大量的小索引段,从而导致文件句柄打开过多的问题,如修改系统配置,增大系统允许的最大文件打开数。总的来讲,当索引段由多一个合并为一个的时候,会减少索引段的数量从而提高ES性能。对于研发者来讲,我们所能做的就是选择合适的合并策略,尽管段合并完全是Lucene的任务,但随着Lucene开放更多配置借口,新版本的ES还是提供了三种合并的策略tiered,log_byte_size,log_doc。另外,ES也提供了两种Lucene索引段合并的调度器:concurrent和serial。其中各者具体区别,这里暂不赘述,只是抛砖引玉。

分享阅读原文:http://www.cnblogs.com/guguli/p/5218297.html 查看全部


Elasticsearch简述


ElasticSearch是现在技术前沿的大数据引擎,常见的组合有ES+Logstash+Kibana作为一套成熟的日志系统,其中Logstash是ETL工具,Kibana是数据分析展示平台。Elasticsearch让人惊艳的是他强大的搜索相关能力和灾备策略,Elastcisearch开放了一些接口供开发者研发自己的插件,Elasticsearch结合中文分词的插件会给Elasticsearch的搜索和分析起到很大的推动作用。ElasticSearch是使用开源全文检索库Apache Lucene进行索引和搜索的,所以Elasticsearch底层是依赖的Lucene。
 
关于Lucene:
Apache Lucene将写入索引的所有信息组织成一种倒排索引(Inverted Index)的结构之中,该结构是种将词项映射到文档的数据结构。其工作方式与传统的关系数据库不同,大致来说倒排索引是面向词项而不是面向文档的。且Lucene索引之中还存储了很多其他的信息,如词向量等等,每个Lucene都是由多个段构成的,每个段只会被创建一次但会被查询多次,段一旦创建就不会再被修改。多个段会在段合并的阶段合并在一起,何时合并由Lucene的内在机制决定,段合并后数量会变少,但是相应的段本身会变大。段合并的过程是非常消耗I/O的,且与之同时会有些不再使用的信息被清理掉。在Lucene中,将数据转化为倒排索引,将完整串转化为可用于搜索的词项的过程叫做分析。文本分析由分析器(Analyzer)来执行,分析其由分词器(Tokenizer),过滤器(Filter)和字符映射器(Character Mapper)组成,其各个功能显而易见。除此之外,Lucene有自己的一套完整的查询语言来帮助我们进行搜索和读写。
 
*注:Elasticsearch中的索引指的是查询/寻址时URI中的一个字段如:[host]:[port(9200)]/[index]/[type]/[ID]?[option],而Lucene中的索引更多地和ES中的分片的概念相对应。
 
Elasticsearch架构设计理念特性如下:
  1. 合理的默认配置:只需修改节点中的Yaml配置文件,就可以快速配置。这和Spring4中对配置的简化有相似的地方。
  2. 分布式工作模式:Elasticsearch强大的Zen发现机制不仅支持组广播也支持点单播,且有“知一点即知天下”之妙。
  3. 对等架构:节点之间自动备份分片,且使分片本身和样本之间尽量”远离“,可以避免单点故障。且Master节点和Data节点几乎完全等价。
  4. 易于向集群扩充新节点:大大简化研发或运维将新节点加入集群所需的工作。
  5. 不对索引中的数据结构增加任何限制:ES支持在一个索引之中存在多种数据类型。
  6. 准实时:搜索和版本同步,由于ES是分布式应用,一个重大的挑战就是一致性问题,无论索引还是文档数据,然而事实证明ES表现优秀。

 


分片策略


选择合适的分片数和副本数:
ES的分片分为两种,主分片(Primary Shard)和副本(Replicas)。默认情况下,ES会为每个索引创建5个分片,即使是在单机环境下,这种冗余被称作过度分配(Over Allocation),目前看来这么做完全没有必要,仅在散布文档到分片和处理查询的过程中就增加了更多的复杂性,好在ES的优秀性能掩盖了这一点。假设一个索引由一个分片构成,那么当索引的大小超过单个节点的容量的时候,ES不能将索引分割成多份,因此必须在创建索引的时候就指定好需要的分片数量。此时我们所能做的就是创建一个新的索引,并在初始设定之中指定这个索引拥有更多的分片。反之如果过度分配,就增大了Lucene在合并分片查询结果时的复杂度,从而增大了耗时,所以我们得到了以下结论: 我们应该使用最少的分片!
 
主分片,副本和节点最大数之间数量存在以下关系:
节点数 <= 主分片数 *(副本数+1)    NodeNum <= PNum * ( Rnum + 1 )
这个关系,其实就是保持最好一个数据节点,最好保存一个索引的一个分片(不管主副)。
 
控制分片分配行为:
以上是在创建每个索引的时候需要考虑的优化方法,然而在索引已创建好的前提下,是否就是没有办法从分片的角度提高了性能了呢?当然不是,首先能做的是调整分片分配器的类型,具体是在elasticsearch.yml中设置cluster.routing.allocation.type属性,共有两种分片器even_shard,balanced(默认)。even_shard是尽量保证每个节点都具有相同数量的分片,balanced是基于可控制的权重进行分配,相对于前一个分配器,它更暴漏了一些参数而引入调整分配过程的能力。
 
每次ES的分片调整都是在ES上的数据分布发生了变化的时候进行的,最有代表性的就是有新的数据节点加入了集群的时候。当然调整分片的时机并不是由某个阈值触发的,ES内置十一个裁决者来决定是否触发分片调整,这里暂不赘述。另外,这些分配部署策略都是可以在运行时更新的,更多配置分片的属性也请大家自行Google。
 


路由优化


ES中所谓的路由和IP网络不同,是一个类似于Tag的东西。在创建文档的时候,可以通过字段为文档增加一个路由属性的Tag。ES内在机制决定了拥有相同路由属性的文档,一定会被分配到同一个分片上,无论是主分片还是副本。那么,在查询的过程中,一旦指定了感兴趣的路由属性,ES就可以直接到相应的分片所在的机器上进行搜索,而避免了复杂的分布式协同的一些工作,从而提升了ES的性能。于此同时,假设机器1上存有路由属性A的文档,机器2上存有路由属性为B的文档,那么我在查询的时候一旦指定目标路由属性为A,即使机器2故障瘫痪,对机器1构不成很大影响,所以这么做对灾况下的查询也提出了解决方案。所谓的路由,本质上是一个分桶(Bucketing)操作。当然,查询中也可以指定多个路由属性,机制大同小异。
 


Elasticsearch GC调优


ElasticSearch本质上是个Java程序,所以配置JVM垃圾回收器本身也是一个很有意义的工作。我们使用JVM的Xms和Xmx参数来提供指定内存大小,本质上提供的是JVM的堆空间大小,当JVM的堆空间不足的时候就会触发致命的OutOfMemoryException。这意味着要么内存不足,要么出现了内存泄露。处理GC问题,首先要确定问题的源头,一般有三种方案:
  1. 开启ElasticSearch上的GC日志
  2.  使用jstat命令
  3. 生成内存Dump

第一条,在ES的配置文件elasticsearch.yml中有相关的属性可以配置,关于每个属性的用途这里当然说不完。
第二条,jstat命令可以帮助我们查看JVM堆中各个区的使用情况和GC的耗时情况。
第三条,最后的办法就是将JVM的堆空间转储到文件中去,实质上是对JVM堆空间的一个快照。

想了解更多关于JVM本身GC调优方法请参考:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html 

另外,通过修改ES节点的启动参数,也可以调整GC的方式,但是实质上和上述方法是等同的。
 


避免内存交换


这一点很简单,由于操作系统的虚拟内存页交换机制,会给性能带来障碍,如数据写满内存会写入Linux中的Swap分区。

可以通过在elasticsearch.yml文件中的bootstrap.mlockall设置为true来实现,但是需要管理员权限,需要修改操作系统的相关配置文件。
 


控制索引合并


上文提到过,ES中的分片和副本本质上都是Lucene索引,而Lucene索引又基于多个索引段构建(至少一个),索引文件中的绝大多数都是只被写一次,读多次,在Lucene内在机制控制下,当满足某种条件的时候多个索引段会被合并到一个更大的索引段,而那些旧的索引段会被抛弃并移除磁盘,这个操作叫做段合并。 

Lucene要执行段合并的理由很简单充分:索引段粒度越小,查询性能越低且耗费的内存越多。频繁的文档更改操作会导致大量的小索引段,从而导致文件句柄打开过多的问题,如修改系统配置,增大系统允许的最大文件打开数。总的来讲,当索引段由多一个合并为一个的时候,会减少索引段的数量从而提高ES性能。对于研发者来讲,我们所能做的就是选择合适的合并策略,尽管段合并完全是Lucene的任务,但随着Lucene开放更多配置借口,新版本的ES还是提供了三种合并的策略tiered,log_byte_size,log_doc。另外,ES也提供了两种Lucene索引段合并的调度器:concurrent和serial。其中各者具体区别,这里暂不赘述,只是抛砖引玉。


分享阅读原文:http://www.cnblogs.com/guguli/p/5218297.html


ElasticsearchIllegalArgumentException 错误

大数据/云计算采菊篱下 回复了问题 • 2 人关注 • 1 个回复 • 220 次浏览 • 2016-11-08 19:47 • 来自相关话题

Elasticsearch的UNASSIGNED shareds怎么恢复?

大数据/云计算采菊篱下 回复了问题 • 2 人关注 • 2 个回复 • 233 次浏览 • 2016-11-08 10:54 • 来自相关话题

条新动态, 点击查看
采菊篱下

采菊篱下 回答了问题 • 2015-10-18 20:19 • 2 个回复 不感兴趣

Hadoop可以运行单机模式吗?

赞同来自:

可以的,hadoop可以运行如下三种模式:

单机模式
伪分布式模式
全分布式模式
可以的,hadoop可以运行如下三种模式:

单机模式
伪分布式模式
全分布式模式

CDH Hadoop + HBase HA 部署详解

大数据/云计算采菊篱下 发表了文章 • 0 个评论 • 314 次浏览 • 2016-11-07 21:07 • 来自相关话题

CDH 的部署和 Apache Hadoop 的部署是没有任何区别的。这里着重的是 HA的部署,需要特殊说明的是NameNode HA 需要依赖 Zookeeper
 

准备

Hosts文件配置:
cat > /etc/hosts << _HOSTS_
127.0.0.1 localhost
10.0.2.59 cdh-m1
10.0.2.60 cdh-m2
10.0.2.61 cdh-s1
_HOSTS_各个节点服务情况
cdh-m1 Zookeeper JournalNode NameNode DFSZKFailoverController HMaster
cdh-m2 Zookeeper JournalNode NameNode DFSZKFailoverController HMaster
cdh-s1 Zookeeper JournalNode DataNode HRegionServer对几个新服务说明下: 
JournalNode 用于同步 NameNode 元数据,和 Zookeeper 一样需要 2N+1个节点存活集群才可用。DFSZKFailoverController(ZKFC) 用于主备切换,类似 Keepalived 所扮演的角色。
 
NTP 服务
设置时区
rm -f /etc/localtime
ln -s /usr/share/zoneinfo/UTC /etc/localtime配置NTP Server
yum install -y ntp
cat > /etc/ntp.conf << _NTP_
driftfile /var/lib/ntp/drift

restrict default nomodify
restrict -6 default nomodify

server cn.ntp.org.cn prefer
server news.neu.edu.cn iburst
server dns.sjtu.edu.cn iburst
server 127.127.1.1 iburst

tinker dispersion 100
tinker step 1800
tinker stepout 3600
includefile /etc/ntp/crypto/pw

keys /etc/ntp/keys
_NTP_

# NTP启动时立即同步
cat >> /etc/ntp/step-tickers << _NTP_
server cn.ntp.org.cn prefer
server news.neu.edu.cn iburst
server dns.sjtu.edu.cn iburst
_NTP_

# 同步硬件时钟
cat >> /etc/sysconfig/ntpd << _NTPHW_
SYNC_HWCLOCK=yes
_NTPHW_启动并设置开机自启动
/etc/init.d/ntpd start
chkconfig ntpd on配置 NTP Client
yum install -y ntp
# 注意修改内网NTP Server地址
cat > /etc/ntp.conf << _NTP_
driftfile /var/lib/ntp/drift

restrict default nomodify
restrict -6 default nomodify

restrict 127.0.0.1
restrict -6 ::1

server 10.0.2.59 prefer

tinker dispersion 100
tinker step 1800
tinker stepout 3600
includefile /etc/ntp/crypto/pw

keys /etc/ntp/keys
_NTP_

# NTP启动时立即同步
cat >> /etc/ntp/step-tickers << _NTP_
server 10.0.2.59 prefer
_NTP_

# 同步硬件时钟
cat >> /etc/sysconfig/ntpd << _NTPHW_
SYNC_HWCLOCK=yes
_NTPHW_启动并设置开机自启动
/etc/init.d/ntpd start
chkconfig ntpd on检查 NTP 同步
ntpq -p

# 结果
remote refid st t when poll reach delay offset jitter
==============================================================================
*time7.aliyun.co 10.137.38.86 2 u 17 64 3 44.995 5.178 0.177
news.neu.edu.cn .INIT. 16 u - 64 0 0.000 0.000 0.000
202.120.2.90 .INIT. 16 u - 64 0 0.000 0.000 0.000JDK
创建目录
mkdir -p /data/{install,app,logs,pid,appData}
mkdir /data/appData/tmpcd /data/install
wget -c http://oracle.com/jdk-7u51-linux-x64.gz
tar xf jdk-7u51-linux-x64.gz -C /data/app
cd /data/app
ln -s jdk1.7.0_51 jdk1.7
cat >> /etc/profile << _PATH_
export JAVA_HOME=/data/app/jdk1.7
export CLASSPATH=.:\$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar
export PATH=\$JAVA_HOME/bin:\$PATH
_PATH_
source /etc/profile
创建运行账户
useradd -u 600 run安装包
http://archive.cloudera.com/cdh5/cdh/5/
cd /data/install
wget -c http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.4.5.tar.gz
wget -c http://archive.apache.org/dist/zookeeper/zookeeper-3.4.5/zookeeper-3.4.5.tar.gz
wget -c http://archive.cloudera.com/cdh5/cdh/5/hbase-1.0.0-cdh5.4.5.tar.gz

安装 Zookeeper

cd /data/install
tar xf zookeeper-3.4.5.tar.gz -C /data/app
cd /data/app
ln -s zookeeper-3.4.5 zookeeper设置环境变量
sed -i '/^export PATH=/i\export ZOOKEEPER_HOME=/data/app/zookeeper' /etc/profile
sed -i 's#export PATH=#&\$ZOOKEEPER_HOME/bin:#' /etc/profile
source /etc/profile删除无用文件
cd $ZOOKEEPER_HOME
rm -rf *xml *txt zookeeper-3.4.5.jar.* src recipes docs dist-maven contrib
rm -f $ZOOKEEPER_HOME/bin/*.cmd $ZOOKEEPER_HOME/bin/*.txt
rm -f $ZOOKEEPER_HOME/conf/zoo_sample.cfg创建数据目录
mkdir -p /data/appData/zookeeper/{data,logs}配置
cat > $ZOOKEEPER_HOME/conf/zoo.cfg << _ZOO_
tickTime=2000
initLimit=10
syncLimit=5
clientPort=2181
dataDir=/data/appData/zookeeper/data
dataLogDir=/data/appData/zookeeper/logs
server.1=cdh-m1:2888:3888
server.2=cdh-m2:2888:3888
server.3=cdh-s1:2888:3888
_ZOO_修改Zookeeper的日志打印方式,与日志路径设置
编辑
$ZOOKEEPER_HOME/bin/zkEnv.sh在27行后加入两个变量
ZOO_LOG_DIR=/data/logs/zookeeper
ZOO_LOG4J_PROP="INFO,ROLLINGFILE"创建 myid文件
# 注意myid与配置文件保持一致
echo 1 >/data/appData/zookeeper/data/myid设置目录权限
chown -R run.run /data/{app,appData,logs}启动、停止
# 启动
runuser - run -c 'zkServer.sh start'
# 停止
runuser - run -c 'zkServer.sh stop'

安装 Hadoop

tar xf hadoop-2.6.0-cdh5.4.5.tar.gz -C /data/app
cd /data/app
ln -s hadoop-2.6.0-cdh5.4.5 hadoop设置环境变量
sed -i '/^export PATH=/i\export HADOOP_HOME=/data/app/hadoop' /etc/profile
sed -i 's#export PATH=#&\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin:#' /etc/profile
source /etc/profile删除无用文件
cd $HADOOP_HOME
rm -rf *txt share/doc src examples* include bin-mapreduce1 cloudera
find . -name "*.cmd"|xargs rm -f新建数据目录
mkdir -p /data/appData/hdfs/{name,edits,data,jn,tmp}配置
切换到配置文件目录
cd $HADOOP_HOME/etc/hadoop编辑 core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- HDFS 集群名称,可指定端口 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://hdfs-cdh</value>
</property>

<!-- 临时文件目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/data/appData/hdfs/tmp</value>
</property>

<!-- 回收站设置,0不启用回收站,1440 表示1440分钟后删除 -->
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>

<!-- SequenceFiles在读写中可以使用的缓存大小,单位 bytes 默认 4096 -->
<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>

<!-- 可用压缩算法,启用在hdfs-site.xml中,需要编译动态链接库才能用 -->
<property>
<name>io.compression.codecs</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>
</configuration>编辑 hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 指定hdfs 集群名称,需要和core-site.xml中的保持一致 -->
<property>
<name>dfs.nameservices</name>
<value>hdfs-cdh</value>
</property>

<!-- 指定 Zookeeper 用于NameNode HA,默认官方配置在core-site.xml中,为了查看清晰配置到hdfs-site.xml也是可用的 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>cdh-m1:2181,cdh-m2:2181,cdh-s1:2181</value>
</property>

<!-- hdfs-cdh 下有两个NameNode,分别为 nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.hdfs-cdh</name>
<value>nn1,nn2</value>
</property>

<!-- nn1 RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.hdfs-cdh.nn1</name>
<value>cdh-m1:9000</value>
</property>

<!-- nn1 HTTP通信地址 -->
<property>
<name>dfs.namenode.http-address.hdfs-cdh.nn1</name>
<value>cdh-m1:50070</value>
</property>

<!-- nn2 RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.hdfs-cdh.nn2</name>
<value>cdh-m2:9000</value>
</property>

<!-- nn2 HTTP通信地址 -->
<property>
<name>dfs.namenode.http-address.hdfs-cdh.nn2</name>
<value>cdh-m2:50070</value>
</property>

<!-- 指定NameNode元数据在JournalNode上的存储路径 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://cdh-m1:8485;cdh-m2:8485;cdh-s1:8485;/hdfs-cdh</value>
</property>

<!-- 开启NameNode失败自动切换 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>

<!-- 配置主备切换实现方式 -->
<property>
<name>dfs.client.failover.proxy.provider.hdfs-cdh</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

<!-- 配置主备切换方法,每个方法一行-->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>

<!-- 指定运行用户的秘钥,需要NameNode双向免密码登录,用于主备自动切换 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/run/.ssh/id_rsa</value>
</property>

<!-- 配置sshfence 超时时间 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>50000</value>
</property>

<!-- NameNode 数据本地存储路径 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>/data/appData/hdfs/name</value>
</property>

<!-- DataNode 数据本地存储路径 -->
<property>
<name>dfs.datanode.data.dir</name>
<value>/data/appData/hdfs/data</value>
</property>

<!-- JournalNode 数据本地存储路径 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/data/appData/hdfs/jn</value>
</property>

<!-- 修改文件存储到edits,定期同步到DataNode -->
<property>
<name>dfs.namenode.edits.noeditlogchannelflush</name>
<value>true</value>
</property>

<!-- edits 数据本地存储路径 -->
<property>
<name>dfs.namenode.edits.dir</name>
<value>/data/appData/hdfs/edits</value>
</property>

<!-- 开启Block Location metadata允许impala知道数据块在哪块磁盘上 默认关闭 -->
<property>
<name>dfs.datanode.hdfs-blocks-metadata.enabled</name>
<value>true</value>
</property>

<!-- 权限检查 默认开启 -->
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>

<!-- block 大小设置 -->
<property>
<name>dfs.blocksize</name>
<value>64m</value>
</property>
</configuration>小于5个DataNode建议添加如下配置
<!-- 数据副本数量,不能超过DataNode数量,大集群建议使用默认值 默认 3 -->
<property>
<name>dfs.replication</name>
<value>2</value>
</property>

<!-- 当副本写入失败时不分配新节点,小集群适用 -->
<property>
<name>dfs.client.block.write.replace-datanode-on-failure.policy</name>
<value>NEVER</value>
</property>在 hadoop-env.sh 中添加如下变量
export JAVA_HOME=/data/app/jdk1.7
export HADOOP_LOG_DIR=/data/logs/hadoop
export HADOOP_PID_DIR=/data/pid
# SSH端口 可选
export HADOOP_SSH_OPTS="-p 36000"Heap 设置,单位 MB
export HADOOP_HEAPSIZE=1024权限设置
chown -R run.run /data/{app,appData,logs}
chmod 777 /data/pid格式化
格式化只需要执行一次,格式化之前启动Zookeeper
 
切换用户
su - run启动所有 JournalNode
hadoop-daemon.sh start journalnode格式化 Zookeeper(为 ZKFC 创建znode)
hdfs zkfc -formatZKNameNode 主节点格式化并启动
hdfs namenode -format
hadoop-daemon.sh start namenodeNameNode 备节点同步数据并启动
hdfs namenode -bootstrapStandby
hadoop-daemon.sh start namenode启动 ZKFC
hadoop-daemon.sh start zkfc启动 DataNode
hadoop-daemon.sh start datanode启动与停止
切换用户
su - run集群批量启动
需要配置运行用户ssh-key免密码登录,与$HADOOP_HOME/etc/hadoop/slaves
# 启动
start-dfs.sh
# 停止
stop-dfs.sh单服务启动停止
启动HDFS
hadoop-daemon.sh start journalnode
hadoop-daemon.sh start namenode
hadoop-daemon.sh start zkfc
hadoop-daemon.sh start datanode停止HDFS
hadoop-daemon.sh stop datanode
hadoop-daemon.sh stop namenode
hadoop-daemon.sh stop journalnode
hadoop-daemon.sh stop zkfc
测试
HDFS HA 测试
打开 NameNode 状态页:
http://cdh-m1:50010
http://cdh-m2:50010 

在 Overview 后面能看见 active 或 standby,active 为当前 Master,停止 active 上的 NameNode,检查 standby是否为 active。
 
HDFS 测试
hadoop fs -mkdir /test
hadoop fs -put /etc/hosts /test
hadoop fs -ls /test结果:
-rw-r--r-- 2 java supergroup 89 2016-06-15 10:30 /test/hosts
# 其中权限后面的列(这里的2)代表文件总数,即副本数量。HDFS 管理命令
# 动态加载 hdfs-site.xml
hadoop dfsadmin -refreshNodes

HBase安装配置

cd /data/install
tar xf hbase-1.0.0-cdh5.4.5.tar.gz -C /data/app
cd /data/app
ln -s hbase-1.0.0-cdh5.4.5 hbase设置环境变量
sed -i '/^export PATH=/i\export HBASE_HOME=/data/app/hbase' /etc/profile
sed -i 's#export PATH=#&\$HBASE_HOME/bin:#' /etc/profile
source /etc/profile删除无用文件
cd $HBASE_HOME
rm -rf *.txt pom.xml src docs cloudera dev-support hbase-annotations hbase-assembly hbase-checkstyle hbase-client hbase-common hbase-examples hbase-hadoop2-compat hbase-hadoop-compat hbase-it hbase-prefix-tree hbase-protocol hbase-rest hbase-server hbase-shell hbase-testing-util hbase-thrift
find . -name "*.cmd"|xargs rm -f配置
进入配置文件目录
cd $HBASE_HOME/conf编辑 hbase-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- HBase 数据存储路径 -->
<property>
<name>hbase.rootdir</name>
<value>hdfs://hdfs-cdh/hbase</value>
</property>

<!-- 完全分布式模式 -->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>

<!-- HMaster 节点 -->
<property>
<name>hbase.master</name>
<value>cdh-m1:60000,cdh-m2:60000</value>
</property>

<!-- Zookeeper 节点 -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>cdh-m1:2181,cdh-m2:2181,cdh-s1:2181</value>
</property>

<!-- znode 路径,Zookeeper集群中有多个HBase集群需要设置不同znode -->
<property>
<name>zookeeper.znode.parent</name>
<value>/hbase</value>
</property>

<!-- HBase 协处理器 -->
<property>
<name>hbase.coprocessor.user.region.classes</name>
<value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>
</property>
</configuration>在 hbase-env.sh 中添加如下变量
export JAVA_HOME=/data/app/jdk1.7
export HBASE_LOG_DIR=/data/logs/hbase
export HBASE_PID_DIR=/data/pid
export HBASE_MANAGES_ZK=false
# SSH 默认端口 可选
export HBASE_SSH_OPTS="-o ConnectTimeout=1 -p 36000"Heap 设置,单位 MB
export HBASE_HEAPSIZE=1024可选设置 regionservers 中添加所有RegionServer主机名,用于集群批量启动、停止
 
启动与停止
切换用户
su - run集群批量启动
需要配置运行用户ssh-key免密码登录,与$HBASE_HOME/conf/regionservers
# 启动
start-hbase.sh
# 停止
stop-hbase.sh单服务启动停止
HMaster
# 启动
hbase-daemon.sh start master
# 停止
hbase-daemon.sh stop masterHRegionServer
# 启动
hbase-daemon.sh start regionserver
# 停止
hbase-daemon.sh stop regionserver
测试
HBase HA 测试
浏览器打开两个HMaster状态页:
http://cdh-m1:60010
http://cdh-m2:60010 

可以在Master后面看见其中一个主机名,Backup Masters中看见另一个。
停止当前Master,刷新另一个HMaster状态页会发现Master后面已经切换,HA成功。
 
HBase 测试
进入hbase shell 执行:
create 'users','user_id','address','info'
list
put 'users','anton','info:age','24'
get 'users','anton'

# 最终结果
COLUMN CELL
info:age timestamp=1465972035945, value=24
1 row(s) in 0.0170 seconds清除测试数据:
disable 'users'
drop 'users'到这里安装就全部完成,不懂的地方可以留言交流! 查看全部
hadoop.jpg

CDH 的部署和 Apache Hadoop 的部署是没有任何区别的。这里着重的是 HA的部署,需要特殊说明的是NameNode HA 需要依赖 Zookeeper
 


准备


Hosts文件配置:
cat > /etc/hosts << _HOSTS_
127.0.0.1 localhost
10.0.2.59 cdh-m1
10.0.2.60 cdh-m2
10.0.2.61 cdh-s1
_HOSTS_
各个节点服务情况
cdh-m1 Zookeeper JournalNode NameNode DFSZKFailoverController HMaster
cdh-m2 Zookeeper JournalNode NameNode DFSZKFailoverController HMaster
cdh-s1 Zookeeper JournalNode DataNode HRegionServer
对几个新服务说明下: 
  • JournalNode 用于同步 NameNode 元数据,和 Zookeeper 一样需要 2N+1个节点存活集群才可用。
  • DFSZKFailoverController(ZKFC) 用于主备切换,类似 Keepalived 所扮演的角色。

 
NTP 服务
设置时区
rm -f /etc/localtime
ln -s /usr/share/zoneinfo/UTC /etc/localtime
配置NTP Server
yum install -y ntp
cat > /etc/ntp.conf << _NTP_
driftfile /var/lib/ntp/drift

restrict default nomodify
restrict -6 default nomodify

server cn.ntp.org.cn prefer
server news.neu.edu.cn iburst
server dns.sjtu.edu.cn iburst
server 127.127.1.1 iburst

tinker dispersion 100
tinker step 1800
tinker stepout 3600
includefile /etc/ntp/crypto/pw

keys /etc/ntp/keys
_NTP_

# NTP启动时立即同步
cat >> /etc/ntp/step-tickers << _NTP_
server cn.ntp.org.cn prefer
server news.neu.edu.cn iburst
server dns.sjtu.edu.cn iburst
_NTP_

# 同步硬件时钟
cat >> /etc/sysconfig/ntpd << _NTPHW_
SYNC_HWCLOCK=yes
_NTPHW_
启动并设置开机自启动
/etc/init.d/ntpd start
chkconfig ntpd on
配置 NTP Client
yum install -y ntp
# 注意修改内网NTP Server地址
cat > /etc/ntp.conf << _NTP_
driftfile /var/lib/ntp/drift

restrict default nomodify
restrict -6 default nomodify

restrict 127.0.0.1
restrict -6 ::1

server 10.0.2.59 prefer

tinker dispersion 100
tinker step 1800
tinker stepout 3600
includefile /etc/ntp/crypto/pw

keys /etc/ntp/keys
_NTP_

# NTP启动时立即同步
cat >> /etc/ntp/step-tickers << _NTP_
server 10.0.2.59 prefer
_NTP_

# 同步硬件时钟
cat >> /etc/sysconfig/ntpd << _NTPHW_
SYNC_HWCLOCK=yes
_NTPHW_
启动并设置开机自启动
/etc/init.d/ntpd start
chkconfig ntpd on
检查 NTP 同步
ntpq -p

# 结果
remote refid st t when poll reach delay offset jitter
==============================================================================
*time7.aliyun.co 10.137.38.86 2 u 17 64 3 44.995 5.178 0.177
news.neu.edu.cn .INIT. 16 u - 64 0 0.000 0.000 0.000
202.120.2.90 .INIT. 16 u - 64 0 0.000 0.000 0.000
JDK
创建目录
mkdir -p /data/{install,app,logs,pid,appData}
mkdir /data/appData/tmp
cd /data/install
wget -c http://oracle.com/jdk-7u51-linux-x64.gz
tar xf jdk-7u51-linux-x64.gz -C /data/app
cd /data/app
ln -s jdk1.7.0_51 jdk1.7
cat >> /etc/profile << _PATH_
export JAVA_HOME=/data/app/jdk1.7
export CLASSPATH=.:\$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar
export PATH=\$JAVA_HOME/bin:\$PATH
_PATH_
source /etc/profile

创建运行账户
useradd -u 600 run
安装包
http://archive.cloudera.com/cdh5/cdh/5/
cd /data/install
wget -c http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.4.5.tar.gz
wget -c http://archive.apache.org/dist/zookeeper/zookeeper-3.4.5/zookeeper-3.4.5.tar.gz
wget -c http://archive.cloudera.com/cdh5/cdh/5/hbase-1.0.0-cdh5.4.5.tar.gz


安装 Zookeeper


cd /data/install
tar xf zookeeper-3.4.5.tar.gz -C /data/app
cd /data/app
ln -s zookeeper-3.4.5 zookeeper
设置环境变量
sed -i '/^export PATH=/i\export ZOOKEEPER_HOME=/data/app/zookeeper' /etc/profile
sed -i 's#export PATH=#&\$ZOOKEEPER_HOME/bin:#' /etc/profile
source /etc/profile
删除无用文件
cd $ZOOKEEPER_HOME
rm -rf *xml *txt zookeeper-3.4.5.jar.* src recipes docs dist-maven contrib
rm -f $ZOOKEEPER_HOME/bin/*.cmd $ZOOKEEPER_HOME/bin/*.txt
rm -f $ZOOKEEPER_HOME/conf/zoo_sample.cfg
创建数据目录
mkdir -p /data/appData/zookeeper/{data,logs}
配置
cat > $ZOOKEEPER_HOME/conf/zoo.cfg << _ZOO_
tickTime=2000
initLimit=10
syncLimit=5
clientPort=2181
dataDir=/data/appData/zookeeper/data
dataLogDir=/data/appData/zookeeper/logs
server.1=cdh-m1:2888:3888
server.2=cdh-m2:2888:3888
server.3=cdh-s1:2888:3888
_ZOO_
修改Zookeeper的日志打印方式,与日志路径设置
编辑
$ZOOKEEPER_HOME/bin/zkEnv.sh
在27行后加入两个变量
ZOO_LOG_DIR=/data/logs/zookeeper
ZOO_LOG4J_PROP="INFO,ROLLINGFILE"
创建 myid文件
# 注意myid与配置文件保持一致
echo 1 >/data/appData/zookeeper/data/myid
设置目录权限
chown -R run.run /data/{app,appData,logs}
启动、停止
# 启动
runuser - run -c 'zkServer.sh start'
# 停止
runuser - run -c 'zkServer.sh stop'


安装 Hadoop


tar xf hadoop-2.6.0-cdh5.4.5.tar.gz -C /data/app
cd /data/app
ln -s hadoop-2.6.0-cdh5.4.5 hadoop
设置环境变量
sed -i '/^export PATH=/i\export HADOOP_HOME=/data/app/hadoop' /etc/profile
sed -i 's#export PATH=#&\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin:#' /etc/profile
source /etc/profile
删除无用文件
cd $HADOOP_HOME
rm -rf *txt share/doc src examples* include bin-mapreduce1 cloudera
find . -name "*.cmd"|xargs rm -f
新建数据目录
mkdir -p /data/appData/hdfs/{name,edits,data,jn,tmp}
配置
切换到配置文件目录
cd $HADOOP_HOME/etc/hadoop
编辑 core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- HDFS 集群名称,可指定端口 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://hdfs-cdh</value>
</property>

<!-- 临时文件目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/data/appData/hdfs/tmp</value>
</property>

<!-- 回收站设置,0不启用回收站,1440 表示1440分钟后删除 -->
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>

<!-- SequenceFiles在读写中可以使用的缓存大小,单位 bytes 默认 4096 -->
<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>

<!-- 可用压缩算法,启用在hdfs-site.xml中,需要编译动态链接库才能用 -->
<property>
<name>io.compression.codecs</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>
</configuration>
编辑 hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- 指定hdfs 集群名称,需要和core-site.xml中的保持一致 -->
<property>
<name>dfs.nameservices</name>
<value>hdfs-cdh</value>
</property>

<!-- 指定 Zookeeper 用于NameNode HA,默认官方配置在core-site.xml中,为了查看清晰配置到hdfs-site.xml也是可用的 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>cdh-m1:2181,cdh-m2:2181,cdh-s1:2181</value>
</property>

<!-- hdfs-cdh 下有两个NameNode,分别为 nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.hdfs-cdh</name>
<value>nn1,nn2</value>
</property>

<!-- nn1 RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.hdfs-cdh.nn1</name>
<value>cdh-m1:9000</value>
</property>

<!-- nn1 HTTP通信地址 -->
<property>
<name>dfs.namenode.http-address.hdfs-cdh.nn1</name>
<value>cdh-m1:50070</value>
</property>

<!-- nn2 RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.hdfs-cdh.nn2</name>
<value>cdh-m2:9000</value>
</property>

<!-- nn2 HTTP通信地址 -->
<property>
<name>dfs.namenode.http-address.hdfs-cdh.nn2</name>
<value>cdh-m2:50070</value>
</property>

<!-- 指定NameNode元数据在JournalNode上的存储路径 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://cdh-m1:8485;cdh-m2:8485;cdh-s1:8485;/hdfs-cdh</value>
</property>

<!-- 开启NameNode失败自动切换 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>

<!-- 配置主备切换实现方式 -->
<property>
<name>dfs.client.failover.proxy.provider.hdfs-cdh</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

<!-- 配置主备切换方法,每个方法一行-->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>

<!-- 指定运行用户的秘钥,需要NameNode双向免密码登录,用于主备自动切换 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/run/.ssh/id_rsa</value>
</property>

<!-- 配置sshfence 超时时间 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>50000</value>
</property>

<!-- NameNode 数据本地存储路径 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>/data/appData/hdfs/name</value>
</property>

<!-- DataNode 数据本地存储路径 -->
<property>
<name>dfs.datanode.data.dir</name>
<value>/data/appData/hdfs/data</value>
</property>

<!-- JournalNode 数据本地存储路径 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/data/appData/hdfs/jn</value>
</property>

<!-- 修改文件存储到edits,定期同步到DataNode -->
<property>
<name>dfs.namenode.edits.noeditlogchannelflush</name>
<value>true</value>
</property>

<!-- edits 数据本地存储路径 -->
<property>
<name>dfs.namenode.edits.dir</name>
<value>/data/appData/hdfs/edits</value>
</property>

<!-- 开启Block Location metadata允许impala知道数据块在哪块磁盘上 默认关闭 -->
<property>
<name>dfs.datanode.hdfs-blocks-metadata.enabled</name>
<value>true</value>
</property>

<!-- 权限检查 默认开启 -->
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>

<!-- block 大小设置 -->
<property>
<name>dfs.blocksize</name>
<value>64m</value>
</property>
</configuration>
小于5个DataNode建议添加如下配置
<!-- 数据副本数量,不能超过DataNode数量,大集群建议使用默认值 默认 3 -->
<property>
<name>dfs.replication</name>
<value>2</value>
</property>

<!-- 当副本写入失败时不分配新节点,小集群适用 -->
<property>
<name>dfs.client.block.write.replace-datanode-on-failure.policy</name>
<value>NEVER</value>
</property>
在 hadoop-env.sh 中添加如下变量
export JAVA_HOME=/data/app/jdk1.7
export HADOOP_LOG_DIR=/data/logs/hadoop
export HADOOP_PID_DIR=/data/pid
# SSH端口 可选
export HADOOP_SSH_OPTS="-p 36000"
Heap 设置,单位 MB
export HADOOP_HEAPSIZE=1024
权限设置
chown -R run.run /data/{app,appData,logs}
chmod 777 /data/pid
格式化
格式化只需要执行一次,格式化之前启动Zookeeper
 
切换用户
su - run
启动所有 JournalNode
hadoop-daemon.sh start journalnode
格式化 Zookeeper(为 ZKFC 创建znode)
hdfs zkfc -formatZK
NameNode 主节点格式化并启动
hdfs namenode -format
hadoop-daemon.sh start namenode
NameNode 备节点同步数据并启动
hdfs namenode -bootstrapStandby
hadoop-daemon.sh start namenode
启动 ZKFC
hadoop-daemon.sh start zkfc
启动 DataNode
hadoop-daemon.sh start datanode
启动与停止
切换用户
su - run
集群批量启动
需要配置运行用户ssh-key免密码登录,与$HADOOP_HOME/etc/hadoop/slaves
# 启动
start-dfs.sh
# 停止
stop-dfs.sh
单服务启动停止
启动HDFS
hadoop-daemon.sh start journalnode
hadoop-daemon.sh start namenode
hadoop-daemon.sh start zkfc
hadoop-daemon.sh start datanode
停止HDFS
hadoop-daemon.sh stop datanode
hadoop-daemon.sh stop namenode
hadoop-daemon.sh stop journalnode
hadoop-daemon.sh stop zkfc

测试
HDFS HA 测试
打开 NameNode 状态页:
http://cdh-m1:50010
http://cdh-m2:50010 

在 Overview 后面能看见 active 或 standby,active 为当前 Master,停止 active 上的 NameNode,检查 standby是否为 active。
 
HDFS 测试
hadoop fs -mkdir /test
hadoop fs -put /etc/hosts /test
hadoop fs -ls /test
结果:
-rw-r--r--   2 java supergroup         89 2016-06-15 10:30 /test/hosts
# 其中权限后面的列(这里的2)代表文件总数,即副本数量。
HDFS 管理命令
# 动态加载 hdfs-site.xml
hadoop dfsadmin -refreshNodes


HBase安装配置


cd /data/install
tar xf hbase-1.0.0-cdh5.4.5.tar.gz -C /data/app
cd /data/app
ln -s hbase-1.0.0-cdh5.4.5 hbase
设置环境变量
sed -i '/^export PATH=/i\export HBASE_HOME=/data/app/hbase' /etc/profile
sed -i 's#export PATH=#&\$HBASE_HOME/bin:#' /etc/profile
source /etc/profile
删除无用文件
cd $HBASE_HOME
rm -rf *.txt pom.xml src docs cloudera dev-support hbase-annotations hbase-assembly hbase-checkstyle hbase-client hbase-common hbase-examples hbase-hadoop2-compat hbase-hadoop-compat hbase-it hbase-prefix-tree hbase-protocol hbase-rest hbase-server hbase-shell hbase-testing-util hbase-thrift
find . -name "*.cmd"|xargs rm -f
配置
进入配置文件目录
cd $HBASE_HOME/conf
编辑 hbase-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- HBase 数据存储路径 -->
<property>
<name>hbase.rootdir</name>
<value>hdfs://hdfs-cdh/hbase</value>
</property>

<!-- 完全分布式模式 -->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>

<!-- HMaster 节点 -->
<property>
<name>hbase.master</name>
<value>cdh-m1:60000,cdh-m2:60000</value>
</property>

<!-- Zookeeper 节点 -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>cdh-m1:2181,cdh-m2:2181,cdh-s1:2181</value>
</property>

<!-- znode 路径,Zookeeper集群中有多个HBase集群需要设置不同znode -->
<property>
<name>zookeeper.znode.parent</name>
<value>/hbase</value>
</property>

<!-- HBase 协处理器 -->
<property>
<name>hbase.coprocessor.user.region.classes</name>
<value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>
</property>
</configuration>
在 hbase-env.sh 中添加如下变量
export JAVA_HOME=/data/app/jdk1.7
export HBASE_LOG_DIR=/data/logs/hbase
export HBASE_PID_DIR=/data/pid
export HBASE_MANAGES_ZK=false
# SSH 默认端口 可选
export HBASE_SSH_OPTS="-o ConnectTimeout=1 -p 36000"
Heap 设置,单位 MB
export HBASE_HEAPSIZE=1024
可选设置 regionservers 中添加所有RegionServer主机名,用于集群批量启动、停止
 
启动与停止
切换用户
su - run
集群批量启动
需要配置运行用户ssh-key免密码登录,与$HBASE_HOME/conf/regionservers
# 启动
start-hbase.sh
# 停止
stop-hbase.sh
单服务启动停止
HMaster
# 启动
hbase-daemon.sh start master
# 停止
hbase-daemon.sh stop master
HRegionServer
# 启动
hbase-daemon.sh start regionserver
# 停止
hbase-daemon.sh stop regionserver

测试
HBase HA 测试
浏览器打开两个HMaster状态页:
http://cdh-m1:60010
http://cdh-m2:60010 

可以在Master后面看见其中一个主机名,Backup Masters中看见另一个。
停止当前Master,刷新另一个HMaster状态页会发现Master后面已经切换,HA成功。
 
HBase 测试
进入hbase shell 执行:
create 'users','user_id','address','info'
list
put 'users','anton','info:age','24'
get 'users','anton'

# 最终结果
COLUMN CELL
info:age timestamp=1465972035945, value=24
1 row(s) in 0.0170 seconds
清除测试数据:
disable 'users'
drop 'users'
到这里安装就全部完成,不懂的地方可以留言交流!

Elasticsearch Recovery详解

大数据/云计算OpenSkill 发表了文章 • 0 个评论 • 416 次浏览 • 2016-09-08 23:56 • 来自相关话题

基础知识点

在Eleasticsearch中recovery指的就是一个索引的分片分配到另外一个节点的过程;一般在快照恢复、索引副本数变更、节点故障、节点重启时发生。由于master保存整个集群的状态信息,因此可以判断出哪些shard需要做再分配,以及分配到哪个结点,例如:
如果某个shard主分片在,副分片所在结点挂了,那么选择另外一个可用结点,将副分片分配(allocate)上去,然后进行主从分片的复制。如果某个shard的主分片所在结点挂了,副分片还在,那么将副分片升级为主分片,然后做主从分片复制。如果某个shard的主副分片所在结点都挂了,则暂时无法恢复,等待持有相关数据的结点重新加入集群后,从该结点上恢复主分片,再选择另外的结点复制副分片。
 
正常情况下,我们可以通过ES的health的API接口,查看整个集群的健康状态和整个集群数据的完整性:




状态及含义如下:
green: 所有的shard主副分片都是正常的;yellow: 所有shard的主分片都完好,部分副分片没有或者不完整,数据完整性依然完好;red: 某些shard的主副分片都没有了,对应的索引数据不完整。
 
recovery过程要消耗额外的资源,CPU、内存、结点之间的网络带宽等等。 这些额外的资源消耗,有可能会导致集群的服务性能下降,或者一部分功能暂时不可用。了解一些recovery的过程和相关的配置参数,对于减小recovery带来的资源消耗,加快集群恢复过程都是很有帮助的。
 

减少集群Full Restart造成的数据来回拷贝

ES集群可能会有整体重启的情况,比如需要升级硬件、升级操作系统或者升级ES大版本。重启所有结点可能带来的一个问题: 某些结点可能先于其他结点加入集群, 先加入集群的结点可能已经可以选举好master,并立即启动了recovery的过程,由于这个时候整个集群数据还不完整,master会指示一些结点之间相互开始复制数据。 那些晚到的结点,一旦发现本地的数据已经被复制到其他结点,则直接删除掉本地“失效”的数据。 当整个集群恢复完毕后,数据分布不均衡,显然是不均衡的,master会触发rebalance过程,将数据在节点之间挪动。整个过程无谓消耗了大量的网络流量;合理设置recovery相关参数则可以防范这种问题的发生。gateway.expected_nodes
gateway.expected_master_nodes
gateway.expected_data_nodes以上三个参数是说集群里一旦有多少个节点就立即开始recovery过程。 不同之处在于,第一个参数指的是master或者data都算在内,而后面两个参数则分指master和data node。
 
在期待的节点数条件满足之前, recovery过程会等待gateway.recover_after_time (默认5分钟) 这么长时间,一旦等待超时,则会根据以下条件判断是否启动:gateway.recover_after_nodes
gateway.recover_after_master_nodes
gateway.recover_after_data_nodes
 
举例来说,对于一个有10个data node的集群,如果有以下的设置:gateway.expected_data_nodes: 10
gateway.recover_after_time: 5m
gateway.recover_after_data_nodes: 8那么集群5分钟以内10个data node都加入了,或者5分钟以后8个以上的data node加入了,都会立即启动recovery过程。
 

减少主副本之间的数据复制

如果不是full restart,而是重启单个data node,仍然会造成数据在不同结点之间来回复制。为避免这个问题,可以在重启之前,先关闭集群的shard allocation:




然后在节点重启完成加入集群后,再重新打开:




这样在节点重启完成后,尽量多的从本地直接恢复数据。

但是在ES1.6版本之前,即使做了以上措施,仍然会发现有大量主副本之间的数据拷贝。从表面去看,这点很让人不能理解。 主副本数据完全一致,ES应该直接从副本本地恢复数据就好了,为什么要重新从主片再复制一遍呢? 原因在于recovery是简单对比主副本的segment file来判断哪些数据一致可以本地恢复,哪些不一致需要远端拷贝的。而不同节点的segment merge是完全独立运行的,可能导致主副本merge的深度不完全一样,从而造成即使文档集完全一样,产生的segment file却不完全一样。
 
为了解决这个问题,ES1.6版本以后加入了synced flush的新特性。 对于5分钟没有更新过的shard,会自动synced flush一下,实质是为对应的shard加了一个synced flush ID。这样当重启节点的时候,先对比一下shard的synced flush ID,就可以知道两个shard是否完全相同,避免了不必要的segment file拷贝,极大加快了冷索引的恢复速度。
 
需要注意的是synced flush只对冷索引有效,对于热索引(5分钟内有更新的索引)没有作用。 如果重启的结点包含有热索引,那么还是免不了大量的文件拷贝。因此在重启一个结点之前,最好按照以下步骤执行,recovery几乎可以瞬间完成:
暂停数据写入程序关闭集群shard allocation手动执行POST /_flush/synced重启节点重新开启集群shard allocation 等待recovery完成,集群health status变成green重新开启数据写入程序
 

特大热索引为何恢复慢

对于冷索引,由于数据不再更新,利用synced flush特性,可以快速直接从本地恢复数据。 而对于热索引,特别是shard很大的热索引,除了synced flush派不上用场需要大量跨节点拷贝segment file以外,translog recovery是导致慢的更重要的原因。
 
从主片恢复数据到副片需要经历3个阶段:
对主片上的segment file做一个快照,然后拷贝到复制片分配到的结点。数据拷贝期间,不会阻塞索引请求,新增索引操作记录到translog里。对translog做一个快照,此快照包含第一阶段新增的索引请求,然后重放快照里的索引操作。此阶段仍然不阻塞索引请求,新增索引操作记录到translog里。为了能达到主副片完全同步,阻塞掉新索引请求,然后重放阶段二新增的translog操作。
 
可见,在recovery完成之前,translog是不能够被清除掉的(禁用掉正常运作期间后台的flush操作)。如果shard比较大,第一阶段耗时很长,会导致此阶段产生的translog很大。重放translog比起简单的文件拷贝耗时要长得多,因此第二阶段的translog耗时也会显著增加。等到第三阶段,需要重放的translog可能会比第二阶段还要多。 而第三阶段是会阻塞新索引写入的,在对写入实时性要求很高的场合,就会非常影响用户体验。 因此,要加快大的热索引恢复速度,最好的方式是遵从上一节提到的方法: 暂停新数据写入,手动sync flush,等待数据恢复完成后,重新开启数据写入,这样可以将数据延迟影响可以降到最低。
 
万一遇到Recovery慢,想知道进度怎么办呢? CAT Recovery API可以显示详细的recovery各个阶段的状态。 这个API怎么用就不在这里赘述了,参考: CAT Recovery。
 

其他Recovery相关的专家级设置

还有其他一些专家级的设置(参见: recovery)可以影响recovery的速度,但提升速度的代价是更多的资源消耗,因此在生产集群上调整这些参数需要结合实际情况谨慎调整,一旦影响应用要立即调整回来。 对于搜索并发量要求高,延迟要求低的场合,默认设置一般就不要去动了。 对于日志实时分析类对于搜索延迟要求不高,但对于数据写入延迟期望比较低的场合,可以适当调大indices.recovery.max_bytes_per_sec,提升recovery速度,减少数据写入被阻塞的时长。
 
最后要说的一点是ES的版本迭代很快,对于Recovery的机制也在不断的优化中。 其中有一些版本甚至引入了一些bug,比如在ES1.4.x有严重的translog recovery bug,导致大的索引trans log recovery几乎无法完成 (issue #9226)  。因此实际使用中如果遇到问题,最好在Github的issue list里搜索一下,看是否使用的版本有其他人反映同样的问题。
分享阅读原文:http://elasticsearch.cn/article/38 查看全部


基础知识点


在Eleasticsearch中recovery指的就是一个索引的分片分配到另外一个节点的过程;一般在快照恢复、索引副本数变更、节点故障、节点重启时发生。由于master保存整个集群的状态信息,因此可以判断出哪些shard需要做再分配,以及分配到哪个结点,例如:
  1. 如果某个shard主分片在,副分片所在结点挂了,那么选择另外一个可用结点,将副分片分配(allocate)上去,然后进行主从分片的复制。
  2. 如果某个shard的主分片所在结点挂了,副分片还在,那么将副分片升级为主分片,然后做主从分片复制。
  3. 如果某个shard的主副分片所在结点都挂了,则暂时无法恢复,等待持有相关数据的结点重新加入集群后,从该结点上恢复主分片,再选择另外的结点复制副分片。

 
正常情况下,我们可以通过ES的health的API接口,查看整个集群的健康状态和整个集群数据的完整性:
EsHealth.png

状态及含义如下:
  • green: 所有的shard主副分片都是正常的;
  • yellow: 所有shard的主分片都完好,部分副分片没有或者不完整,数据完整性依然完好;
  • red: 某些shard的主副分片都没有了,对应的索引数据不完整。

 
recovery过程要消耗额外的资源,CPU、内存、结点之间的网络带宽等等。 这些额外的资源消耗,有可能会导致集群的服务性能下降,或者一部分功能暂时不可用。了解一些recovery的过程和相关的配置参数,对于减小recovery带来的资源消耗,加快集群恢复过程都是很有帮助的。
 


减少集群Full Restart造成的数据来回拷贝


ES集群可能会有整体重启的情况,比如需要升级硬件、升级操作系统或者升级ES大版本。重启所有结点可能带来的一个问题: 某些结点可能先于其他结点加入集群, 先加入集群的结点可能已经可以选举好master,并立即启动了recovery的过程,由于这个时候整个集群数据还不完整,master会指示一些结点之间相互开始复制数据。 那些晚到的结点,一旦发现本地的数据已经被复制到其他结点,则直接删除掉本地“失效”的数据。 当整个集群恢复完毕后,数据分布不均衡,显然是不均衡的,master会触发rebalance过程,将数据在节点之间挪动。整个过程无谓消耗了大量的网络流量;合理设置recovery相关参数则可以防范这种问题的发生。
gateway.expected_nodes
gateway.expected_master_nodes
gateway.expected_data_nodes
以上三个参数是说集群里一旦有多少个节点就立即开始recovery过程。 不同之处在于,第一个参数指的是master或者data都算在内,而后面两个参数则分指master和data node。
 
在期待的节点数条件满足之前, recovery过程会等待gateway.recover_after_time (默认5分钟) 这么长时间,一旦等待超时,则会根据以下条件判断是否启动:
gateway.recover_after_nodes
gateway.recover_after_master_nodes
gateway.recover_after_data_nodes
 
举例来说,对于一个有10个data node的集群,如果有以下的设置:
gateway.expected_data_nodes: 10
gateway.recover_after_time: 5m
gateway.recover_after_data_nodes: 8
那么集群5分钟以内10个data node都加入了,或者5分钟以后8个以上的data node加入了,都会立即启动recovery过程。
 


减少主副本之间的数据复制


如果不是full restart,而是重启单个data node,仍然会造成数据在不同结点之间来回复制。为避免这个问题,可以在重启之前,先关闭集群的shard allocation:
EsNone.png

然后在节点重启完成加入集群后,再重新打开:
EsAll.png

这样在节点重启完成后,尽量多的从本地直接恢复数据。

但是在ES1.6版本之前,即使做了以上措施,仍然会发现有大量主副本之间的数据拷贝。从表面去看,这点很让人不能理解。 主副本数据完全一致,ES应该直接从副本本地恢复数据就好了,为什么要重新从主片再复制一遍呢? 原因在于recovery是简单对比主副本的segment file来判断哪些数据一致可以本地恢复,哪些不一致需要远端拷贝的。而不同节点的segment merge是完全独立运行的,可能导致主副本merge的深度不完全一样,从而造成即使文档集完全一样,产生的segment file却不完全一样。
 
为了解决这个问题,ES1.6版本以后加入了synced flush的新特性。 对于5分钟没有更新过的shard,会自动synced flush一下,实质是为对应的shard加了一个synced flush ID。这样当重启节点的时候,先对比一下shard的synced flush ID,就可以知道两个shard是否完全相同,避免了不必要的segment file拷贝,极大加快了冷索引的恢复速度。
 
需要注意的是synced flush只对冷索引有效,对于热索引(5分钟内有更新的索引)没有作用。 如果重启的结点包含有热索引,那么还是免不了大量的文件拷贝。因此在重启一个结点之前,最好按照以下步骤执行,recovery几乎可以瞬间完成:
  1. 暂停数据写入程序
  2. 关闭集群shard allocation
  3. 手动执行POST /_flush/synced
  4. 重启节点
  5. 重新开启集群shard allocation 
  6. 等待recovery完成,集群health status变成green
  7. 重新开启数据写入程序

 


特大热索引为何恢复慢


对于冷索引,由于数据不再更新,利用synced flush特性,可以快速直接从本地恢复数据。 而对于热索引,特别是shard很大的热索引,除了synced flush派不上用场需要大量跨节点拷贝segment file以外,translog recovery是导致慢的更重要的原因。
 
从主片恢复数据到副片需要经历3个阶段:
  1. 对主片上的segment file做一个快照,然后拷贝到复制片分配到的结点。数据拷贝期间,不会阻塞索引请求,新增索引操作记录到translog里。
  2. 对translog做一个快照,此快照包含第一阶段新增的索引请求,然后重放快照里的索引操作。此阶段仍然不阻塞索引请求,新增索引操作记录到translog里。
  3. 为了能达到主副片完全同步,阻塞掉新索引请求,然后重放阶段二新增的translog操作。

 
可见,在recovery完成之前,translog是不能够被清除掉的(禁用掉正常运作期间后台的flush操作)。如果shard比较大,第一阶段耗时很长,会导致此阶段产生的translog很大。重放translog比起简单的文件拷贝耗时要长得多,因此第二阶段的translog耗时也会显著增加。等到第三阶段,需要重放的translog可能会比第二阶段还要多。 而第三阶段是会阻塞新索引写入的,在对写入实时性要求很高的场合,就会非常影响用户体验。 因此,要加快大的热索引恢复速度,最好的方式是遵从上一节提到的方法: 暂停新数据写入,手动sync flush,等待数据恢复完成后,重新开启数据写入,这样可以将数据延迟影响可以降到最低。
 
万一遇到Recovery慢,想知道进度怎么办呢? CAT Recovery API可以显示详细的recovery各个阶段的状态。 这个API怎么用就不在这里赘述了,参考: CAT Recovery
 


其他Recovery相关的专家级设置


还有其他一些专家级的设置(参见: recovery)可以影响recovery的速度,但提升速度的代价是更多的资源消耗,因此在生产集群上调整这些参数需要结合实际情况谨慎调整,一旦影响应用要立即调整回来。 对于搜索并发量要求高,延迟要求低的场合,默认设置一般就不要去动了。 对于日志实时分析类对于搜索延迟要求不高,但对于数据写入延迟期望比较低的场合,可以适当调大indices.recovery.max_bytes_per_sec,提升recovery速度,减少数据写入被阻塞的时长。
 
最后要说的一点是ES的版本迭代很快,对于Recovery的机制也在不断的优化中。 其中有一些版本甚至引入了一些bug,比如在ES1.4.x有严重的translog recovery bug,导致大的索引trans log recovery几乎无法完成 (issue #9226)  。因此实际使用中如果遇到问题,最好在Github的issue list里搜索一下,看是否使用的版本有其他人反映同样的问题。
分享阅读原文:http://elasticsearch.cn/article/38

强制清除Elasticsearch中已删除的文件

大数据/云计算采菊篱下 发表了文章 • 0 个评论 • 766 次浏览 • 2016-06-05 01:14 • 来自相关话题

 Elasticsearch是建立在Apache Lucene 基础上的实时分布式搜索引擎,Lucene为了提高搜索的实时性,采用不可再修改(immutable)方式将文档存储在一个个segment中。也就是说,一个segment在写入到存储系统之后,将不可以再修改。那么Lucene是如何从一个segment中删除一个被索引的文档呢?简单的讲,当用户发出命令删除一个被索引的文档#ABC时,该文档并不会被马上从相应的存储它的segment中删除掉,而是通过一个特殊的文件来标记该文档已被删除。当用户再次搜索到#ABC时,Elasticsearch在segment中仍能找到#ABC,但由于#ABC文档已经被标记为删除,所以Lucene会从发回给用户的搜索结果中剔除#ABC,所以给用户感觉的是#ABC已经被删除了。
 
 Elasticseach会有后台线程根据Lucene的合并规则定期进行segment merging 合并操作,一般不需要用户担心或者采取任何行动。被删除的文档在segment合并时,才会被真正删除掉。在此之前,它仍然会占用着JVM heap和操作系统的文件cache等资源。在某些情况下,我们需要强制Elasticsearch进行segment merging,已释放其占用的大量系统资源。
                       POST /{index}/_optimize?only_expunge_deletes=true&wait_for_completion=true
_optimize命令可强制进行segment合并,并删除所有标记为删除的文档。Segment merging要消耗CPU,以及大量的I/O资源,所以一定要在你的ElasticSearch集群处于维护窗口期间,并且有足够的I/O空间的(如:SSD)的条件下进行;否则很可能造成集群崩溃和数据丢失。
 
下图展示了我们在进行强制expunge时,所观察到的CPU和磁盘I/O的使用情况。该集群运行在微软的Azure云平台IaaS虚拟机上,所有的数据节点都采用 D13 虚拟机,数据存储在本地的SSD磁盘中。该集群是一个备份集群,为了保证合并顺利进行,在此期间暂停了所有对其进行的写操作,仅有少量的读操作。这里需要注意: expunge操作是一种不得已而为之的操作,即在Elasticsearch不能有效自动清除删除文件的情况下才执行该操作。同时建议在此操作期间,最好停止对集群的所有读/写操作,并暂停止shard的自动分配 (cluster.routing.allocation.enable= none),以防有节点被踢出后shard自动分配造成的数据丢失。








下面两个设置可以用于控制清除时的处理速度,其中给出值是默认值,可以根据需求进行调整,具体请参见Merge。此外, 还可以临时将所有索引的replica设置为0,这样只用针对Primary进行expunge,以减小I/O压力。
PUT /{index}/_settings
{
"settings": {
"index.merge.policy.expunge_deletes_allowed": "10",
"index.merge.policy.max_merge_at_once_explicit" : "30"
}
}参考资料:Lucene‘s Handling of Deleted Documents.
分享阅读:http://blog.csdn.net/quicknet/article/details/46421505 查看全部
 Elasticsearch是建立在Apache Lucene 基础上的实时分布式搜索引擎,Lucene为了提高搜索的实时性,采用不可再修改(immutable)方式将文档存储在一个个segment中。也就是说,一个segment在写入到存储系统之后,将不可以再修改。那么Lucene是如何从一个segment中删除一个被索引的文档呢?简单的讲,当用户发出命令删除一个被索引的文档#ABC时,该文档并不会被马上从相应的存储它的segment中删除掉,而是通过一个特殊的文件来标记该文档已被删除。当用户再次搜索到#ABC时,Elasticsearch在segment中仍能找到#ABC,但由于#ABC文档已经被标记为删除,所以Lucene会从发回给用户的搜索结果中剔除#ABC,所以给用户感觉的是#ABC已经被删除了。
 
 Elasticseach会有后台线程根据Lucene的合并规则定期进行segment merging 合并操作,一般不需要用户担心或者采取任何行动。被删除的文档在segment合并时,才会被真正删除掉。在此之前,它仍然会占用着JVM heap和操作系统的文件cache等资源。在某些情况下,我们需要强制Elasticsearch进行segment merging,已释放其占用的大量系统资源。
                       POST /{index}/_optimize?only_expunge_deletes=true&wait_for_completion=true
_optimize命令可强制进行segment合并,并删除所有标记为删除的文档。Segment merging要消耗CPU,以及大量的I/O资源,所以一定要在你的ElasticSearch集群处于维护窗口期间,并且有足够的I/O空间的(如:SSD)的条件下进行;否则很可能造成集群崩溃和数据丢失。
 
下图展示了我们在进行强制expunge时,所观察到的CPU和磁盘I/O的使用情况。该集群运行在微软的Azure云平台IaaS虚拟机上,所有的数据节点都采用 D13 虚拟机,数据存储在本地的SSD磁盘中。该集群是一个备份集群,为了保证合并顺利进行,在此期间暂停了所有对其进行的写操作,仅有少量的读操作。这里需要注意: expunge操作是一种不得已而为之的操作,即在Elasticsearch不能有效自动清除删除文件的情况下才执行该操作。同时建议在此操作期间,最好停止对集群的所有读/写操作,并暂停止shard的自动分配 (cluster.routing.allocation.enable= none),以防有节点被踢出后shard自动分配造成的数据丢失。
Cpu.png

sec.png

下面两个设置可以用于控制清除时的处理速度,其中给出值是默认值,可以根据需求进行调整,具体请参见Merge。此外, 还可以临时将所有索引的replica设置为0,这样只用针对Primary进行expunge,以减小I/O压力。
PUT /{index}/_settings
{
"settings": {
"index.merge.policy.expunge_deletes_allowed": "10",
"index.merge.policy.max_merge_at_once_explicit" : "30"
}
}
参考资料:Lucene‘s Handling of Deleted Documents.
分享阅读:http://blog.csdn.net/quicknet/article/details/46421505

怎么彻底删除kafka的topic,然后重建?

大数据/云计算chris 回复了问题 • 3 人关注 • 2 个回复 • 3828 次浏览 • 2016-01-03 19:25 • 来自相关话题

怎么查看kafka的版本号

大数据/云计算OpenSkill 回复了问题 • 2 人关注 • 1 个回复 • 2245 次浏览 • 2016-10-26 21:37 • 来自相关话题

Hbase/Hdfs删除节点

大数据/云计算采菊篱下 发表了文章 • 0 个评论 • 2202 次浏览 • 2015-11-30 00:16 • 来自相关话题

线上有台服务器随时可能会挂掉,所以需要把在这个服务器上hbase的regionserver和hdfs的datanode节点移除。然后重新拿台新服务器部署接管。
 
之前在文章 http://openskill.cn/article/178 中讲到怎么新增一个hdfs的datanode,所以我先讲一下怎么添加一个hbase的regionserver,然后再讲怎么删除! 

添加hbase regionserver节点

添加步骤如下:
1、在hbase  master上修改regionservers文件# cd hbase_install_dir/conf
# echo "new_hbase_node_hostname" >> ./regionservers2、如果你hbase集群使用自身zk集群的话,还需要修改hbase-site.xml文件,反之不用操作!# cd hbase_install_dir/conf
# vim hbase-site.xml
找到hbase.zookeeper.quorum属性 -->加入新节点3、同步以上修改的文件到hbase的各个节点上
4、在新节点上启动hbase regionserver# cd hbase_install_dir/bin/
# ./hbase-daemon.sh start regionserver5、在hbasemaster启动hbase shell用status命令确认一下集群情况hbase新增一个 regionserver节点补充完成了,下面介绍删除hbase和hdfs节点!
 
集群上既部署有Hadoop,又部署有HBase,因为HBase存储是基于Hadoop HDFS的,所以先要移除HBase节点,之后再移除Hadoop节点。添加则反之。

移除hbase regionserver节点

1、在0.90.2之前,我们只能通过在要卸载的节点上执行;我的hbase版本(0.98.7)# cd hbase_install_dir
# ./bin/hbase-daemon.sh stop regionserver来实现。这条语句执行后,该RegionServer首先关闭其负载的所有Region而后关闭自己。在关闭时,RegionServer在ZooKeeper中的"Ephemeral Node"会失效。此时,Master检测到RegionServer挂掉并把它作为一个宕机节点,并将该RegionServer上的Region重新分配到其他RegionServer。
 
注意:使用此方法前,一定要关闭HBase Load Balancer。关闭方法:hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3290 seconds总结:这种方法很大的一个缺点是该节点上的Region会离线很长时间。因为假如该RegionServer上有大量Region的话,因为Region的关闭是顺序执行的,第一个关闭的Region得等到和最后一个Region关闭并Assigned后一起上线。这是一个相当漫长的时间。以我这次的实验为例,现在一台RegionServer平均有1000个Region,每个Region Assigned需要4s,也就是说光Assigned就至少需要1个小时。2、自0.90.2之后,HBase添加了一个新的方法,即"graceful_stop",在你移除的服务器执行:# cd hbase_install_dir
# ./bin/graceful_stop.sh hostname该命令会自动关闭Load Balancer,然后Assigned Region,之后会将该节点关闭。除此之外,你还可以查看remove的过程,已经assigned了多少个Region,还剩多少个Region,每个Region 的Assigned耗时。
 
补充graceful stop的一些其他命令参数:# ./bin/graceful_stop.sh
Usage: graceful_stop.sh [--config &conf-dir>] [--restart] [--reload] [--thrift] [--rest] &hostname>
thrift If we should stop/start thrift before/after the hbase stop/start
rest If we should stop/start rest before/after the hbase stop/start
restart If we should restart after graceful stop
reload Move offloaded regions back on to the stopped server
debug Move offloaded regions back on to the stopped server
hostname Hostname of server we are to stop最终都需要我们手动打开load balancer:hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3590 seconds然后再开启:hbase(main):001:0> balance_switch true
false
0 row(s) in 0.3290 seconds对比两种方法,建议使用"graceful_stop"来移除hbase RegionServer节点。
官网说明:http://hbase.apache.org/0.94/book/node.management.html​  http://hbase.apache.org/book.html#decommission​  

移除hdfs datanode节点

1、在core-site.xml文件下新增如下内容<property>
<name>dfs.hosts.exclude</name>
<value>/hdfs_install_dir/conf/excludes</value>
</property>2、创建exclude文件,把需要删除节点的主机名写入# cd hdfs_install_dir/conf
# vim excludes
添加需要删除的节点主机名,比如 hdnode1 保存退出3、 然后在namenode节点执行如下命令,强制让namenode重新读取配置文件,不需要重启集群。# cd hdfs_install_dir/bin/
# ./hadoop dfsadmin -refreshNodes它会在后台进行Block块的移动
 4、 查看状态
等待第三步的操作结束后,需要下架的机器就可以安全的关闭了。# ./hadoop dfsadmin -report可以查看到现在集群上连接的节点 正在执行Decommission,会显示:
Decommission Status : Decommission in progress

执行完毕后,会显示:
Decommission Status : Decommissioned如下:Name: 10.0.180.6:50010
Decommission Status : Decommission in progress
Configured Capacity: 917033340928 (10.83 TB)
DFS Used: 7693401063424 (7 TB)
Non DFS Used: 118121652224 (110.00 GB)
DFS Remaining: 4105510625280(3.63 TB)
DFS Used%: 64.56%
DFS Remaining%: 34.45%
Last contact: Mon Nov 29 23:53:52 CST 2015也可以直接通过Hadoop 浏览器查看:
LIVE的节点可以查看到:http://master_ip:50070/dfsnodelist.jsp?whatNodes=LIVE
查看看到卸载的节点状态是:Decommission in progress
等待节点完成移除后,浏览:http://master_ip:50070/dfsnodelist.jsp?whatNodes=DEAD 结果如下:




完成后,删除的节点显示在dead nodes中。且其上的服务停止。Live Nodes中仅剩had2,had3
以上即为从Hadoop集群中Remove Node的过程,但是,有一点一定要注意:
hdfs-site.xml配置文件中dfs.replication值必须小于或者等于踢除节点后正常datanode的数量,即:dfs.replication <= 集群所剩节点数修改备份系数可以参考:http://heylinux.com/archives/2047.html

重载入删除的datanode节点 

1、修改namenode的core-site.xml文件,把我们刚刚加入的内容删除或者注释掉,我这里选择注释掉。<!--

<property>
<name>dfs.hosts.exclude</name>
<value>/root/hadoop/conf/excludes</value>
</property>

-->2、 再执行重载namenode的配置文件# ./bin/hadoop dfsadmin -refreshNodes3、最后去启动datanode上的datanode# ./bin/hadoop-daemon.sh start datanode
starting datanode, logging to /usr/local/hadoop/bin/../logs/hadoop-root-datanode-had1.out4、查看启动情况# jps
18653 Jps
19687 DataNode ---->启动正常重新载入HBase RegionServer节点
只需要重启regionserver进程即可。
参考:http://www.edureka.co/blog/commissioning-and-decommissioning-nodes-in-a-hadoop-cluster/
           https://pravinchavan.wordpress.com/2013/06/03/removing-node-from-hadoop-cluster/ 查看全部
线上有台服务器随时可能会挂掉,所以需要把在这个服务器上hbase的regionserver和hdfs的datanode节点移除。然后重新拿台新服务器部署接管。
 
之前在文章 http://openskill.cn/article/178 中讲到怎么新增一个hdfs的datanode,所以我先讲一下怎么添加一个hbase的regionserver,然后再讲怎么删除! 


添加hbase regionserver节点


添加步骤如下:
1、在hbase  master上修改regionservers文件
# cd hbase_install_dir/conf
# echo "new_hbase_node_hostname" >> ./regionservers
2、如果你hbase集群使用自身zk集群的话,还需要修改hbase-site.xml文件,反之不用操作!
# cd hbase_install_dir/conf
# vim hbase-site.xml
找到hbase.zookeeper.quorum属性 -->加入新节点
3、同步以上修改的文件到hbase的各个节点上
4、在新节点上启动hbase regionserver
# cd hbase_install_dir/bin/
# ./hbase-daemon.sh start regionserver
5、在hbasemaster启动hbase shell
用status命令确认一下集群情况
hbase新增一个 regionserver节点补充完成了,下面介绍删除hbase和hdfs节点!
 
集群上既部署有Hadoop,又部署有HBase,因为HBase存储是基于Hadoop HDFS的,所以先要移除HBase节点,之后再移除Hadoop节点。添加则反之。


移除hbase regionserver节点


1、在0.90.2之前,我们只能通过在要卸载的节点上执行;我的hbase版本(0.98.7)
# cd hbase_install_dir
# ./bin/hbase-daemon.sh stop regionserver
来实现。这条语句执行后,该RegionServer首先关闭其负载的所有Region而后关闭自己。在关闭时,RegionServer在ZooKeeper中的"Ephemeral Node"会失效。此时,Master检测到RegionServer挂掉并把它作为一个宕机节点,并将该RegionServer上的Region重新分配到其他RegionServer。
 
注意:使用此方法前,一定要关闭HBase Load Balancer。关闭方法:
hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3290 seconds
总结:
这种方法很大的一个缺点是该节点上的Region会离线很长时间。因为假如该RegionServer上有大量Region的话,因为Region的关闭是顺序执行的,第一个关闭的Region得等到和最后一个Region关闭并Assigned后一起上线。这是一个相当漫长的时间。以我这次的实验为例,现在一台RegionServer平均有1000个Region,每个Region Assigned需要4s,也就是说光Assigned就至少需要1个小时。
2、自0.90.2之后,HBase添加了一个新的方法,即"graceful_stop",在你移除的服务器执行:
# cd hbase_install_dir
# ./bin/graceful_stop.sh hostname
该命令会自动关闭Load Balancer,然后Assigned Region,之后会将该节点关闭。除此之外,你还可以查看remove的过程,已经assigned了多少个Region,还剩多少个Region,每个Region 的Assigned耗时。
 
补充graceful stop的一些其他命令参数:
# ./bin/graceful_stop.sh
Usage: graceful_stop.sh [--config &conf-dir>] [--restart] [--reload] [--thrift] [--rest] &hostname>
thrift If we should stop/start thrift before/after the hbase stop/start
rest If we should stop/start rest before/after the hbase stop/start
restart If we should restart after graceful stop
reload Move offloaded regions back on to the stopped server
debug Move offloaded regions back on to the stopped server
hostname Hostname of server we are to stop
最终都需要我们手动打开load balancer:
hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3590 seconds
然后再开启:
hbase(main):001:0> balance_switch true
false
0 row(s) in 0.3290 seconds
对比两种方法,建议使用"graceful_stop"来移除hbase RegionServer节点。
官网说明:http://hbase.apache.org/0.94/book/node.management.html​  http://hbase.apache.org/book.html#decommission​  


移除hdfs datanode节点


1、在core-site.xml文件下新增如下内容
<property>
<name>dfs.hosts.exclude</name>
<value>/hdfs_install_dir/conf/excludes</value>
</property>
2、创建exclude文件,把需要删除节点的主机名写入
# cd hdfs_install_dir/conf
# vim excludes
添加需要删除的节点主机名,比如 hdnode1 保存退出
3、 然后在namenode节点执行如下命令,强制让namenode重新读取配置文件,不需要重启集群。
# cd hdfs_install_dir/bin/
# ./hadoop dfsadmin -refreshNodes
它会在后台进行Block块的移动
 4、 查看状态
等待第三步的操作结束后,需要下架的机器就可以安全的关闭了。
# ./hadoop dfsadmin -report
可以查看到现在集群上连接的节点 
正在执行Decommission,会显示: 
Decommission Status : Decommission in progress

执行完毕后,会显示:
Decommission Status : Decommissioned
如下:
Name: 10.0.180.6:50010
Decommission Status : Decommission in progress
Configured Capacity: 917033340928 (10.83 TB)
DFS Used: 7693401063424 (7 TB)
Non DFS Used: 118121652224 (110.00 GB)
DFS Remaining: 4105510625280(3.63 TB)
DFS Used%: 64.56%
DFS Remaining%: 34.45%
Last contact: Mon Nov 29 23:53:52 CST 2015
也可以直接通过Hadoop 浏览器查看:
LIVE的节点可以查看到:http://master_ip:50070/dfsnodelist.jsp?whatNodes=LIVE
查看看到卸载的节点状态是:Decommission in progress
等待节点完成移除后,浏览:http://master_ip:50070/dfsnodelist.jsp?whatNodes=DEAD 结果如下:
hdead.png

完成后,删除的节点显示在dead nodes中。且其上的服务停止。Live Nodes中仅剩had2,had3
以上即为从Hadoop集群中Remove Node的过程,但是,有一点一定要注意:
hdfs-site.xml配置文件中dfs.replication值必须小于或者等于踢除节点后正常datanode的数量,即:
dfs.replication <= 集群所剩节点数
修改备份系数可以参考:http://heylinux.com/archives/2047.html


重载入删除的datanode节点 


1、修改namenode的core-site.xml文件,把我们刚刚加入的内容删除或者注释掉,我这里选择注释掉。
<!--

<property>
<name>dfs.hosts.exclude</name>
<value>/root/hadoop/conf/excludes</value>
</property>

-->
2、 再执行重载namenode的配置文件
# ./bin/hadoop dfsadmin -refreshNodes
3、最后去启动datanode上的datanode
# ./bin/hadoop-daemon.sh start datanode
starting datanode, logging to /usr/local/hadoop/bin/../logs/hadoop-root-datanode-had1.out
4、查看启动情况
# jps
18653 Jps
19687 DataNode ---->启动正常
重新载入HBase RegionServer节点
只需要重启regionserver进程即可。
参考:http://www.edureka.co/blog/commissioning-and-decommissioning-nodes-in-a-hadoop-cluster/
           https://pravinchavan.wordpress.com/2013/06/03/removing-node-from-hadoop-cluster/

控制Elasticsearch分片和副本的分配

大数据/云计算OpenSkill 发表了文章 • 1 个评论 • 7924 次浏览 • 2015-09-15 00:04 • 来自相关话题

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

一、显式控制分配

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

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



    如上图所示,我们将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"}}
]
}' 查看全部
    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"}}
]
}'

Elasticsearch 分片交互过程详解

大数据/云计算Ansible 发表了文章 • 0 个评论 • 1516 次浏览 • 2015-06-18 01:40 • 来自相关话题

一、Elasticseach如何将数据存储到分片中
二、主分片与复制分片如何交互
1、索引与删除一个文档
2、更新一个文档
3、检索文档

一、Elasticseach如何将数据存储到分片中

问题:当我们要在ES中存储数据的时候,数据应该存储在主分片和复制分片中的哪一个中去;当我们在ES中检索数据的时候,又是怎么判断要查询的数据是属于哪一个分片。 

数据存储到分片的过程是一定规则的,并不是随机发生的。

规则:shard = hash(routing) % number_of_primary_shards

Routing值可以是一个任意的字符串,默认情况下,它的值为存数数据对应文档 _id 值,也可以是用户自定义的值。Routing这个字符串通过一个hash的函数处理,并返回一个数值,然后再除以索引中主分片的数目,所得的余数作为主分片的编号,取值一般在0到number_of_primary_shards - 1的这个范围中。通过这种方法计算出该数据是存储到哪个分片中。

正是这种路由机制,导致了主分片的个数为什么在索引建立之后不能修改。对已有索引主分片数目的修改直接会导致路由规则出现严重问题,部分数据将无法被检索。
 
二、主分片与复制分片如何交互
为了说明这个问题,我用一个例子来说明。





在上面这个例子中,有三个ES的node,其中每一个index中包含两个primary shard,每个primary shard拥有一个replica shard。下面从几种常见的数据操作来说明二者之间的交互情况。
 
1、索引与删除一个文档





这两种过程均可以分为三个过程来描述:
阶段1:客户端发送了一个索引或者删除的请求给node 1。

阶段2:node 1通过请求中文档的 _id 值判断出该文档应该被存储在shard 0 这个分片中,并且node 1知道shard 0的primary shard位于node 3这个节点上。因此node 1会把这个请求转发到node 3。

阶段3:node 3在shard 0 的primary shard上执行请求。如果请求执行成功,它node 3将并行地将该请求发给shard 0的其余所有replica shard上,也就是存在于node 1和node 2中的replica shard。如果所有的replica shard都成功地执行了请求,那么将会向node 3回复一个成功确认,当node 3收到了所有replica shard的确认信息后,则最后向用户返回一个Success的消息。
 
2、更新一个文档





该过程可以分为四个阶段来描述:
阶段1:客户端向node 1发送一个文档更新的请求。

阶段2:同样的node 1通过请求中文档的 _id 值判断出该文档应该被存储在shard 0 这个分片中,并且node 1知道shard 0的primary shard位于node 3这个节点上。因此node 1会把这个请求转发到node 3。

阶段3:node 3从文档所在的primary shard中获取到它的JSON文件,并修改其中的_source中的内容,之后再重新索引该文档到其primary shard中。

阶段4:如果node 3成功地更新了文档,node 3将会把文档新的版本并行地发给其余所有的replica shard所在node中。这些node也同样重新索引新版本的文档,执行后则向node 3确认成功,当node 3接收到所有的成功确认之后,再向客户端发送一个更新成功的信息。
 
3、检索文档
CRUD这些操作的过程中一般都是结合一些唯一的标记例如:_index,_type,以及routing的值,这就意味在执行操作的时候都是确切的知道文档在集群中的哪个node中,哪个shard中。

而检索过程往往需要更多的执行模式,因为我们并不清楚所要检索的文档具体位置所在, 它们可能存在于ES集群中个任何位置。因此,一般情况下,检索的执行不得不去询问index中的每一个shard。

但是,找到所有匹配检索的文档仅仅只是检索过程的一半,在向客户端返回一个结果列表之前,必须将各个shard发回的小片的检索结果,拼接成一个大的已排好序的汇总结果列表。正因为这个原因,检索的过程将分为查询阶段与获取阶段(Query Phase and Fetch Phase)。

Query Phase
在最初的查询过程中,查询请求会广播到index中的每一个primary shard和replica shard中,每一个shard会在本地执行检索,并建立一个优先级队列(priority queue)。这个优先级队列是一个根据文档匹配度这个指标所排序列表,列表的长度由分页参数from和size两个参数所决定。例如:






下面从一个例子中说明这个过程:





Query Phase阶段可以再细分成3个小的子阶段:

子阶段1:客户端发送一个检索的请求给node 3,此时node 3会创建一个空的优先级队列并且配置好分页参数from与size。

子阶段2:node 3将检索请求发送给该index中个每一个shard(这里的每一个意思是无论它是primary还是replica,它们的组合可以构成一个完整的index数据)。每个shard在本地执行检索,并将结果添加到本地优先级队列中。

子阶段3:每个shard返回本地优先级序列中所记录的_id与sort值,并发送node 3。Node 3将这些值合并到自己的本地的优先级队列中,并做全局的排序。
 
Fetch Phase
Query Phase主要定位了所要检索数据的具体位置,但是我们还必须取回它们才能完成整个检索过程。而Fetch Phase阶段的任务就是将这些定位好的数据内容取回并返回给客户端。
 
同样也用一个例子来说明这个过程:





Fetch Phase过程可以分为三个子过程来描述:

子阶段1:node 3获取了所有待检索数据的定位之后,发送一个mget的请求给与数据相关的shard。

子阶段2:每个收到node 3的get请求的shard将读取相关文档_source中的内容,并将它们返回给node 3。

子阶段3:当node 3获取到了所有shard返回的文档后,node 3将它们合并成一条汇总的结果,返回给客户端。 查看全部


一、Elasticseach如何将数据存储到分片中
二、主分片与复制分片如何交互
1、索引与删除一个文档
2、更新一个文档
3、检索文档


一、Elasticseach如何将数据存储到分片中

问题:当我们要在ES中存储数据的时候,数据应该存储在主分片和复制分片中的哪一个中去;当我们在ES中检索数据的时候,又是怎么判断要查询的数据是属于哪一个分片。 

数据存储到分片的过程是一定规则的,并不是随机发生的。

规则:shard = hash(routing) % number_of_primary_shards

Routing值可以是一个任意的字符串,默认情况下,它的值为存数数据对应文档 _id 值,也可以是用户自定义的值。Routing这个字符串通过一个hash的函数处理,并返回一个数值,然后再除以索引中主分片的数目,所得的余数作为主分片的编号,取值一般在0到number_of_primary_shards - 1的这个范围中。通过这种方法计算出该数据是存储到哪个分片中。

正是这种路由机制,导致了主分片的个数为什么在索引建立之后不能修改。对已有索引主分片数目的修改直接会导致路由规则出现严重问题,部分数据将无法被检索。
 
二、主分片与复制分片如何交互
为了说明这个问题,我用一个例子来说明。

a.png

在上面这个例子中,有三个ES的node,其中每一个index中包含两个primary shard,每个primary shard拥有一个replica shard。下面从几种常见的数据操作来说明二者之间的交互情况。
 
1、索引与删除一个文档

b.png

这两种过程均可以分为三个过程来描述:
阶段1:客户端发送了一个索引或者删除的请求给node 1。

阶段2:node 1通过请求中文档的 _id 值判断出该文档应该被存储在shard 0 这个分片中,并且node 1知道shard 0的primary shard位于node 3这个节点上。因此node 1会把这个请求转发到node 3。

阶段3:node 3在shard 0 的primary shard上执行请求。如果请求执行成功,它node 3将并行地将该请求发给shard 0的其余所有replica shard上,也就是存在于node 1和node 2中的replica shard。如果所有的replica shard都成功地执行了请求,那么将会向node 3回复一个成功确认,当node 3收到了所有replica shard的确认信息后,则最后向用户返回一个Success的消息。
 
2、更新一个文档

c.png

该过程可以分为四个阶段来描述:
阶段1
:客户端向node 1发送一个文档更新的请求。

阶段2:同样的node 1通过请求中文档的 _id 值判断出该文档应该被存储在shard 0 这个分片中,并且node 1知道shard 0的primary shard位于node 3这个节点上。因此node 1会把这个请求转发到node 3。

阶段3:node 3从文档所在的primary shard中获取到它的JSON文件,并修改其中的_source中的内容,之后再重新索引该文档到其primary shard中。

阶段4:如果node 3成功地更新了文档,node 3将会把文档新的版本并行地发给其余所有的replica shard所在node中。这些node也同样重新索引新版本的文档,执行后则向node 3确认成功,当node 3接收到所有的成功确认之后,再向客户端发送一个更新成功的信息。
 
3、检索文档
CRUD这些操作的过程中一般都是结合一些唯一的标记例如:_index,_type,以及routing的值,这就意味在执行操作的时候都是确切的知道文档在集群中的哪个node中,哪个shard中。

而检索过程往往需要更多的执行模式,因为我们并不清楚所要检索的文档具体位置所在, 它们可能存在于ES集群中个任何位置。因此,一般情况下,检索的执行不得不去询问index中的每一个shard。

但是,找到所有匹配检索的文档仅仅只是检索过程的一半,在向客户端返回一个结果列表之前,必须将各个shard发回的小片的检索结果,拼接成一个大的已排好序的汇总结果列表。正因为这个原因,检索的过程将分为查询阶段与获取阶段(Query Phase and Fetch Phase)。

Query Phase
在最初的查询过程中,查询请求会广播到index中的每一个primary shard和replica shard中,每一个shard会在本地执行检索,并建立一个优先级队列(priority queue)。这个优先级队列是一个根据文档匹配度这个指标所排序列表,列表的长度由分页参数from和size两个参数所决定。例如:

d.png


下面从一个例子中说明这个过程:

e.png

Query Phase阶段可以再细分成3个小的子阶段:

子阶段1:客户端发送一个检索的请求给node 3,此时node 3会创建一个空的优先级队列并且配置好分页参数from与size。

子阶段2:node 3将检索请求发送给该index中个每一个shard(这里的每一个意思是无论它是primary还是replica,它们的组合可以构成一个完整的index数据)。每个shard在本地执行检索,并将结果添加到本地优先级队列中。

子阶段3:每个shard返回本地优先级序列中所记录的_id与sort值,并发送node 3。Node 3将这些值合并到自己的本地的优先级队列中,并做全局的排序。
 
Fetch Phase
Query Phase主要定位了所要检索数据的具体位置,但是我们还必须取回它们才能完成整个检索过程。而Fetch Phase阶段的任务就是将这些定位好的数据内容取回并返回给客户端。
 
同样也用一个例子来说明这个过程:

f.png

Fetch Phase过程可以分为三个子过程来描述:

子阶段1:node 3获取了所有待检索数据的定位之后,发送一个mget的请求给与数据相关的shard。

子阶段2:每个收到node 3的get请求的shard将读取相关文档_source中的内容,并将它们返回给node 3。

子阶段3:当node 3获取到了所有shard返回的文档后,node 3将它们合并成一条汇总的结果,返回给客户端。

Hadoop可以运行单机模式吗?

回复

大数据/云计算采菊篱下 回复了问题 • 2 人关注 • 2 个回复 • 624 次浏览 • 2015-10-18 22:18 • 来自相关话题

启动hadoop时,log中出现:java.io.IOException: NameNode is not formatted.

回复

大数据/云计算OpenSkill 回复了问题 • 2 人关注 • 1 个回复 • 1025 次浏览 • 2015-06-29 01:36 • 来自相关话题

OVM混合虚拟化设计目标及设计思路

大数据/云计算maoliang 发表了文章 • 0 个评论 • 281 次浏览 • 2016-09-29 09:42 • 来自相关话题

1、OVM虚拟化的目标:

OVM是要实现混合虚拟化,做一个大一统的资源管理和交付平台,纵观虚拟化市场,现在当属开源的KVM和Docker最火,我们工作过去有vmware,现在大量使用kvm,未来一定会考虑docker,但现有市场上的产品要么架构太大,开发难度高,易用性不够强,要么就是单纯的虚拟化,类似vmware等。

新形式下,我们需要的产品要同时具备如下目标:

跨平台,支持KVM、Esxi和Docker容器

因为我们单位过去采用虚拟化技术混杂,上面又遗留很多虚拟机,这就要求我们新开发产品能够兼容不同hypervior,同时还能识别并管理原有hypervior上的虚拟机,能够识别并导入原数据库技术并不难,难的是导入后还能纳入新平台管理,这部分我们又研发了自动捕获技术,而不同混合虚拟化管理技术可以摆脱对底层Hypervisor的依赖,专心于资源的统一管理。

单独的用户自助服务门户

过去采用传统虚拟化时,解决了安装部署的麻烦,但资源的申请和扩容、准备资源和切割资源仍然没有变,还是要让我们做,占据了日常运维工作的大部分工作量,每天确实烦人,所以我们想而这部分工作是可以放给相关的部门Leader或者专员,来减少运维的工作量,所以我们希望新设计的OVM允许用户通过一个单独的Web门户来直接访问自己的资源(云主机、云硬盘、网络等),而且对自己的资源进行管理,而不需要知道资源的具体位置,同时用户的所有云主机都建立在高可用环境之上,也不必担心实际物理硬件故障引起服务瘫痪。

Opscode Chef自动化运维集成

实行自助服务后,有一个问题,就是软件不同版本部署不兼容,这就需要设计能够把操作系统、中间件、数据库、web能统一打包部署,减少自助用户哭天喊地甚至骂我们,我们通过对chef的集成,可以一键更新所有的虚拟机,在指定的虚拟机上安装指定的软件。有了chef工具,为虚拟机打补丁、安装软件,只需要几个简单的命令即可搞定。

可持续性

做运维不要故障处理办法是不行,而且还要自动化的,同时我们有vmware和kvm,就需要新平台能在esxi上(不要vcenter,要付钱的)和kvm同时实现ha功能

可运维性
一个平台再强大,技术再厉害,如果不可运维,那结果可想而知。因此我们希望OVM可以给用户带来一个稳定、可控、安全的生产环境

弹性伸缩
自助服务部门拿到资源后,通过对各项目资源的限额,以及对各虚拟机和容器性能指标的实时监控,可以实现弹性的资源伸缩,达到合理分配利用资源。

资源池化
将数据中心的计算、存储、网络资源全部池化,然后通过OVM虚拟化平台统一对外提供IaaS服务。

2、OVM设计思路

OVM架构选型一

我们觉得架构就是一个产品的灵魂所在,决定着产品日后的发展。

我们团队在产品选型初期,分别调研了目前比较热门的openstack,以及前几年的明星产品convirt、ovirt,这几个产品可谓是典型的代表。

Openstack偏重于公有云,架构设计的很不错,其分布式、插件式的模块化架构,可以有效避免单点故障的发生,从发布之初便备受推崇,但是其存在的问题也同样令人头疼目前使用Openstack的大多是一些有实力的IDC、大型的互联网公司在用。而对于一般的企业来说,没有强大的开发和维护团队,并不敢大规模的采用openstack,初期使用一段时间后我们放弃了OS。

而前几年的convirt,在当时也掀起了一股使用热潮,其简单化的使用体验,足以满足小企业的虚拟化需求,但是他的问题是架构采用了集中式的架构,而且对于上了规模之后,也会带来性能方面的瓶颈,除非是把数据库等一些组件松藕合,解决起来也比较麻烦,所以到了后期也是不温不火,官方也停止了社区的更新和维护。

OVM架构选型二

      通过对以上产品的优劣势分析,我们决定采用用分布式、松耦合的模块化插件架构,分布式使其可以规避单点故障,达到业务持续高可用,松耦合的模块化特点让产品在后期的扩展性方面不受任何限制,使其向下可以兼容数据中心所有硬件(通过OVM标准的Rest API接口),向上可以实现插件式的我们即将需要的工作流引擎、计费引擎、报表引擎、桌面云引擎和自动化运维引擎。

而目前阶段我们则专心于实现虚拟化的全部功能,发掘内部对虚拟化的需求,打造一款真正简单、易用、稳定、可运维的一款虚拟化管理软件,并预留向上、向下的接口留作后期发展。(架构图大家可以查看刚才上面发的图片)

虚拟化技术选择

    Docker当下很火,其轻量级、灵活、高密度部署是优点,但是大规模使用还未成熟。许多场景还是需要依赖传统的虚拟化技术。所以我们选择传统虚拟化技术KVM+Docker,确保线上业务稳定性、连续性的同时,开发、测试环境又可以利用到Docker的轻量级、高密度和灵活。

     另外很多用户的生产环境存在不止一种虚拟化技术,例如KVM+Esxi组合、KVM+XenServer组合、KVM+Hyper-V组合,而目前的虚拟化管理平台,大多都是只支持一种Hypervisor的管理,用户想要维护不同的虚拟化技术的虚拟机,就要反复的在不同环境之间切换。

    基于此考虑,我和团队内部和外部一些同行选择兼容(兼容KVM、Esxi,Docker),并自主打造新一代虚拟化管理平台——混合虚拟化。

网络  

 网络方面,我们对所有Hypervisor的虚拟机使用统一的网络管理(包括Docker容器),这样做的一个好处就是可以减少运维工作量,降低网络复杂性。初期我们只实现2层的虚拟网络管理,为虚拟机和容器提供Vlan隔离、DHCP分配网络,当然也可以手工为虚拟机挑选一个网络,这个可以满足一般的虚拟化需求,后期我们会在此基础上增加虚拟网络防火墙、负载均衡。

存储

存储上面我们采用本地存储+NFS两种方式,对于一般中小企业来说,不希望购买高昂的商业存储,直接使用本地存储虚拟机的性能是最好的,而且我们也提供了存储快照、存储热迁移、虚拟机的无共享热迁移来提升业务安全。此外NFS作为辅助,可以为一些高风险业务提供HA。后期存储方面我们会考虑集成Ceph和GlusterFS存储来提升存储管理。

镜像中心

顾名思义,镜像中心就是用来存放镜像的。传统虚拟化我们使用NFS来作为镜像中心,所有宿主机共享一个镜像中心,这样可以更方便的来统一管理镜像,而针对Docker容器则保留了使用Docker自己的私有仓库,但是我们在WEB UI的镜像中心增加了从Docker私有仓库下载模板这么一个功能,实现了在同一个镜像中心的管理,后期我们会着重打造传统虚拟化镜像与Docker镜像的相互转换,实现两者内容的统一。

HA

OVM 主机HA依然坚持全兼容策略,支持对可管理的所有Hypervisor的HA。

在启用HA的资源池,当检测到一个Hypervisor故障,创建和运行在该Hypervisor共享存储上的虚拟机将在相同资源池下的另外一个主机上重启。

具体工作流程为:

第一次检测到故障会将该故障主机标记;

第二次检测依然故障将启动迁移任务;

迁移任务启动后将在该故障主机所在的资源池寻找合适的主机;

确定合适主机后,会将故障主机上所有的虚拟机自动迁移到合适的主机上面并重新启动;

 

VM分配策略

负载均衡

PERFORMANCE(性能): 这条策略分配虚拟机到不同的主机上。它挑选一组中可用资源最多的主机来部署虚拟机。如果有多个主机都有相同的资源可用,它使用一个循环算法,每个虚拟机分配到一个不同的主机上。

PROGRESSIVE(逐行扫描): 这条策略意味着,所有虚拟机将被分配在同一个主机上,直到它的资源被用尽。此项策略将一个主机资源使用完,然后再切换到另一个主机。

负载均衡级别

所有资源池: 如果选定此选项,则负载均衡级别策略将适用于所选定数据中心的所有资源池中的主机。

所有主机: 该策略将适用于所选数据中心单个资源池的所有主机。

特定主机: 该策略仅适用于所选的特定主机。

 

VM设计一

VM是整个虚拟化平台的核心,我们开发了一个单独的模块来负责虚拟机的相关操作。其采用异步通信和独立的并行操作,提升了虚拟机性能、稳定性和扩展性。

可扩展性:独立、并发

可追溯性:错误信息和log、监控控制台、性能

非阻塞操作:稳定性、改进重新配置、改进回滚、标准、统一的hypervisor通信、自动化测试

 

VM设计二

我们设计基于vApp来部署虚拟机,一个vApp可包含N个虚拟机:

N 个虚拟机配置

N个开机请求

我们希望并行运行N个配置(要求资源允许),并在配置后每个虚拟机请求一个开机。这些操作都是并发和独立的。

 

平台设计

OVM产品目前由三大组件、七大模块组成。其中三大组件分别为OVM UI、OVM API和OVM数据中心组件。

OVM UI提供WEB自服务界面,OVM API负责UI和数据中心组件之间的交互,OVM数据中心组件分别提供不同的功能。七大模块分别负责不同的功能实现,和三大组件之间分别交互。

VDC资源限额

管理员可以为每个VDC设置资源限额,防止资源的过度浪费。

账户管理

OVM提供存储SDK、备份SDK,以及虚拟防火墙SDK,轻松与第三方实现集成

获得帮助

下载请访问OVM社区官网:51ovm.com

使用过程中遇到什么问题及获得下载密码,加入OVM社区qq官方交流群:22265939

“ 实践是检验真理唯一标准“,OVM社区视您为社区的发展动力,此刻,诚邀您参与我们的调查,共同做出一款真正解决问题、放心的产品,一起推动国内虚拟化的进步和发展。

填写调查问卷!只需1分钟喔!
https://www.wenjuan.com/s/iiEVZv 查看全部
1、OVM虚拟化的目标:

OVM是要实现混合虚拟化,做一个大一统的资源管理和交付平台,纵观虚拟化市场,现在当属开源的KVM和Docker最火,我们工作过去有vmware,现在大量使用kvm,未来一定会考虑docker,但现有市场上的产品要么架构太大,开发难度高,易用性不够强,要么就是单纯的虚拟化,类似vmware等。

新形式下,我们需要的产品要同时具备如下目标:

跨平台,支持KVM、Esxi和Docker容器

因为我们单位过去采用虚拟化技术混杂,上面又遗留很多虚拟机,这就要求我们新开发产品能够兼容不同hypervior,同时还能识别并管理原有hypervior上的虚拟机,能够识别并导入原数据库技术并不难,难的是导入后还能纳入新平台管理,这部分我们又研发了自动捕获技术,而不同混合虚拟化管理技术可以摆脱对底层Hypervisor的依赖,专心于资源的统一管理。

单独的用户自助服务门户

过去采用传统虚拟化时,解决了安装部署的麻烦,但资源的申请和扩容、准备资源和切割资源仍然没有变,还是要让我们做,占据了日常运维工作的大部分工作量,每天确实烦人,所以我们想而这部分工作是可以放给相关的部门Leader或者专员,来减少运维的工作量,所以我们希望新设计的OVM允许用户通过一个单独的Web门户来直接访问自己的资源(云主机、云硬盘、网络等),而且对自己的资源进行管理,而不需要知道资源的具体位置,同时用户的所有云主机都建立在高可用环境之上,也不必担心实际物理硬件故障引起服务瘫痪。

Opscode Chef自动化运维集成

实行自助服务后,有一个问题,就是软件不同版本部署不兼容,这就需要设计能够把操作系统、中间件、数据库、web能统一打包部署,减少自助用户哭天喊地甚至骂我们,我们通过对chef的集成,可以一键更新所有的虚拟机,在指定的虚拟机上安装指定的软件。有了chef工具,为虚拟机打补丁、安装软件,只需要几个简单的命令即可搞定。

可持续性

做运维不要故障处理办法是不行,而且还要自动化的,同时我们有vmware和kvm,就需要新平台能在esxi上(不要vcenter,要付钱的)和kvm同时实现ha功能

可运维性
一个平台再强大,技术再厉害,如果不可运维,那结果可想而知。因此我们希望OVM可以给用户带来一个稳定、可控、安全的生产环境

弹性伸缩
自助服务部门拿到资源后,通过对各项目资源的限额,以及对各虚拟机和容器性能指标的实时监控,可以实现弹性的资源伸缩,达到合理分配利用资源。

资源池化
将数据中心的计算、存储、网络资源全部池化,然后通过OVM虚拟化平台统一对外提供IaaS服务。

2、OVM设计思路

OVM架构选型一

我们觉得架构就是一个产品的灵魂所在,决定着产品日后的发展。

我们团队在产品选型初期,分别调研了目前比较热门的openstack,以及前几年的明星产品convirt、ovirt,这几个产品可谓是典型的代表。

Openstack偏重于公有云,架构设计的很不错,其分布式、插件式的模块化架构,可以有效避免单点故障的发生,从发布之初便备受推崇,但是其存在的问题也同样令人头疼目前使用Openstack的大多是一些有实力的IDC、大型的互联网公司在用。而对于一般的企业来说,没有强大的开发和维护团队,并不敢大规模的采用openstack,初期使用一段时间后我们放弃了OS。

而前几年的convirt,在当时也掀起了一股使用热潮,其简单化的使用体验,足以满足小企业的虚拟化需求,但是他的问题是架构采用了集中式的架构,而且对于上了规模之后,也会带来性能方面的瓶颈,除非是把数据库等一些组件松藕合,解决起来也比较麻烦,所以到了后期也是不温不火,官方也停止了社区的更新和维护。

OVM架构选型二

      通过对以上产品的优劣势分析,我们决定采用用分布式、松耦合的模块化插件架构,分布式使其可以规避单点故障,达到业务持续高可用,松耦合的模块化特点让产品在后期的扩展性方面不受任何限制,使其向下可以兼容数据中心所有硬件(通过OVM标准的Rest API接口),向上可以实现插件式的我们即将需要的工作流引擎、计费引擎、报表引擎、桌面云引擎和自动化运维引擎。

而目前阶段我们则专心于实现虚拟化的全部功能,发掘内部对虚拟化的需求,打造一款真正简单、易用、稳定、可运维的一款虚拟化管理软件,并预留向上、向下的接口留作后期发展。(架构图大家可以查看刚才上面发的图片)

虚拟化技术选择

    Docker当下很火,其轻量级、灵活、高密度部署是优点,但是大规模使用还未成熟。许多场景还是需要依赖传统的虚拟化技术。所以我们选择传统虚拟化技术KVM+Docker,确保线上业务稳定性、连续性的同时,开发、测试环境又可以利用到Docker的轻量级、高密度和灵活。

     另外很多用户的生产环境存在不止一种虚拟化技术,例如KVM+Esxi组合、KVM+XenServer组合、KVM+Hyper-V组合,而目前的虚拟化管理平台,大多都是只支持一种Hypervisor的管理,用户想要维护不同的虚拟化技术的虚拟机,就要反复的在不同环境之间切换。

    基于此考虑,我和团队内部和外部一些同行选择兼容(兼容KVM、Esxi,Docker),并自主打造新一代虚拟化管理平台——混合虚拟化。

网络  

 网络方面,我们对所有Hypervisor的虚拟机使用统一的网络管理(包括Docker容器),这样做的一个好处就是可以减少运维工作量,降低网络复杂性。初期我们只实现2层的虚拟网络管理,为虚拟机和容器提供Vlan隔离、DHCP分配网络,当然也可以手工为虚拟机挑选一个网络,这个可以满足一般的虚拟化需求,后期我们会在此基础上增加虚拟网络防火墙、负载均衡。

存储

存储上面我们采用本地存储+NFS两种方式,对于一般中小企业来说,不希望购买高昂的商业存储,直接使用本地存储虚拟机的性能是最好的,而且我们也提供了存储快照、存储热迁移、虚拟机的无共享热迁移来提升业务安全。此外NFS作为辅助,可以为一些高风险业务提供HA。后期存储方面我们会考虑集成Ceph和GlusterFS存储来提升存储管理。

镜像中心

顾名思义,镜像中心就是用来存放镜像的。传统虚拟化我们使用NFS来作为镜像中心,所有宿主机共享一个镜像中心,这样可以更方便的来统一管理镜像,而针对Docker容器则保留了使用Docker自己的私有仓库,但是我们在WEB UI的镜像中心增加了从Docker私有仓库下载模板这么一个功能,实现了在同一个镜像中心的管理,后期我们会着重打造传统虚拟化镜像与Docker镜像的相互转换,实现两者内容的统一。

HA

OVM 主机HA依然坚持全兼容策略,支持对可管理的所有Hypervisor的HA。

在启用HA的资源池,当检测到一个Hypervisor故障,创建和运行在该Hypervisor共享存储上的虚拟机将在相同资源池下的另外一个主机上重启。

具体工作流程为:

第一次检测到故障会将该故障主机标记;

第二次检测依然故障将启动迁移任务;

迁移任务启动后将在该故障主机所在的资源池寻找合适的主机;

确定合适主机后,会将故障主机上所有的虚拟机自动迁移到合适的主机上面并重新启动;

 

VM分配策略

负载均衡

PERFORMANCE(性能): 这条策略分配虚拟机到不同的主机上。它挑选一组中可用资源最多的主机来部署虚拟机。如果有多个主机都有相同的资源可用,它使用一个循环算法,每个虚拟机分配到一个不同的主机上。

PROGRESSIVE(逐行扫描): 这条策略意味着,所有虚拟机将被分配在同一个主机上,直到它的资源被用尽。此项策略将一个主机资源使用完,然后再切换到另一个主机。

负载均衡级别

所有资源池: 如果选定此选项,则负载均衡级别策略将适用于所选定数据中心的所有资源池中的主机。

所有主机: 该策略将适用于所选数据中心单个资源池的所有主机。

特定主机: 该策略仅适用于所选的特定主机。

 

VM设计一

VM是整个虚拟化平台的核心,我们开发了一个单独的模块来负责虚拟机的相关操作。其采用异步通信和独立的并行操作,提升了虚拟机性能、稳定性和扩展性。

可扩展性:独立、并发

可追溯性:错误信息和log、监控控制台、性能

非阻塞操作:稳定性、改进重新配置、改进回滚、标准、统一的hypervisor通信、自动化测试

 

VM设计二

我们设计基于vApp来部署虚拟机,一个vApp可包含N个虚拟机:

N 个虚拟机配置

N个开机请求

我们希望并行运行N个配置(要求资源允许),并在配置后每个虚拟机请求一个开机。这些操作都是并发和独立的。

 

平台设计

OVM产品目前由三大组件、七大模块组成。其中三大组件分别为OVM UI、OVM API和OVM数据中心组件。

OVM UI提供WEB自服务界面,OVM API负责UI和数据中心组件之间的交互,OVM数据中心组件分别提供不同的功能。七大模块分别负责不同的功能实现,和三大组件之间分别交互。

VDC资源限额

管理员可以为每个VDC设置资源限额,防止资源的过度浪费。

账户管理

OVM提供存储SDK、备份SDK,以及虚拟防火墙SDK,轻松与第三方实现集成

获得帮助

下载请访问OVM社区官网:51ovm.com

使用过程中遇到什么问题及获得下载密码,加入OVM社区qq官方交流群:22265939

“ 实践是检验真理唯一标准“,OVM社区视您为社区的发展动力,此刻,诚邀您参与我们的调查,共同做出一款真正解决问题、放心的产品,一起推动国内虚拟化的进步和发展。

填写调查问卷!只需1分钟喔!
https://www.wenjuan.com/s/iiEVZv

Hbase/Hdfs删除节点

大数据/云计算采菊篱下 发表了文章 • 0 个评论 • 2202 次浏览 • 2015-11-30 00:16 • 来自相关话题

线上有台服务器随时可能会挂掉,所以需要把在这个服务器上hbase的regionserver和hdfs的datanode节点移除。然后重新拿台新服务器部署接管。
 
之前在文章 http://openskill.cn/article/178 中讲到怎么新增一个hdfs的datanode,所以我先讲一下怎么添加一个hbase的regionserver,然后再讲怎么删除! 

添加hbase regionserver节点

添加步骤如下:
1、在hbase  master上修改regionservers文件# cd hbase_install_dir/conf
# echo "new_hbase_node_hostname" >> ./regionservers2、如果你hbase集群使用自身zk集群的话,还需要修改hbase-site.xml文件,反之不用操作!# cd hbase_install_dir/conf
# vim hbase-site.xml
找到hbase.zookeeper.quorum属性 -->加入新节点3、同步以上修改的文件到hbase的各个节点上
4、在新节点上启动hbase regionserver# cd hbase_install_dir/bin/
# ./hbase-daemon.sh start regionserver5、在hbasemaster启动hbase shell用status命令确认一下集群情况hbase新增一个 regionserver节点补充完成了,下面介绍删除hbase和hdfs节点!
 
集群上既部署有Hadoop,又部署有HBase,因为HBase存储是基于Hadoop HDFS的,所以先要移除HBase节点,之后再移除Hadoop节点。添加则反之。

移除hbase regionserver节点

1、在0.90.2之前,我们只能通过在要卸载的节点上执行;我的hbase版本(0.98.7)# cd hbase_install_dir
# ./bin/hbase-daemon.sh stop regionserver来实现。这条语句执行后,该RegionServer首先关闭其负载的所有Region而后关闭自己。在关闭时,RegionServer在ZooKeeper中的"Ephemeral Node"会失效。此时,Master检测到RegionServer挂掉并把它作为一个宕机节点,并将该RegionServer上的Region重新分配到其他RegionServer。
 
注意:使用此方法前,一定要关闭HBase Load Balancer。关闭方法:hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3290 seconds总结:这种方法很大的一个缺点是该节点上的Region会离线很长时间。因为假如该RegionServer上有大量Region的话,因为Region的关闭是顺序执行的,第一个关闭的Region得等到和最后一个Region关闭并Assigned后一起上线。这是一个相当漫长的时间。以我这次的实验为例,现在一台RegionServer平均有1000个Region,每个Region Assigned需要4s,也就是说光Assigned就至少需要1个小时。2、自0.90.2之后,HBase添加了一个新的方法,即"graceful_stop",在你移除的服务器执行:# cd hbase_install_dir
# ./bin/graceful_stop.sh hostname该命令会自动关闭Load Balancer,然后Assigned Region,之后会将该节点关闭。除此之外,你还可以查看remove的过程,已经assigned了多少个Region,还剩多少个Region,每个Region 的Assigned耗时。
 
补充graceful stop的一些其他命令参数:# ./bin/graceful_stop.sh
Usage: graceful_stop.sh [--config &conf-dir>] [--restart] [--reload] [--thrift] [--rest] &hostname>
thrift If we should stop/start thrift before/after the hbase stop/start
rest If we should stop/start rest before/after the hbase stop/start
restart If we should restart after graceful stop
reload Move offloaded regions back on to the stopped server
debug Move offloaded regions back on to the stopped server
hostname Hostname of server we are to stop最终都需要我们手动打开load balancer:hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3590 seconds然后再开启:hbase(main):001:0> balance_switch true
false
0 row(s) in 0.3290 seconds对比两种方法,建议使用"graceful_stop"来移除hbase RegionServer节点。
官网说明:http://hbase.apache.org/0.94/book/node.management.html​  http://hbase.apache.org/book.html#decommission​  

移除hdfs datanode节点

1、在core-site.xml文件下新增如下内容<property>
<name>dfs.hosts.exclude</name>
<value>/hdfs_install_dir/conf/excludes</value>
</property>2、创建exclude文件,把需要删除节点的主机名写入# cd hdfs_install_dir/conf
# vim excludes
添加需要删除的节点主机名,比如 hdnode1 保存退出3、 然后在namenode节点执行如下命令,强制让namenode重新读取配置文件,不需要重启集群。# cd hdfs_install_dir/bin/
# ./hadoop dfsadmin -refreshNodes它会在后台进行Block块的移动
 4、 查看状态
等待第三步的操作结束后,需要下架的机器就可以安全的关闭了。# ./hadoop dfsadmin -report可以查看到现在集群上连接的节点 正在执行Decommission,会显示:
Decommission Status : Decommission in progress

执行完毕后,会显示:
Decommission Status : Decommissioned如下:Name: 10.0.180.6:50010
Decommission Status : Decommission in progress
Configured Capacity: 917033340928 (10.83 TB)
DFS Used: 7693401063424 (7 TB)
Non DFS Used: 118121652224 (110.00 GB)
DFS Remaining: 4105510625280(3.63 TB)
DFS Used%: 64.56%
DFS Remaining%: 34.45%
Last contact: Mon Nov 29 23:53:52 CST 2015也可以直接通过Hadoop 浏览器查看:
LIVE的节点可以查看到:http://master_ip:50070/dfsnodelist.jsp?whatNodes=LIVE
查看看到卸载的节点状态是:Decommission in progress
等待节点完成移除后,浏览:http://master_ip:50070/dfsnodelist.jsp?whatNodes=DEAD 结果如下:




完成后,删除的节点显示在dead nodes中。且其上的服务停止。Live Nodes中仅剩had2,had3
以上即为从Hadoop集群中Remove Node的过程,但是,有一点一定要注意:
hdfs-site.xml配置文件中dfs.replication值必须小于或者等于踢除节点后正常datanode的数量,即:dfs.replication <= 集群所剩节点数修改备份系数可以参考:http://heylinux.com/archives/2047.html

重载入删除的datanode节点 

1、修改namenode的core-site.xml文件,把我们刚刚加入的内容删除或者注释掉,我这里选择注释掉。<!--

<property>
<name>dfs.hosts.exclude</name>
<value>/root/hadoop/conf/excludes</value>
</property>

-->2、 再执行重载namenode的配置文件# ./bin/hadoop dfsadmin -refreshNodes3、最后去启动datanode上的datanode# ./bin/hadoop-daemon.sh start datanode
starting datanode, logging to /usr/local/hadoop/bin/../logs/hadoop-root-datanode-had1.out4、查看启动情况# jps
18653 Jps
19687 DataNode ---->启动正常重新载入HBase RegionServer节点
只需要重启regionserver进程即可。
参考:http://www.edureka.co/blog/commissioning-and-decommissioning-nodes-in-a-hadoop-cluster/
           https://pravinchavan.wordpress.com/2013/06/03/removing-node-from-hadoop-cluster/ 查看全部
线上有台服务器随时可能会挂掉,所以需要把在这个服务器上hbase的regionserver和hdfs的datanode节点移除。然后重新拿台新服务器部署接管。
 
之前在文章 http://openskill.cn/article/178 中讲到怎么新增一个hdfs的datanode,所以我先讲一下怎么添加一个hbase的regionserver,然后再讲怎么删除! 


添加hbase regionserver节点


添加步骤如下:
1、在hbase  master上修改regionservers文件
# cd hbase_install_dir/conf
# echo "new_hbase_node_hostname" >> ./regionservers
2、如果你hbase集群使用自身zk集群的话,还需要修改hbase-site.xml文件,反之不用操作!
# cd hbase_install_dir/conf
# vim hbase-site.xml
找到hbase.zookeeper.quorum属性 -->加入新节点
3、同步以上修改的文件到hbase的各个节点上
4、在新节点上启动hbase regionserver
# cd hbase_install_dir/bin/
# ./hbase-daemon.sh start regionserver
5、在hbasemaster启动hbase shell
用status命令确认一下集群情况
hbase新增一个 regionserver节点补充完成了,下面介绍删除hbase和hdfs节点!
 
集群上既部署有Hadoop,又部署有HBase,因为HBase存储是基于Hadoop HDFS的,所以先要移除HBase节点,之后再移除Hadoop节点。添加则反之。


移除hbase regionserver节点


1、在0.90.2之前,我们只能通过在要卸载的节点上执行;我的hbase版本(0.98.7)
# cd hbase_install_dir
# ./bin/hbase-daemon.sh stop regionserver
来实现。这条语句执行后,该RegionServer首先关闭其负载的所有Region而后关闭自己。在关闭时,RegionServer在ZooKeeper中的"Ephemeral Node"会失效。此时,Master检测到RegionServer挂掉并把它作为一个宕机节点,并将该RegionServer上的Region重新分配到其他RegionServer。
 
注意:使用此方法前,一定要关闭HBase Load Balancer。关闭方法:
hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3290 seconds
总结:
这种方法很大的一个缺点是该节点上的Region会离线很长时间。因为假如该RegionServer上有大量Region的话,因为Region的关闭是顺序执行的,第一个关闭的Region得等到和最后一个Region关闭并Assigned后一起上线。这是一个相当漫长的时间。以我这次的实验为例,现在一台RegionServer平均有1000个Region,每个Region Assigned需要4s,也就是说光Assigned就至少需要1个小时。
2、自0.90.2之后,HBase添加了一个新的方法,即"graceful_stop",在你移除的服务器执行:
# cd hbase_install_dir
# ./bin/graceful_stop.sh hostname
该命令会自动关闭Load Balancer,然后Assigned Region,之后会将该节点关闭。除此之外,你还可以查看remove的过程,已经assigned了多少个Region,还剩多少个Region,每个Region 的Assigned耗时。
 
补充graceful stop的一些其他命令参数:
# ./bin/graceful_stop.sh
Usage: graceful_stop.sh [--config &conf-dir>] [--restart] [--reload] [--thrift] [--rest] &hostname>
thrift If we should stop/start thrift before/after the hbase stop/start
rest If we should stop/start rest before/after the hbase stop/start
restart If we should restart after graceful stop
reload Move offloaded regions back on to the stopped server
debug Move offloaded regions back on to the stopped server
hostname Hostname of server we are to stop
最终都需要我们手动打开load balancer:
hbase(main):001:0> balance_switch false
true
0 row(s) in 0.3590 seconds
然后再开启:
hbase(main):001:0> balance_switch true
false
0 row(s) in 0.3290 seconds
对比两种方法,建议使用"graceful_stop"来移除hbase RegionServer节点。
官网说明:http://hbase.apache.org/0.94/book/node.management.html​  http://hbase.apache.org/book.html#decommission​  


移除hdfs datanode节点


1、在core-site.xml文件下新增如下内容
<property>
<name>dfs.hosts.exclude</name>
<value>/hdfs_install_dir/conf/excludes</value>
</property>
2、创建exclude文件,把需要删除节点的主机名写入
# cd hdfs_install_dir/conf
# vim excludes
添加需要删除的节点主机名,比如 hdnode1 保存退出
3、 然后在namenode节点执行如下命令,强制让namenode重新读取配置文件,不需要重启集群。
# cd hdfs_install_dir/bin/
# ./hadoop dfsadmin -refreshNodes
它会在后台进行Block块的移动
 4、 查看状态
等待第三步的操作结束后,需要下架的机器就可以安全的关闭了。
# ./hadoop dfsadmin -report
可以查看到现在集群上连接的节点 
正在执行Decommission,会显示: 
Decommission Status : Decommission in progress

执行完毕后,会显示:
Decommission Status : Decommissioned
如下:
Name: 10.0.180.6:50010
Decommission Status : Decommission in progress
Configured Capacity: 917033340928 (10.83 TB)
DFS Used: 7693401063424 (7 TB)
Non DFS Used: 118121652224 (110.00 GB)
DFS Remaining: 4105510625280(3.63 TB)
DFS Used%: 64.56%
DFS Remaining%: 34.45%
Last contact: Mon Nov 29 23:53:52 CST 2015
也可以直接通过Hadoop 浏览器查看:
LIVE的节点可以查看到:http://master_ip:50070/dfsnodelist.jsp?whatNodes=LIVE
查看看到卸载的节点状态是:Decommission in progress
等待节点完成移除后,浏览:http://master_ip:50070/dfsnodelist.jsp?whatNodes=DEAD 结果如下:
hdead.png

完成后,删除的节点显示在dead nodes中。且其上的服务停止。Live Nodes中仅剩had2,had3
以上即为从Hadoop集群中Remove Node的过程,但是,有一点一定要注意:
hdfs-site.xml配置文件中dfs.replication值必须小于或者等于踢除节点后正常datanode的数量,即:
dfs.replication <= 集群所剩节点数
修改备份系数可以参考:http://heylinux.com/archives/2047.html


重载入删除的datanode节点 


1、修改namenode的core-site.xml文件,把我们刚刚加入的内容删除或者注释掉,我这里选择注释掉。
<!--

<property>
<name>dfs.hosts.exclude</name>
<value>/root/hadoop/conf/excludes</value>
</property>

-->
2、 再执行重载namenode的配置文件
# ./bin/hadoop dfsadmin -refreshNodes
3、最后去启动datanode上的datanode
# ./bin/hadoop-daemon.sh start datanode
starting datanode, logging to /usr/local/hadoop/bin/../logs/hadoop-root-datanode-had1.out
4、查看启动情况
# jps
18653 Jps
19687 DataNode ---->启动正常
重新载入HBase RegionServer节点
只需要重启regionserver进程即可。
参考:http://www.edureka.co/blog/commissioning-and-decommissioning-nodes-in-a-hadoop-cluster/
           https://pravinchavan.wordpress.com/2013/06/03/removing-node-from-hadoop-cluster/

新增一个hdfs的DataNode节点

大数据/云计算采菊篱下 发表了文章 • 1 个评论 • 1640 次浏览 • 2015-11-11 01:51 • 来自相关话题

场景

在hadoop中的分布式文件系统hdfs中,当存储节点磁盘使用达到预警值是,我们需要新增一个数据存储节点,来存储数据!我这里hdfs的版本是2.2.0!新增方法:
[]静态添加[/][]动态添加[/]

静态添加

静态新增的方式,就是相当于我们起初部署hdfs集群规划一样,停止NameNode,新增一个DateNode数据节点,这种方法不适用于线上提供服务的场景,具体操作如下:

1、停止NameNode节点
# cd hdfs_install_dir/sbin/
# ./hadoop-deamon.sh stop namenode

2、修改配置文件slaves文件,并修改/etc/hosts记录把新增的节点对应的ip和hostname追加到各节点
# cd hdfs_install_dir/etc/hadoop/
# echo "new_datanode_hostname" >> ./slaves
# echo "new_datanode_ip new_datanode_hostname" >> /etc/hosts
然后再利用rsync 同步配置文件和hosts文件,到各节点

3、确保Hadoop/HDFS集群的NameNode可以对新节点进行SSH免密码登录。

4、重新启动NameNode节点

5、如果你希望各数据节点磁盘使用量达到一个相对平衡的状态,就是百分比,你还需要执行hadoop balance命令,后面会具体讲到!


动态添加

动态添加,不需要停止启动NameNode节点,具体步骤如下:

1、修改所有hdfs集群机器的配置文件slaves文件,并修改/etc/hosts记录把新增的节点对应的ip和hostname追加到各节点
# cd hdfs_install_dir/etc/hadoop/
# echo "new_datanode_hostname" >> ./slaves
# echo "new_datanode_ip new_datanode_hostname" >> /etc/hosts

如果你使用ansible管理的话,hdfs集群的集群做一个叫hdfs的分组,两条命令搞定:
# ansible hdfs -m shell -a 'echo "new_datanode_hostname" >> hdfs_install_dir/etc/hadoop/slaves'
# ansible hdfs -m shell -a 'echo "new_datanode_ip new_datanode_hostname" >> /etc/hosts'
这样所有的节点slaves文件和host文件都更新了!

2、启动新增的datanode节点
# cd hdfs_install_dir/sbin
# ./hadoop-daemon.sh start datanode

3、查看是否正常加入到集群
web查看方式:http://NameNode_ip:50070/dfsnodelist.jsp?whatNodes=LIVE
命令查看方式:cd hdfs_install_dir/bin/ && ./hadoop dfsadmin -report

4、数据再平衡
添加新节点时,HDFS不会自动重新平衡。然而,HDFS提供了一个手动调用的重新平衡(reblancer)工具。这个工具将整个集群中的数据块分布调整到一个可人工配置的百分比阈值。如果在其他现有的节点上有空间存储问题,再平衡就会根据阀值,然后平衡分布数据。

执行再平衡命令,可选参数-threshold指定了磁盘容量的余量百分比,用来判定一个节点的磁盘利用率是过低还是过高。一个利用不足的数据节点其利用率低于平均利用率−阈值。过度利用的数据节点其利用率高于平均利用率+阈值。该参数设置的越小,整个集群越平衡,但会花费更多的时间进行再平衡操作。默认阈值为10%。平衡执行命令如下:
# cd hdfs_install_dir/sbin/
# ./start-balancer.sh -threshold 5

-threshold参数就是是指定平衡的阈值。
-threshold的默认是10,即每个datanode节点的实际hdfs存储使用量/集群hdfs存储量

具体解释例子如下:
datanode hdfs使用量1000G;
集群总hdfs存储量10T即10000G;
则t值为1000/10000 = 0.1 = 10%
当执行balance的-t参数小于0.1时,集群进行balance;
命令为:start-balancer.sh -threshold 10 ;Expecting a number in the range of [1.0, 100.0]: 5%sh $HADOOP_HOME/bin/start-balancer.sh –t 10%
这个命令中-t参数后面跟的是HDFS达到平衡状态的磁盘使用率偏差值。如果机器与机器之间磁盘使用率偏差小于10%,那么我们就认为HDFS集群已经达到了平衡的状态。


标注知识点

1、 balance命令可以在namenode或者datanode上启动,也可以随时利用stop-balance.sh脚本停止平衡!

2、balance的默认带宽是1M/s。 如果你希望修改平衡数据的带宽大小可以用./hdfs dfsadmin -setBalancerBandwidth 124288000命令指定

3、slave文件是用于重启时使用。集群的start和stop需要读取slave文件。启用datanode时只要在hdfs-site中配置了namenode位置,就可以将信息push给namenode。 这就是为什么slaves文件很重要的原因。 查看全部


场景


在hadoop中的分布式文件系统hdfs中,当存储节点磁盘使用达到预警值是,我们需要新增一个数据存储节点,来存储数据!我这里hdfs的版本是2.2.0!
新增方法:
    []静态添加[/][]动态添加[/]


静态添加


静态新增的方式,就是相当于我们起初部署hdfs集群规划一样,停止NameNode,新增一个DateNode数据节点,这种方法不适用于线上提供服务的场景,具体操作如下:

1、停止NameNode节点
# cd hdfs_install_dir/sbin/
# ./hadoop-deamon.sh stop namenode

2、修改配置文件slaves文件,并修改/etc/hosts记录把新增的节点对应的ip和hostname追加到各节点
# cd hdfs_install_dir/etc/hadoop/
# echo "new_datanode_hostname" >> ./slaves
# echo "new_datanode_ip new_datanode_hostname" >> /etc/hosts
然后再利用rsync 同步配置文件和hosts文件,到各节点

3、确保Hadoop/HDFS集群的NameNode可以对新节点进行SSH免密码登录。

4、重新启动NameNode节点

5、如果你希望各数据节点磁盘使用量达到一个相对平衡的状态,就是百分比,你还需要执行hadoop balance命令,后面会具体讲到!


动态添加


动态添加,不需要停止启动NameNode节点,具体步骤如下:

1、修改所有hdfs集群机器的配置文件slaves文件,并修改/etc/hosts记录把新增的节点对应的ip和hostname追加到各节点
# cd hdfs_install_dir/etc/hadoop/
# echo "new_datanode_hostname" >> ./slaves
# echo "new_datanode_ip new_datanode_hostname" >> /etc/hosts

如果你使用ansible管理的话,hdfs集群的集群做一个叫hdfs的分组,两条命令搞定:
# ansible hdfs -m shell -a 'echo "new_datanode_hostname" >> hdfs_install_dir/etc/hadoop/slaves'
# ansible hdfs -m shell -a 'echo "new_datanode_ip new_datanode_hostname" >> /etc/hosts'
这样所有的节点slaves文件和host文件都更新了!

2、启动新增的datanode节点
# cd hdfs_install_dir/sbin
# ./hadoop-daemon.sh start datanode

3、查看是否正常加入到集群
web查看方式:http://NameNode_ip:50070/dfsnodelist.jsp?whatNodes=LIVE
命令查看方式:cd hdfs_install_dir/bin/ && ./hadoop dfsadmin -report

4、数据再平衡
添加新节点时,HDFS不会自动重新平衡。然而,HDFS提供了一个手动调用的重新平衡(reblancer)工具。这个工具将整个集群中的数据块分布调整到一个可人工配置的百分比阈值。如果在其他现有的节点上有空间存储问题,再平衡就会根据阀值,然后平衡分布数据。

执行再平衡命令,可选参数-threshold指定了磁盘容量的余量百分比,用来判定一个节点的磁盘利用率是过低还是过高。一个利用不足的数据节点其利用率低于平均利用率−阈值。过度利用的数据节点其利用率高于平均利用率+阈值。该参数设置的越小,整个集群越平衡,但会花费更多的时间进行再平衡操作。默认阈值为10%。平衡执行命令如下:
# cd hdfs_install_dir/sbin/
# ./start-balancer.sh -threshold 5

-threshold参数就是是指定平衡的阈值。
-threshold的默认是10,即每个datanode节点的实际hdfs存储使用量/集群hdfs存储量

具体解释例子如下:
datanode hdfs使用量1000G;
集群总hdfs存储量10T即10000G;
则t值为1000/10000 = 0.1 = 10%
当执行balance的-t参数小于0.1时,集群进行balance;
命令为:start-balancer.sh -threshold 10 ;
Expecting a number in the range of [1.0, 100.0]: 5%
sh $HADOOP_HOME/bin/start-balancer.sh –t 10%
这个命令中-t参数后面跟的是HDFS达到平衡状态的磁盘使用率偏差值。如果机器与机器之间磁盘使用率偏差小于10%,那么我们就认为HDFS集群已经达到了平衡的状态。


标注知识点


1、 balance命令可以在namenode或者datanode上启动,也可以随时利用stop-balance.sh脚本停止平衡! 

2、balance的默认带宽是1M/s。 如果你希望修改平衡数据的带宽大小可以用./hdfs dfsadmin -setBalancerBandwidth 124288000命令指定

3、slave文件是用于重启时使用。集群的start和stop需要读取slave文件。启用datanode时只要在hdfs-site中配置了namenode位置,就可以将信息push给namenode。 这就是为什么slaves文件很重要的原因。
云技术、大数据处理