集群是一种计算机系统, 它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。集群计算机通常用来改进单个计算机的计算速度和/或可靠性。一般情况下集群计算机比单个计算机,比如工作站或超级计算机性能价格比要高得多。
集群拥有以下两个特点:
集群必须拥有以下两大能力:
负载均衡和错误恢复要求各服务实体中有执行同一任务的资源存在,而且对于同一任务的各个资源来说,执行任务所需的信息视图必须是相同的。
说到集群,可能大家会立刻联想到另一个和它很相近的一个词----“分布式”。那么集群和分布式是一回事吗?有什么联系和区别呢?
相同点:
分布式和集群都是需要有很多节点服务器通过网络协同工作完成整体的任务目标。
不同点:
分布式是指将业务系统进行拆分,即分布式的每一个节点都是实现不同的功能。而集群每个节点做的是同一件事情。
如下图,每个人都有不同的分工,一起协作干一件事,叫做“分布式”
再看下图:每个划桨人干的都是一样的活,叫做集群。
分布式的每一个节点也可以做成集群。其实这个赛龙舟的图,总整体来看属于分布式,包括打鼓和划桨两个分布式节点,而划桨的节点又是集群的形态。
大部分分布式应用需要一个主控、协调器或者控制器来管理物理分布的子进程。目前,大多数都要开发私有的协调程序,缺乏一个通用机制,协调程序的反复编写浪费,且难以形成通用、伸缩性好的协调器,zookeeper提供通用的分布式锁服务,用以协调分布式应用。所以说zookeeper是分布式应用的协作服务。
zookeeper作为注册中心,服务器和客户端都要访问,如果有大量的并发,肯定会有等待。所以可以通过zookeeper集群解决。
下面是zookeeper集群部署结构图:
Zookeeper的启动过程中leader选举是非常重要而且最复杂的一个环节。那么什么是leader选举呢?zookeeper为什么需要leader选举呢?zookeeper的leader选举的过程又是什么样子的?
首先我们来看看什么是leader选举。其实这个很好理解,leader选举就像总统选举一样,每人一票,获得多数票的人就当选为总统了。在zookeeper集群中也是一样,每个节点都会投票,如果某个节点获得超过半数以上的节点的投票,则该节点就是leader节点了。
1.编号1的zk服务启动,给自己投票,投票消息是(zid,myId)(0, 1),myId是服务器唯一编号,zid在下面解释,这时候因为其他服务器还没启动无法,编号1的服务无法接收到反馈消息,然后进入LOOKING状态
2.编号2的zk服务启动,这时候,会广播一条选举请求,请求消息是(0, 2),这时候会与编号1交换消息,先比对zid,这里发现zid相同,再比较myId,编号2的id比编号1的大所以,编号1会在下一轮修改投票消息为(0, 2),这时候编号1和编号2都一致投票编号2,但是这时候编号2才获得两票,无法成为leader
3.编号3的ZK服务启动,这时候广播一条选举请求,请求消息为(0,3),与编号1,2互相交互选举信息,先比对zId再比对myId,最后一致认为编号3的服务最大,编号1和编号2的投票信息改成(0,3),这时候编号3获得3票,编号3成为leader,编号1,2的zk服务把LOOKING状态改成follower
4.编号4启动,已经有leader了,从leader那边同步信息,成为follower
5.编号5服务启动,同编号4
这个就是ZK集群服务器启动的时候的选举流程,下面解释一下,zId这玩意
zId,有三个值,一个cZid(对应为节点创建时间),一个是mZid(对应为节点修改时间),pZid(改节点的子节点对应变化时间,与更下级的子节点没有关系)
在zk选举中的zId是zk集群中一次事物变化后累加的值,当服务启动从0开始,后面在集群顺利运行过程中(已经选举出leader,没有选举出leader的话zk集群是无法工作的),当leader广播一次事物,最后半数通过,成功提交一次事物,那么zId就会加1,那么可见,我们能通过这个zId保证选举出事物最新的一台,防止那些旧的,没有最新数据的zk服务器成为leader
以一个简单的例子来说明整个选举的过程.
假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器依序启动,来看看会发生什么 。
1) 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态
2) 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态.
3) 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader.
4) 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了.
5) 服务器5启动,同4一样,当小弟
真实的集群是需要部署在不同的服务器上的,但是在我测试时同时启动十几个虚拟机内存会吃不消,所以我会搭建伪集群,也就是把所有的服务都搭建在一台虚拟机上,用端口进行区分。
这里搭建一个三个节点的Zookeeper集群(伪集群)。
重新部署一台虚拟机作为我们搭建集群的测试服务器。
(1)安装JDK 【这个很简单的百度一下就好,朋友】。
(2)Zookeeper压缩包上传到服务器
(3)将Zookeeper解压 ,创建data目录 ,将 conf下zoo_sample.cfg 文件改名为 zoo.cfg
(4)建立/usr/local/zookeeper-cluster目录,将解压后的Zookeeper复制到以下三个目录
/usr/local/zookeeper-cluster/zookeeper-1
/usr/local/zookeeper-cluster/zookeeper-2
/usr/local/zookeeper-cluster/zookeeper-3
命令行如下:
[root@localhost ~]# mkdir /usr/local/zookeeper-cluster
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/zookeeper-cluster/zookeeper-1
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/zookeeper-cluster/zookeeper-2
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/zookeeper-cluster/zookeeper-3
(5) 配置每一个Zookeeper 的dataDir(zoo.cfg) clientPort 分别为2181 2182 2183
修改/usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg
clientPort=2181
dataDir=/usr/local/zookeeper-cluster/zookeeper-1/data
修改/usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg
clientPort=2182
dataDir=/usr/local/zookeeper-cluster/zookeeper-2/data
修改/usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg
clientPort=2183
dataDir=/usr/local/zookeeper-cluster/zookeeper-3/data
(1)在每个zookeeper的 data 目录下创建一个 myid 文件,内容分别是1、2、3 。这个文件就是记录每个服务器的ID
------知识点小贴士------
如果你要创建的文本文件内容比较简单,我们可以通过echo 命令快速创建文件
格式为:
echo 内容 >文件名
例如我们为第一个zookeeper指定ID为1,则输入命令 echo 1 > myid
(2)在每一个zookeeper 的 zoo.cfg配置客户端访问端口(clientPort)和集群服务器IP列表。
集群服务器IP列表如下
server.1=192.168.25.140:2881:3881
server.2=192.168.25.140:2882:3882
server.3=192.168.25.140:2883:3883
解释:server.服务器ID=服务器IP地址:服务器之间通信端口:服务器之间投票选举端口
启动集群就是分别启动每个实例。
启动后我们查询一下每个实例的运行状态
先查询第一个服务
Mode为follower表示是跟随者(从)
再查询第二个服务Mod 为leader表示是领导者(主)
查询第三个为跟随者(从)
(1)首先我先测试如果是从服务器挂掉,会怎么样
把3号服务器停掉,观察1号和2号,发现状态并没有变化
由此得出结论,3个节点的集群,从服务器挂掉,集群正常
(2)我再把1号服务器(从服务器)也停掉,查看2号(主服务器)的状态,发现已经停止运行了。
由此得出结论,3个节点的集群,2个从服务器都挂掉,主服务器也无法运行。因为可运行的机器没有超过集群总数量的半数。
(3)我再次把1号服务器启动起来,发现2号服务器又开始正常工作了。而且依然是领导者。
(4)我把3号服务器也启动起来,把2号服务器停掉(汗~~干嘛?领导挂了?)停掉后观察1号和3号的状态。
发现新的leader产生了~
由此得出结论,当集群中的主服务器挂了,集群中的其他服务器会自动进行选举状态,然后产生新得leader
(5)我再次测试,当我们把2号服务器重新启动起来(汗~~这是诈尸啊!)启动后,会发生什么?2号服务器会再次成为新的领导吗?我们看结果
我们会发现,2号服务器启动后依然是跟随者(从服务器),3号服务器依然是领导者(主服务器),没有撼动3号服务器的领导地位。哎~退休了就是退休了,说了不算了,哈哈。
由此我们得出结论,当领导者产生后,再次有新服务器加入集群,不会影响到现任领导者。
修改服务提供者和服务调用者的spring 配置文件
<dubbo:registry
protocol="zookeeper" address="192.168.25.140:2181,192.168.25.140:2182,192.168.25.140:2183">
dubbo:registry>
为了方便操作,我们将在一台机器上搭建3个Elasticsearch,实现集群。配置环境如下:
节点名字 | IP | HTTP端口 | TCP端口 |
---|---|---|---|
noted-1 | 192.168.211.128 | 9201 | 9301 |
node-2 | 192.168.211.128 | 9202 | 9302 |
node-3 | 192.168.211.128 | 9203 | 9303 |
把下载的 elasticsearch-5.6.8.tar.gz 拷贝到服务器中 /usr/local/server/es/es1 目录下,并解压。
[root@localhost es1]# tar -xf elasticsearch-5.6.8.tar.gz
先永久关闭防火墙:
[root@localhost config]# chkconfig iptables off
centos7关闭防火墙命令变了,请自行百度,为了测试方便,我在这里关闭防火墙了。朋友你要是工作中这么干,会有惊喜的哦。
因为修改配置,可能需要重新切换用户,所以这里先创建用户账号
[root@localhost es]# useradd es
[root@localhost es]# passwd es
Changing password for user es.
New password:
BAD PASSWORD: it is too simplistic/systematic
BAD PASSWORD: is too simple
Retype new password:
passwd: all authentication tokens updated successfully.
目录授权
[root@localhost es]# chown -R es:es es1
修改elasticsearch.yml配置
[root@localhost /]# cd /usr/local/server/es/es1/elasticsearch-5.6.8/config
[root@localhost config]# vi elasticsearch.yml
修改如下:
# ======================== Elasticsearch Configuration =========================
#
# NOTE: Elasticsearch comes with reasonable defaults for most settings.
# Before you set out to tweak and tune the configuration, make sure you
# understand what are you trying to accomplish and the consequences.
#
# The primary way of configuring a node is via this file. This template lists
# the most important settings you may want to configure for a production cluster.
#
# Please consult the documentation for further information on configuration options:
# https://www.elastic.co/guide/en/elasticsearch/reference/index.html
#
# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
#集群名称
cluster.name: es-cluster
#
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
#节点名称,其余两个节点分别为node-2 和node-3
node.name: node-1
#
# Add custom attributes to the node:
#
#node.attr.rack: r1
#
# ----------------------------------- Paths ------------------------------------
#
# Path to directory where to store the data (separate multiple locations by comma):
#数据存储路径
path.data: ../data
#
# Path to log files:
#日志存储路径
path.logs: ../logs
#
# ----------------------------------- Memory -----------------------------------
#
# Lock the memory on startup:
#
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
#
# Make sure that the heap size is set to about half the memory available
# on the system and that the owner of the process is allowed to use this
# limit.
#
# Elasticsearch performs poorly when the system is swapping the memory.
#
# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
#绑定IP
network.host: 192.168.211.128
#
# Set a custom port for HTTP:
#置对外服务的http端口,默认为9201
http.port: 9201
#设置节点间交互的tcp端口,默认是9300
transport.tcp.port: 9301
#
# For more information, consult the network module documentation.
#
# --------------------------------- Discovery ----------------------------------
#
# Pass an initial list of hosts to perform discovery when new node is started:
# The default list of hosts is ["127.0.0.1", "[::1]"]
#这提供了自动集群体验,而无需进行任何配置。数组设置或逗号分隔的设置。每个值的形式应该是host:port或host
discovery.zen.ping.unicast.hosts: ["192.168.211.128:9301", "192.168.211.128:9302", "192.168.211.128:9303"]
#
# Prevent the "split brain" by configuring the majority of nodes (total number of master-eligible nodes / 2 + 1):
#集群中的脑裂问题的最小个数
discovery.zen.minimum_master_nodes: 2
#
# For more information, consult the zen discovery module documentation.
#
# ---------------------------------- Gateway -----------------------------------
#
# Block initial recovery after a full cluster restart until N nodes are started:
#
#gateway.recover_after_nodes: 3
#
# For more information, consult the gateway module documentation.
#
# ---------------------------------- Various -----------------------------------
#
# Require explicit names when deleting indices:
#
#action.destructive_requires_name: true
参数说明
cluster.name 集群的名字
node.name 节点名字
network.host 网络地址
http.port http 端口
path.data 数据的存储路径
path.log 日志的存储路径
discovery.zen.ping.unicast.hosts 集群节点
discovery.zen.minimum_master_nodes 集群节点个数
bootstrap.memory_lock 是否锁定内存,不适用虚拟内存
修改jvm.options,es默认使用内存为2G,我等会需要在一台虚拟机上配置3台ElasticSearch,所以最好将虚拟机内存调整到3~4G,每台es使用内存调整为512m(我的电脑是弱鸡)。
修改jvm.options
-Xms512m
-Xmx512m
[root@localhost /]$ cd /usr/local/server/es/es1/elasticsearch-5.6.8/bin
[root@localhost bin]$ ./elasticsearch
当前操作系统为centos6.5,会出现如下警告,这里只需要升级centos内核即可解决,这里我们可以直接忽略。
错误信息:
解决方法:
修改limits.conf文件 ,在该文件结尾添加如下配置:
vim /etc/security/limits.conf
添加内容如下:
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
* soft memlock unlimited
* hard memlock unlimited
修改/etc/security/limits.d/90-nproc.conf,将1024改成2048
[root@localhost bin]# vim /etc/security/limits.d/90-nproc.conf
* soft nproc 1024
改成
* soft nproc 2048
修改/etc/sysctl.conf,追加如下代码
vm.max_map_count=655360
执行sysctl -p 会出现如下参数配置信息
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
vm.max_map_count = 655360
切换用户 并切换回来使其生效:
[root@localhost config]# chkconfig iptables off
[root@localhost config]# su es
[es@localhost config]$ su - root
密码:
[root@localhost ~]#
重新启动测试
[es@localhost /]$ cd /usr/local/server/es/es1/elasticsearch-5.6.8/bin
[es@localhost bin]$ ./elasticsearch
[root@localhost ~]# curl -get 192.168.25.129:9201
{
"name" : "B852paX",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "cKkCUQ6oQReg44Z6Tvtcrg",
"version" : {
"number" : "5.6.8",
"build_hash" : "688ecce",
"build_date" : "2018-02-16T16:46:30.010Z",
"build_snapshot" : false,
"lucene_version" : "6.6.1"
},
"tagline" : "You Know, for Search"
}
[root@localhost ~]#
访问测试如下:
我们可以直接利用刚才配置好的es,修改下配置参数即可实现集群。我们参考下面的配置信息修改es配置文件节点即可实现集群。
节点名字 | IP | HTTP端口 | TCP端口 |
---|---|---|---|
noted-1 | 192.168.211.128 | 9201 | 9301 |
node-2 | 192.168.211.128 | 9202 | 9302 |
node-3 | 192.168.211.128 | 9203 | 9303 |
将es1节点拷贝2份,分别为es2,es3,es2为node-2节点的配置,es3为node-3的配置,代码如下:
[root@localhost es]# cp -r es1 es2
[root@localhost es]# cp -r es1 es3
[root@localhost es]# ls
elasticsearch-5.6.8.tar.gz es1 es2 es3
对es2和es3目录授权给es用户
[root@localhost es]# chown -R es:es es2
[root@localhost es]# chown -R es:es es3
修改elasticsearch.yml
[root@localhost /]# cd /usr/local/server/es/es2/elasticsearch-5.6.8/config
[root@localhost config]# vi elasticsearch.yml
修改如下:
#节点名称
node.name: node-2
#置对外服务的http端口,默认为9200
http.port: 9202
#设置节点间交互的tcp端口,默认是9300
transport.tcp.port: 9302
修改完成后,记得删除data和logs目录
[root@localhost elasticsearch-5.6.8]# rm -rf data
[root@localhost elasticsearch-5.6.8]# rm -rf logs
修改elasticsearch.yml
[root@localhost /]# cd /usr/local/server/es/es3/elasticsearch-5.6.8/config
[root@localhost config]# vi elasticsearch.yml
修改如下:
#节点名称
node.name: node-3
#置对外服务的http端口,默认为9200
http.port: 9203
#设置节点间交互的tcp端口,默认是9300
transport.tcp.port: 9303
修改完成后,记得删除data和logs目录
[root@localhost elasticsearch-5.6.8]# rm -rf data
[root@localhost elasticsearch-5.6.8]# rm -rf logs
进入es2的elasticsearch-5.6.8/bin目录,然后启动
[es@localhost bin]$ ./elasticsearch
进入es3的elasticsearch-5.6.8/bin目录,然后启动
[es@localhost bin]$ ./elasticsearch
测试如下图:
http://192.168.211.128:9201/
http://192.168.211.128:9202/
http://192.168.211.128:9203/
IK分词器下载地址https://github.com/medcl/elasticsearch-analysis-ik/releases
将ik分词器上传到服务器上,先上传到第1个es的plugins目录下,并解压,并将解压后的ik文件,拷贝到每个es的plugins目录下(记得解压后查看一下确保plugins目录下的分词器文件夹名是ik)。
[root@localhost plugins]# unzip elasticsearch-analysis-ik-5.6.8.zip -d ./ik
[root@localhost plugins]# cp -r ik /usr/local/server/es/es2/elasticsearch-5.6.8/plugins
[root@localhost plugins]# cp -r ik /usr/local/server/es/es3/elasticsearch-5.6.8/plugins
http://192.168.211.128:9200/_analyze?analyzer=ik_smart&pretty=true&text=我是程序员
elasticsearch-head需要依赖nodejs,我们需要先安装一次nodejs,如下安装:
yum install epel-release
yum install nodejs npm
查看对应版本
[root@localhost es]# node -v
v5.12.0
[root@localhost es]# npm -v
3.8.6
grunt添加,并加入到环境变量中
npm install grunt --save-dev
安装相关插件
npm install grunt-contrib-clean --registry=https://registry.npm.taobao.org
npm install grunt-contrib-concat --registry=https://registry.npm.taobao.org
npm install grunt-contrib-watch --registry=https://registry.npm.taobao.org
npm install grunt-contrib-connect --registry=https://registry.npm.taobao.org
npm install grunt-contrib-copy --registry=https://registry.npm.taobao.org
npm install grunt-contrib-jasmine --registry=https://registry.npm.taobao.org
修改所有es的elasticsearch.yml配置文件,允许跨域,添加如下代码:
http.cors.enabled: true
http.cors.allow-origin: "*"
重启Elasticsearch ,加一个参数-d 表示后台启动
[root@localhost bin]# ./elasticsearch -d
启动elasticsearch-head,一下是后台启动方式
npm run start &
访问http://192.168.211.128:9100/,测试效果如下:
在项目中,只需要修改下节点配置即可实现使用ES集群。
<elasticsearch:transport-client id="client"
cluster-name="es-cluster"
cluster-nodes="192.168.211.128:9301,192.168.211.128:9302,192.168.211.128:9303" />
为何要搭建Redis集群。Redis是在内存中保存数据的,而我们的电脑一般内存都不大,这也就意味着Redis不适合存储大数据,适合存储大数据的是Hadoop生态系统的Hbase或者是MogoDB。Redis更适合处理高并发,一台设备的存储能力是很有限的,但是多台设备协同合作,就可以让内存增大很多倍,这就需要用到集群。
Redis集群搭建的方式有多种,例如使用客户端分片、Twemproxy、Codis等,但从redis 3.0之后版本支持redis-cluster集群,它是Redis官方提出的解决方案,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。其redis-cluster架构图如下:
客户端与 redis 节点直连,不需要中间 proxy 层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽.
(1)redis-cluster 把所有的物理节点映射到[0-16383]slot 上,cluster 负责维护
node<->slot<->value
(2)Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
例如三个节点:槽分布的值如下:
SERVER1: 0-5460
SERVER2: 5461-10922
SERVER3: 10923-16383
(1)选举过程是集群中所有master参与,如果半数以上master节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操作. 故障节点对应的从节点自动升级为主节点
(2)什么时候整个集群不可用(cluster_state:fail)?
如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态.
需要 6 台 redis 服务器。搭建伪集群。
需要 6 个 redis 实例。
需要运行在不同的端口 7001-7006
(1)安装gcc
Redis 是 c 语言开发的。安装 redis 需要 c 语言的编译环境。如果没有 gcc 需要在线安装。
yum install gcc-c++
(2)使用yum命令安装 ruby (我们需要使用ruby脚本来实现集群搭建)
yum install ruby
yum install rubygems
----- 知识点小贴士 -----
Ruby,一种简单快捷的面向对象(面向对象程序设计)脚本语言,在20世纪90年代由日本人松本行弘(Yukihiro Matsumoto)开发,遵守GPL协议和Ruby License。它的灵感与特性来自于 Perl、Smalltalk、Eiffel、Ada以及 Lisp 语言。由 Ruby 语言本身还发展出了JRuby(Java平台)、IronRuby(.NET平台)等其他平台的 Ruby 语言替代品。Ruby的作者于1993年2月24日开始编写Ruby,直至1995年12月才正式公开发布于fj(新闻组)。因为Perl发音与6月诞生石pearl(珍珠)相同,因此Ruby以7月诞生石ruby(红宝石)命名
RubyGems简称gems,是一个用于对 Ruby组件进行打包的 Ruby 打包系统
(3)将redis源码包上传到 linux 系统 ,解压redis源码包
(4)编译redis源码 ,进入redis源码文件夹
make
看到以下输出结果,表示编译成功
(5)创建目录/usr/local/redis-cluster目录, 安装6个redis实例,分别安装在以下目录
/usr/local/redis-cluster/redis-1
/usr/local/redis-cluster/redis-2
/usr/local/redis-cluster/redis-3
/usr/local/redis-cluster/redis-4
/usr/local/redis-cluster/redis-5
/usr/local/redis-cluster/redis-6
以第一个redis实例为例,命令如下
make install PREFIX=/usr/local/redis-cluster/redis-1
出现此提示表示成功,按此方法安装其余5个redis实例
(6)复制配置文件 将 /redis-3.0.0/redis.conf 复制到redis下的bin目录下
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-1/bin
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-2/bin
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-3/bin
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-4/bin
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-5/bin
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-6/bin
(1)修改每个redis节点的配置文件redis.conf
修改运行端口为7001 (7002 7003 …)
将cluster-enabled yes 前的注释去掉(632行)
(2)启动每个redis实例
以第一个实例为例,命令如下
cd /usr/local/redis-cluster/redis-1/bin/
./redis-server redis.conf
把其余的5个也启动起来,然后查看一下是不是都启动起来了
[root@localhost ~]# ps -ef | grep redis
root 15776 15775 0 08:19 pts/1 00:00:00 ./redis-server *:7001 [cluster]
root 15810 15784 0 08:22 pts/2 00:00:00 ./redis-server *:7002 [cluster]
root 15831 15813 0 08:23 pts/3 00:00:00 ./redis-server *:7003 [cluster]
root 15852 15834 0 08:23 pts/4 00:00:00 ./redis-server *:7004 [cluster]
root 15872 15856 0 08:24 pts/5 00:00:00 ./redis-server *:7005 [cluster]
root 15891 15875 0 08:24 pts/6 00:00:00 ./redis-server *:7006 [cluster]
root 15926 15895 0 08:24 pts/7 00:00:00 grep redis
(3)上传redis-3.0.0.gem 到~目录,并且在 ~目录下,安装 ruby用于搭建redis集群的脚本。
[root@localhost ~]# gem install redis-3.0.0.gem
Successfully installed redis-3.0.0
1 gem installed
Installing ri documentation for redis-3.0.0...
Installing RDoc documentation for redis-3.0.0...
(4)使用 ruby 脚本搭建集群。
进入redis源码目录中的src目录 执行下面的命令
./redis-trib.rb create --replicas 1 192.168.25.129:7001 192.168.25.129:7002 192.168.25.129:7003 192.168.25.129:7004 192.168.25.129:7005 192.168.25.129:7006
出现下列提示信息(期间会让你输入确认,输入的是 yes不是y哦!!!)
>>> Creating cluster
Connecting to node 192.168.25.140:7001: OK
Connecting to node 192.168.25.140:7002: OK
Connecting to node 192.168.25.140:7003: OK
Connecting to node 192.168.25.140:7004: OK
Connecting to node 192.168.25.140:7005: OK
Connecting to node 192.168.25.140:7006: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.25.140:7001
192.168.25.140:7002
192.168.25.140:7003
Adding replica 192.168.25.140:7004 to 192.168.25.140:7001
Adding replica 192.168.25.140:7005 to 192.168.25.140:7002
Adding replica 192.168.25.140:7006 to 192.168.25.140:7003
M: 1800237a743c2aa918ade045a28128448c6ce689 192.168.25.140:7001
slots:0-5460 (5461 slots) master
M: 7cb3f7d5c60bfbd3ab28800f8fd3bf6de005bf0d 192.168.25.140:7002
slots:5461-10922 (5462 slots) master
M: 436e88ec323a2f8bb08bf09f7df07cc7909fcf81 192.168.25.140:7003
slots:10923-16383 (5461 slots) master
S: c2a39a94b5f41532cd83bf6643e98fc277c2f441 192.168.25.140:7004
replicates 1800237a743c2aa918ade045a28128448c6ce689
S: b0e38d80273515c84b1a01820d8ecee04547d776 192.168.25.140:7005
replicates 7cb3f7d5c60bfbd3ab28800f8fd3bf6de005bf0d
S: 03bf6bd7e3e6eece5a02043224497c2c8e185132 192.168.25.140:7006
replicates 436e88ec323a2f8bb08bf09f7df07cc7909fcf81
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
>>> Performing Cluster Check (using node 192.168.25.140:7001)
M: 1800237a743c2aa918ade045a28128448c6ce689 192.168.25.140:7001
slots:0-5460 (5461 slots) master
M: 7cb3f7d5c60bfbd3ab28800f8fd3bf6de005bf0d 192.168.25.140:7002
slots:5461-10922 (5462 slots) master
M: 436e88ec323a2f8bb08bf09f7df07cc7909fcf81 192.168.25.140:7003
slots:10923-16383 (5461 slots) master
M: c2a39a94b5f41532cd83bf6643e98fc277c2f441 192.168.25.140:7004
slots: (0 slots) master
replicates 1800237a743c2aa918ade045a28128448c6ce689
M: b0e38d80273515c84b1a01820d8ecee04547d776 192.168.25.140:7005
slots: (0 slots) master
replicates 7cb3f7d5c60bfbd3ab28800f8fd3bf6de005bf0d
M: 03bf6bd7e3e6eece5a02043224497c2c8e185132 192.168.25.140:7006
slots: (0 slots) master
replicates 436e88ec323a2f8bb08bf09f7df07cc7909fcf81
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
Redis-cli 连接集群:
redis-cli -p 主机ip -p 端口(集群中任意端口) -c
-c:代表连接的是 redis 集群
测试值的存取:
(1)从本地连接到集群redis 使用7001端口 加 -c 参数
(2)存入name值为abc ,系统提示此值被存入到了7002端口所在的redis (槽是5798)
(3)提取name的值,可以提取。
(4)退出(quit)
(5)再次以7001端口进入 ,不带-c
(6)查询name值,无法获取,因为值在7002端口的redis上
(7)我们以7002端口进入,获取name值发现是可以获取的,而以其它端口进入均不能获取
修改品优购工程 在pinyougou-content-service工程添加spring 配置文件
spring-redis-cluster.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.data.redis.connection.RedisStandaloneConfiguration" id="standaloneConfiguration">
<property name="hostName" value="192.168.25.133">property>
<property name="port" value="6379">property>
bean>
<bean class="org.springframework.data.redis.connection.RedisClusterConfiguration" id="redisClusterConfiguration">
<constructor-arg name="clusterNodes">
<list>
<value>192.168.25.129:7001value>
<value>192.168.25.129:7002value>
<value>192.168.25.129:7003value>
<value>192.168.25.129:7004value>
<value>192.168.25.129:7005value>
<value>192.168.25.129:7006value>
list>
constructor-arg>
bean>
<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" id="connectionFactory">
<constructor-arg name="clusterConfig" ref="redisClusterConfiguration">constructor-arg>
bean>
<bean class="org.springframework.data.redis.core.RedisTemplate" id="redisTemplate">
<property name="connectionFactory" ref="connectionFactory">property>
bean>
beans>
这是一种风险比较大的集群方式,因为一旦Borker重启或宕机期间,将会导致这个服务不可用,因此是不建议线上环境去使用的。
一个集群全部都是Master,没有Slave,它的优点和缺点如下:
优点:配置简单,单个Master宕机或者是重启维护对应用没有什么影响的,在磁盘配置为RAID10时,即使机器宕机不可恢复的情况下,消息也不会丢失(异步刷盘丢失少量消息,同步刷盘则是一条都不会丢失),性能最高
缺点:当单个Broker宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息的实时性会受到影响。
每个Master配置一个Slave,有多对的Master-Slave,HA采用的是异步复制方式,主备有短暂的消息延迟,毫秒级别的(Master收到消息之后立刻向应用返回成功标识,同时向Slave写入消息)。优缺点如下:
优点:即使是磁盘损坏了,消息丢失的非常少,且消息实时性不会受到影响,因为Master宕机之后,消费者仍然可以从Slave消费,此过程对应用透明,不需要人工干预,性能同多个Master模式机会一样。
缺点:Master宕机,磁盘损坏的情况下,会丢失少量的消息。
每个Master配置一个Slave,有多对的Master-Slave,HA采用的是同步双写模式,主备都写成功,才会向应用返回成功。
优点:数据与服务都无单点,Master宕机的情况下,消息无延迟,服务可用性与数据可用性都非常高
缺点:性能比异步复制模式略低,大约低10%左右,发送单个Master的RT会略高,目前主机宕机后,Slave不能自动切换为主机,后续会支持自动切换功能。
这里搭建一个双主双从的集群,采用同步赋值异步刷盘方式进行集群,在工作中,我也推荐这么做,先把环境准备一下。
准备4台机器,如下:
IP | hostname | mastername |
---|---|---|
192.168.211.141 | rocketmq-nameserver1 | rocketmq-master1 |
192.168.211.142 | rocketmq-nameserver2 | rocketmq-master2 |
192.168.211.143 | rocketmq-nameserver3 | rocketmq-master1-slave |
192.168.211.144 | rocketmq-nameserver4 | rocketmq-master2-slave |
在每台机器上安装RocketMQ,安装过程和上面单节点RocketMQ安装流程基本类似。
修改每台机器的/etc/hosts文件,添加如下映射路径
192.168.211.141 rocketmq-nameserver1
192.168.211.142 rocketmq-nameserver2
192.168.211.143 rocketmq-nameserver3
192.168.211.144 rocketmq-nameserver4
192.168.211.141 rocketmq-master1
192.168.211.142 rocketmq-master2
192.168.211.143 rocketmq-master1-slave
192.168.211.144 rocketmq-master2-slave
4台机器一起解压rocketmq压缩文件,最后将解压文件存放在/usr/local/server/mq/rocketmq目录下。
分别在4台机器的rocketmq目录下执行如下操作
mkdir logs
mkdir store
cd store/
mkdir commitlog
mkdir consumequeue
mkdir index
进入141集群rocketmq/conf/2m-2s-sync目录下配置对应的配置文件,修改broker-a.properties配置文件,如下:
terName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-a
#0 表示Master, > 0 表示slave
brokerId=0
#nameServer 地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876;rocketmq-nameserver3:9876;rocketmq-nameserver4:9876
#在发送消息时,自动创建服务器不存在的Topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许Broker自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认是凌晨4点
deleteWhen=04
#文件保留时间,默认48小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/server/mq/rocketmq/store
#commitLog存储路径
storePathCommitLog=/usr/local/server/mq/rocketmq/store/commitlog
#消费队列存储路径
storePathConsumeQueue=/usr/local/server/mq/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/server/mq/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/server/mq/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/server/mq/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
# flushCommitLogLeastPages=4
# flushConsumeQueueLeastPages=2
# flushCommitLogThoroughInterval=10000
# flushConsumeQueueThoroughInterval=60000
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=YNC_MASTER
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageTreadPoolNums=128
#拉消息线程池数量
#pullMessageTreadPoolNums=128
修改broker-b.properties文件,如下:
terName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-b
#0 表示Master, > 0 表示slave
brokerId=0
#nameServer 地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876;rocketmq-nameserver3:9876;rocketmq-nameserver4:9876
#在发送消息时,自动创建服务器不存在的Topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许Broker自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认是凌晨4点
deleteWhen=04
#文件保留时间,默认48小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/server/mq/rocketmq/store
#commitLog存储路径
storePathCommitLog=/usr/local/server/mq/rocketmq/store/commitlog
#消费队列存储路径
storePathConsumeQueue=/usr/local/server/mq/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/server/mq/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/server/mq/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/server/mq/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
# flushCommitLogLeastPages=4
# flushConsumeQueueLeastPages=2
# flushCommitLogThoroughInterval=10000
# flushConsumeQueueThoroughInterval=60000
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=YNC_MASTER
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageTreadPoolNums=128
#拉消息线程池数量
#pullMessageTreadPoolNums=128
修改broker-a-s.properties文件,如下:
terName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-a
#0 表示Master, > 0 表示slave
brokerId=1
#nameServer 地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876;rocketmq-nameserver3:9876;rocketmq-nameserver4:9876
#在发送消息时,自动创建服务器不存在的Topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许Broker自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认是凌晨4点
deleteWhen=04
#文件保留时间,默认48小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/server/mq/rocketmq/store
#commitLog存储路径
storePathCommitLog=/usr/local/server/mq/rocketmq/store/commitlog
#消费队列存储路径
storePathConsumeQueue=/usr/local/server/mq/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/server/mq/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/server/mq/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/server/mq/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
# flushCommitLogLeastPages=4
# flushConsumeQueueLeastPages=2
# flushCommitLogThoroughInterval=10000
# flushConsumeQueueThoroughInterval=60000
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=SLAVE
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageTreadPoolNums=128
#拉消息线程池数量
#pullMessageTreadPoolNums=128
修改broker-b-s.properties文件,如下:
terName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-b
#0 表示Master, > 0 表示slave
brokerId=1
#nameServer 地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876;rocketmq-nameserver3:9876;rocketmq-nameserver4:9876
#在发送消息时,自动创建服务器不存在的Topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许Broker自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认是凌晨4点
deleteWhen=04
#文件保留时间,默认48小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/usr/local/server/mq/rocketmq/store
#commitLog存储路径
storePathCommitLog=/usr/local/server/mq/rocketmq/store/commitlog
#消费队列存储路径
storePathConsumeQueue=/usr/local/server/mq/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/usr/local/server/mq/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/usr/local/server/mq/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/usr/local/server/mq/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
# flushCommitLogLeastPages=4
# flushConsumeQueueLeastPages=2
# flushCommitLogThoroughInterval=10000
# flushConsumeQueueThoroughInterval=60000
# Broker 的角色
# - ASYNC_MASTER 异步复制Master
# - SYNC_MASTER 同步双写Master
# - SLAVE
brokerRole=SLAVE
# 刷盘方式
# - ASYNC_FLUSH 异步刷盘
# - SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageTreadPoolNums=128
#拉消息线程池数量
#pullMessageTreadPoolNums=128
将节点信息拷贝到每台机器,在141机器执行如下命令
scp broker-*.properties 192.168.211.142:/usr/local/server/mq/rocketmq/conf/2m-2s-sync
scp broker-*.properties 192.168.211.143:/usr/local/server/mq/rocketmq/conf/2m-2s-sync
scp broker-*.properties 192.168.211.144:/usr/local/server/mq/rocketmq/conf/2m-2s-sync
效果如下图:
进入到每台机器的conf目录,替换日志文件路径,执行如下命令
sed -i 's#${user.home}#/usr/local/server/mq/rocketmq#g' *.xml
进入每台机器的bin目录下,需改runbroker.sh和runserver.sh文件
runbroker.sh
改前:
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
改后:
JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn1g"
runserver.sh
改前:
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
改后:
JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
先在每台服务器启动namesrv
nohup sh mqnamesrv &
再启动broker
141服务器执行如下启动命令:
nohup sh mqbroker -c /usr/local/server/mq/rocketmq/conf/2m-2s-sync/broker-a.properties > /dev/null 2>&1 &
142服务器执行如下启动命令:
nohup sh mqbroker -c /usr/local/server/mq/rocketmq/conf/2m-2s-sync/broker-b.properties > /dev/null 2>&1 &
143服务器执行如下启动命令:
nohup sh mqbroker -c /usr/local/server/mq/rocketmq/conf/2m-2s-sync/broker-a-s.properties > /dev/null 2>&1 &
144服务器执行如下启动命令:
nohup sh mqbroker -c /usr/local/server/mq/rocketmq/conf/2m-2s-sync/broker-b-s.properties > /dev/null 2>&1 &
输入jps查看进程
[root@localhost bin]# jps
43761 NamesrvStartup
43803 BrokerStartup
44093 Jps
[root@localhost bin]#
启动后,修改控制台的namesrv地址,如下修改:
rocketmq.config.namesrvAddr=192.168.211.141:9876;192.168.211.142:9876;192.168.211.143:9876;192.168.211.144:9876
启动控制台服务,并访问控制台,如下:
这里如果想停掉服务,可以先停掉broker
sh mqshutdown broker
再关闭namesrv
sh mqshutdown namesrv