方案:

  • 使用HAproxy:当其中一台ElasticSearch Master宕掉时,ElasticSearch集群会自动将运行正常的节点提升为Master,但HAproxy不会将失败的请求重新分发到新的Master Node
  • 使用ElasticSearch单search load balancer(外层负载均衡节点)双coordinator(调度节点)若干workhorse(数据节点)。先后在200并发Index、200并发Update测试下(跑在虚拟机下,线程太多就卡爆了),并前后分别测试了Down掉一台主coordinator、Down掉一台workhorse,都没有引起数据异常,集群工作正常

先贴一下使用HAproxy搭建集群失败的配置吧:

#全局配置
global
daemon
nbproc 4
pidfile /tmp/haproxy.pid #默认配置
defaults
mode http #默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK
retries 2 #两次连接失败就认为是服务器不可用,也可以通过后面设置
option redispatch #当serverId对应的服务器挂掉后,强制定向到其他健康的服务器
option httpclose #HAProxy会针对客户端的第一条请求的返回添加cookie并返回给客户端,客户端发送后续请求时会发送此cookie到HAProxy
#option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接
maxconn 4096 #默认的最大连接数
timeout connect 5000ms #连接超时
timeout client 30000ms #客户端超时
timeout server 30000ms #服务器超时
timeout check 2000 #心跳检测超时
log 127.0.0.1 local0 err #[err warning info debug] #统计页面配置
listen admin_stats
bind 0.0.0.0:8888 #监听端口
mode http #http的7层模式
option httplog #采用http日志格式
#log 127.0.0.1 local0 err
maxconn 10
stats refresh 30s #统计页面自动刷新时间
stats uri / #统计页面url
stats realm XingCloud\ Haproxy #统计页面密码框上提示文本
stats auth admin:admin #统计页面用户名和密码设置
#stats hide-version #隐藏统计页面上HAProxy的版本信息 #ElasticSearch Frontend
frontend eshttp
bind 0.0.0.0:9200
mode tcp
use_backend eshttp_server #ElasticSearch Backend
backend eshttp_server
server eshttp1 vm12:9200 cookie 1 check inter 2000 rise 3 fall 3 weight 2
server eshttp2 vm13:9200 cookie 2 check inter 2000 rise 3 fall 3 weight 1
server eshttp3_bk vm14:9200 cookie 3 check inter 1000 rise 3 fall 3 backup

采用ElasticSearch搭建集群的关键几个配置:

search load balancer(LB负载均衡节点):

cluster.name: harold					#集群名称
node.name: "harold_lb" #节点名称 # 3. You want this node to be neither master nor data node, but
# to act as a "search load balancer" (fetching data from nodes,
# aggregating results, etc.)
#
node.master: false
node.data: false discovery.zen.ping.unicast.hosts: ["vm11", "vm12", "vm13", "vm14", "vm15", "vm16"] #自动发现节点hosts

coordinator(Master调度节点):

cluster.name: harold					#集群名称
node.name: "harold_coordinator_1" #节点名称 # 2. You want this node to only serve as a master: to not store any data and
# to have free resources. This will be the "coordinator" of your cluster.
#
node.master: true
node.data: false discovery.zen.ping.unicast.hosts: ["vm11", "vm12", "vm13", "vm14", "vm15", "vm16"] #自动发现节点hosts

workhorse(Data数据节点):

cluster.name: harold					#集群名称
node.name: "harold_data_1" #节点名称 # 1. You want this node to never become a master node, only to hold data.
# This will be the "workhorse" of your cluster.
#
node.master: false
node.data: true discovery.zen.ping.unicast.hosts: ["vm11", "vm12", "vm13", "vm14", "vm15", "vm16"] #自动发现节点hosts

配置完,启动后,/_plugin/head/页面应该是这个样子:

这样配置完的集群应该就是类似这样的:

可以使用curl初始化Index的主分片复制分片:

curl -XPUT -d'{"settings":{"number_of_shards":6, "number_of_replicas":1}}' http://vm11:9200/app1

Tip:

number_of_shards 主分片在集群中的总数量

number_of_replicas 每个主分片的复制分片数量

#复制分片在今后的分布式集群变化过程中,随时都可以根据业务进行新增或减少:
curl -XPUT -d'{"number_of_replicas":2}' http://vm11:9200/app1/_settings
#另外,ElasticSearch在没有任何索引的情况下新增一个文档,便自动创建了索引,为避免发生这种情况,可以在配置文件中添加:
action.auto_create_index: false

删除Index:

curl -XDELETE http://vm11:9200/app1

在当前版本中,这样组建集群会有一个小问题:

当单独把Master CoordinatorDown掉后,/_plugin/head/插件页面会是这个样子:



但可喜的是,并不影响集群与集群客户端之间数据的CRUD操作。

数据有所改变而且较长一段时间后(大约10几分钟?),/_plugin/head/插件页面会恢复正常。

贴下PHP操作ElasticSearch的多进程并发测试代码吧,做下记录:

<?php
class es extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'es:test'; /**
* The console command description.
*
* @var string
*/
protected $description = 'Command description.'; private $hosts = ["vm11:9200"];
private $index = "app1";
private $type = "users1";
private $process = 200;
private $sum = 10000;
private $num_per_proc; /**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->sum % $this->process !== 0 && die("invalid num. \n");
$this->num_per_proc = $this->sum / $this->process;
} private function insert()
{
$es = new ClientBuilder();
$es->setHosts($this->hosts);
$client = $es->build(); $words = str_split("abcdefghijklmnopqrstuvwxyz"); $birth_year = [];
for ($i = 1; $i <= 50; $i++) {
$birth_year[] = 1960 + $i;
} $type = ['1', '2', '3', '4']; $process = [];
for ($p = 0; $p < $this->process; $p++) {
$process[] = new \swoole_process(function () use ($client, $birth_year, $type, $words, $p) {
for ($i = $this->num_per_proc * $p; $i < $this->num_per_proc * ($p + 1); $i++) {
$client->index([
'index' => $this->index,
'type' => $this->type,
'id' => $i,
'body' => [
'birth_year' => $birth_year[array_rand($birth_year)],
'type' => $type[array_rand($type)],
'name' => $words[mt_rand(0, 25)] . $words[mt_rand(0, 25)] . $words[mt_rand(0, 25)] . $words[mt_rand(0, 25)],
'height' => mt_rand(150, 200),
'weight' => mt_rand(40, 200),
'test' => 1,
'userid' => $i
]
]);
}
});
} foreach ($process as $p) {
$pid = $p->start();
echo $pid . "\n";
}
} private function update()
{
$es = new ClientBuilder();
$es->setHosts($this->hosts);
$client = $es->build(); $process = [];
for ($i = 0; $i < $this->process; $i++) {
$process[] = new \swoole_process(function () use ($client, $i) {
$response = $client->search([
'index' => $this->index,
'type' => $this->type,
'size' => $this->num_per_proc,
'from' => $this->num_per_proc * $i,
'sort' => "userid:asc"
]);
foreach ($response['hits']['hits'] as $v) {
$id = $v['_id'];
$test = $v['_source']['test'];
$test++;
file_put_contents("/tmp/s", $test . "\n", FILE_APPEND); $client->update([
'index' => $this->index,
'type' => $this->type,
'id' => $id,
'body' => [
'doc' => [
'test' => $test
]
]
]);
}
});
} foreach ($process as $p) {
$pid = $p->start();
echo $pid . "\n";
}
} private function gets()
{
$es = new ClientBuilder();
$es->setHosts($this->hosts);
$client = $es->build(); $response = $client->search([
'index' => $this->index,
'type' => $this->type,
'size' => 5000,
'from' => 500,
'sort' => "userid:asc"
]);
foreach ($response['hits']['hits'] as $v) {
$id = $v['_id'];
$test = $v['_source']['test'];
// file_put_contents("/tmp/s", $test . "\n", FILE_APPEND);
var_dump($test);
}
} /**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->insert();
}
}

ElasticSearch 高可用分布式集群搭建,与PHP多线程测试的更多相关文章

  1. Dubbo+zookeeper构建高可用分布式集群(二)-集群部署

    在Dubbo+zookeeper构建高可用分布式集群(一)-单机部署中我们讲了如何单机部署.但没有将如何配置微服务.下面分别介绍单机与集群微服务如何配置注册中心. Zookeeper单机配置:方式一. ...

  2. 一张图讲解最少机器搭建FastDFS高可用分布式集群安装说明

     很幸运参与零售云快消平台的公有云搭建及孵化项目.零售云快消平台源于零售云家电3C平台私有项目,是与公司业务强耦合的.为了适用于全场景全品类平台,集团要求项目平台化,我们抢先并承担了此任务.并由我来主 ...

  3. Hadoop-HA(高可用)集群搭建

    Hadoop-HA集群搭建 一.基础准备工作 1.准备好5台Linux系统虚拟服务器或物理服务器 我这里演示采用虚拟服务器搭建Hadoop-HA集群,各自功能分配如下: NameNode节点:vt-s ...

  4. redis高可用分布式集群

    一,高可用 高可用(High Availability),是当一台服务器停止服务后,对于业务及用户毫无影响. 停止服务的原因可能由于网卡.路由器.机房.CPU负载过高.内存溢出.自然灾害等不可预期的原 ...

  5. Redis 高可用分布式集群

    一,高可用 高可用(High Availability),是当一台服务器停止服务后,对于业务及用户毫无影响. 停止服务的原因可能由于网卡.路由器.机房.CPU负载过高.内存溢出.自然灾害等不可预期的原 ...

  6. redis详解(四)-- 高可用分布式集群

    一,高可用 高可用(High Availability),是当一台服务器停止服务后,对于业务及用户毫无影响. 停止服务的原因可能由于网卡.路由器.机房.CPU负载过高.内存溢出.自然灾害等不可预期的原 ...

  7. 高可用k8s集群搭建

    虚拟机选择 Win10 Hyper-V 总体架构 三个master,三个node master的组件 etcd kube-apiserver kube-controller-manager kube- ...

  8. 高可用mysql集群搭建

    对web系统来说,瓶颈大多在数据库和磁盘IO上面,而不是服务器的计算能力.对于系统伸缩性我们一般有2种解决方案,scale-up(纵向扩展)和scale-out(横向扩展).前者如扩内存,增加单机性能 ...

  9. 4 种高可用 RocketMQ 集群搭建方案!

    背景 笔者所在的业务线,最初化分为三个服务,由于业务初期业务复杂度相对简单,三个业务服务都能很好的独立完成业务功能. 随着产品迭代,业务功能越来越多后慢慢也要面对高并发.业务解耦.分布式事务等问题,所 ...

随机推荐

  1. sublime text 3 licence code

    Update:2016年3月9日09:14:12 可用 —– BEGIN LICENSE —–Michael BarnesSingle User LicenseEA7E-8213858A353C41 ...

  2. Object-C基础

    cocoa 类: 传统的写法:Demo.h // // Demo.h // demoClass // // Created by 王 on 13-12-16. // Copyright (c) 201 ...

  3. SQL扫描并执行文件夹里的sql脚本

    场景:项目数据库操作全部使用存储过程实现.每天都会有很多存储过程更新/增加,人工对测试环境中存储过程更新,会有一定概率出现遗漏,也麻烦!所以,需要一个工具将文件夹中所有存         储过程执行一 ...

  4. U8记账凭证修改方法汇总

    在输入记账凭证时,尽管账务系统提供了多种控制错误的措施,但错误凭证的出现是难免的,为此,系统必须能够提供对错误凭证修改的功能.目前,许多财 务软件(如:用友.安易.三门)都提供了“反审核.反记账.反结 ...

  5. 【C#】ASP.NET网页中添加单点登录功能

    背景 首先,要说明的是,原先需求定义的是,同一个账号只能同时有一个人来登录,如果另外一个登录的话,前一个登陆者就自动被踢掉.本来原先要做成存储到服务器的数据库中,但是后来如果是非正常退出的话 下次就没 ...

  6. mongodb - 命令行增删改查

    # insert db.person.insert({ }) db.person.insert({ }) db.person.insert({ }) db.person.insert({ }) # s ...

  7. [NOIP 2014复习]第三章:动态规划——NOIP历届真题回想

    背包型动态规划 1.Wikioi 1047 邮票面值设计 题目描写叙述 Description 给定一个信封,最多仅仅同意粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定全部的邮票数量都 ...

  8. 【JavaScript】直接拿来用!最火的前端开源项目(一)

    摘要:对于开发者而言,了解当下比较流行的开源项目很是必要.利用这些项目,有时能够让你达到事半功倍的效果.为此,本文整理GitHub上最火的前端开源项目列表,这里按分类的方式列出前九个. 对于开发者而言 ...

  9. dsPIC33EP 高速PWM模块初始化设置及应用

    //文件 p33pwm6.h #ifndef _P33PWM6_H_ #define _P33PWM6_H_ //#include "p33pwm6.h" #define FSYN ...

  10. Android Studio中导入第三方库

    之前开发Android都是使用的eclipse,近期因为和外国朋友Timothy一起开发一款应用,他是从WP平台刚切换使用Android的,使用的开发环境时Android Studio,为了便于项目的 ...