咱们之因此要学习集群,是由于单点服务器,存在一系列的问题。node
咱们之前学习的JavaEE项目,都是部署在一台Tomcat上,全部的请求,都由这一台服务器处理,存在很大风险:apache
A:并发处理能力有限。由于单服务器的性能有限制。因此单台Tomcat的最大链接数有限制,编程
B:容错率低,一旦服务器故障,整个服务就没法访问了。缓存
eBay于 1999年6月停机22小时的事故,中断了约230万的拍卖,使eBay的股票降低了9.2个百分点。tomcat
C:单台服务器计算能力低,没法完成复杂的海量数据计算。服务器
提升CPU主频和总线带宽是最初提供计算机性能的主要手段。可是这一手段对系统性能的提供是有限的。接着人们经过增长CPU个数和内存容量来提升性能,因而出现了向量机,对称多处理机(SMP)等。可是当CPU的个数超过某一阈值,这些多处理机系统的可扩展性就变的极差。主要瓶颈在于CPU访问内存的带宽并不能随着CPU个数的增长而有效增加。与SMP相反,集群系统的性能随着CPU个数的增长几乎是线性变化的网络
集群是是指将多台服务器集中在一块儿,每台服务器都实现相同的业务,作相同的事情。可是每台服务器并非缺一不可,存在的做用主要是缓解并发压力和单点故障转移问题。能够利用一些廉价的符合工业标准的硬件构造高性能的系统。实现:高扩展、高性能、低成本、高可用!架构
注意:该图中最大的特色就是,每一个Tomcat都完成相同的业务,可是分担着不一样用户的访问,它们并非缺一不可,若是一个Tomcat出现故障,网站依旧能够运行。并发
伸缩性(Scalability)app
在一些大的系统中,预测最终用户的数量和行为是很是困难的,伸缩性是指系统适应不断增加的用户数的能力。提升这种并发会话能力的一种最直观的方式就增长资源(CPU,内存,硬盘等),集群是解决这个问题的另外一种方式,它容许一组服务器组在一块儿,像单个服务器同样分担处理一个繁重的任务,咱们只须要将新的服务器加入集群中便可,对于客户来看,服务不管从连续性仍是性能上都几乎没有变化,好像系统在不知不觉中完成了升级
高可用性(High availability)
单一服务器的解决方案并非一个健壮方式,由于容易出现单点失效。像银行、帐单处理这样一些关键的应用程序是不能容忍哪怕是几分钟的死机。它们须要这样一些服务在任什么时候间均可以访问并在可预期的合理的时间周期内有响应。高可用性集群的出现是为了使集群的总体服务尽量可用,以便考虑计算硬件和软件的易错性。若是高可用性集群中的主节点发生了故障,那么这段时间内将由次节点代替它。次节点一般是主节点的镜像,因此当它代替主节点时,它能够彻底接管其身份,而且所以使系统环境对于用户是一致的。
负载均衡(Load balancing)
负载均衡集群为企业需求提供了更实用的系统。如名称所暗示的,该系统使负载能够在计算机集群中尽量平均地分摊处理。该负载多是须要均衡的应用程序处理负载或网络流量负载。这样的系统很是适合于运行同一组应用程序的大量用户。每一个节点均可以处理一部分负载,而且能够在节点之间动态分配负载,以实现平衡。
高性能 (High Performance )
一般,第一种涉及为集群开发并行编程应用程序,以解决复杂的科学问题。这是并行计算的基础,尽管它不使用专门的并行超级计算机,这种超级计算机内部由十至上万个独立处理器组成。但它却使用商业系统,如经过高速链接来连接的一组单处理器或双处理器 PC,而且在公共消息传递层上进行通讯以运行并行应用程序。所以,您会经常据说又有一种便宜的 Linux 超级计算机问世了。但它实际是一个计算机集群,其处理能力与真的超级计算机相等
A:系统过于庞大,开发维护困难
B:功能间耦合度过高
C:没法针对单个模块进行优化
D:没法进行水平扩展
分布式是指将多台服务器集中在一块儿,每台服务器都实现整体中的不一样业务,作不一样的事情。而且每台服务器都缺一不可,若是某台服务器故障,则网站部分功能缺失,或致使总体没法运行。存在的主要做用是大幅度的提升效率,缓解服务器的访问和存储压力。
注意:该图中最大特色是:每一个Web服务器(Tomcat)程序都负责一个网站中不一样的功能,缺一不可。若是某台服务器故障,则对应的网站功能缺失,也能够致使其依赖功能甚至所有功能都不可以使用。
所以,分布式系统须要运行在集群服务器中,甚至分布式系统的每一个不一样子任务均可以部署集群
通常分布式中的每个节点,均可以作集群。这样的系统架构,咱们一般称为分布式集群架构。
通常状况下,若是没有特别说明,代理技术默认说的是正向代理技术。关于正向代理的概念以下: 正向代理(forward)是一个位于客户端【用户A】和原始服务器(origin server)【服务器B】之间的服务器【代理服务器Z】,为了从原始服务器取得内容,用户A向代理服务器Z发送一个请求并指定目标(服务器B),而后代理服务器Z向服务器B转交请求并将得到的内容返回给客户端。客户端必需要进行一些特别的设置才能使用正向代理。
简单来讲,正向代理就是代理服务器替代访问方【用户A】去访问目标服务器【服务器B】
为何须要使用正向代理?
great firewall
被服务器屏蔽(wow)
若是在用户A访问服务器B某数据J以前,已经有人经过代理服务器Z访问过服务器B上得数据J,那么代理服务器Z会把数据J保存一段时间,若是有人正好取该数据J,那么代理服务器Z再也不访问服务器B,而把缓存的数据J直接发给用户A。
服务器B并不知道访问本身的实际是用户A,由于代理服务器Z代替用户A去直接与服务器B进行交互。若是代理服务器Z被用户A彻底控制(或不彻底控制),会惯以“肉鸡”术语称呼。
总结一下:正向代理是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),而后代理向原始服务器转交请求并将得到的内容返回给客户端。客户端必须设置正向代理服务器,固然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。
反向代理正好与正向代理相反,对于客户端而言代理服务器就像是原始服务器,而且客户端不须要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将得到的内容返回给客户端。 使用反向代理服务器的做用以下:
用户A始终认为它访问的是原始服务器B而不是代理服务器Z,但实用际上反向代理服务器接受用户A的应答,从原始资源服务器B中取得用户A的需求资源,而后发送给用户A。因为防火墙的做用,只容许代理服务器Z访问原始资源服务器B。在这个虚拟的环境下,防火墙和反向代理的共同做用保护了原始资源服务器B,但用户A并不知情。
当反向代理服务器不止一个的时候,咱们甚至能够把它们作成集群,当更多的用户访问资源服务器B的时候,让不一样的代理服务器Z(x)去应答不一样的用户,而后发送不一样用户须要的资源。
并且反向代理服务器像正向代理服务器同样拥有CACHE的做用,它能够缓存原始资源服务器B的资源,而不是每次都要向原始资源服务器B请求数据,特别是一些静态的数据,好比图片和文件。
简单来讲,反向代理就是反向代理服务器替代原始服务器【服务器B】让【用户A】去访问
Zookeeper是集群分布式中大管家
分布式集群系统比较复杂,子模块不少,可是子模块每每不是孤立存在的,它们彼此之间须要协做和交互,各个子系统就比如动物园里的动物,为了使各个子系统能正常为用户提供统一的服务,必须须要一种机制来进行协调——这就是ZooKeeper
Zookeeper 是为分布式应用程序提供高性能协调服务的工具集合,也是Google的Chubby一个开源的实现,是Hadoop 的分布式协调服务。
在ZooKeeper集群当中,集群中的服务器角色有两种:1个Leader和多个Follower,具体功能以下:
1)领导者(leader),负责进行投票的发起和决议,监控集群中的(follower)是否存活(心跳机制),进行分配资源
2)follower用于接受客户端请求并向客户端返回结果,在选主过程当中参与投票
特色:
A:Zookeeper:一个leader,多个follower组成的集群
B:全局数据一致:每一个server保存一份相同的数据副本,client不管链接到哪一个server,数据都是一致的
C:数据更新原子性,一次数据更新要么成功,要么失败
D:实时性,在必定时间范围内,client能读到最新数据
E:半数机制:整个集群中只要有一半以上存活,就能够提供服务。所以一般Zookeeper由2n+1台servers组成,每一个server都知道彼此的存在。每一个server都维护的内存状态镜像以及持久化存储的事务日志和快照。为了保证Leader选举能过获得多数的支持,因此ZooKeeper集群的数量通常为奇数。对于2n+1台server,只要有n+1台(大多数)server可用,整个系统保持可用
以一个简单的例子来讲明整个选举的过程.
假设有五台服务器组成的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运行了一段时间以后,有机器down掉,从新选举时,选举过程就相对复杂了。
须要加入数据id、leader id和逻辑时钟。
数据id:数据新的id就大,数据每次更新都会更新id。
Leader id:就是咱们配置的myid中的值,每一个机器一个。
逻辑时钟:这个值从0开始递增,每次选举对应一个值,也就是说: 若是在同一次选举中,那么这个值应该是一致的 ; 逻辑时钟值越大,说明这一次选举leader的进程最新.
选举的标准就变成:
一、逻辑时钟小的选举结果被忽略,从新投票
二、统一逻辑时钟后,数据id大的胜出
三、数据id相同的状况下,leader id大的胜出
根据这个规则选出leader。
Zookeeper包含一个简单的原语集,分布式应用程序能够基于它实现命名服务、配置维护、集群选主等:
命名服务:注册节点信息,造成有层次的目录结构(相似Java的包名)。
配置维护:配置信息的统一管理和动态切换
集群选主:确保整个集群中只有一个主,其它为从。而且当主挂了后,能够重新选主
单点的Solr服务的问题:
A:能存储的数据量有限,若是是海量数据,没法存储
B:容易出现单点故障
C:对高并发的处理能力差
若是咱们的须要处理海量数据、应对高并发请求,而且让咱们的服务实现高可用。那么就必需要搭建SolrCloud了。反之,若是数据量不多,请求并发低的状况下,是不须要SolrCloud的,单点Solr就够了
SolrCloud(solr 云)是Solr提供的分布式搜索方案,能够解决海量数据的 分布式全文检索,由于搭建了集群,所以具有高可用的特性,同时对数据进行主从备份,避免了单点故障问题。能够作到数据的快速恢复。而且能够动态的添加新的节点,再对数据进行平衡
为了实现海量数据的存储,咱们会把索引进行分片(Shard),把分片后的数据存储到不一样Solr节点。
为了保证节点数据的高可用,避免单点故障,咱们又会对每个Shard进行复制,产生不少副本(Replicas),每个副本对于一个Solr节点中的一个core
用户访问的时候,能够访问任何一个会被自动分配到任何一个可用副本进行查询,这样就实现了负载均衡。
逻辑结构:
Collection:在SolrCloud集群中逻辑意义上的完整的索引。通常会包含多个Shard(分片),若是大于1个分片,那么就是分布式存储。
Shard: Collection的逻辑分片。每一个Shard被化成一个或者多个replicas(副本),经过选举肯定哪一个是Leader(主),其它为从
Replica: Shard的一个副本,存储在Solr集群的某一台机器中(就是一个节点),对应这台Solr的一个Core。
Leader: 赢得选举的Shard replicas。每一个Shard有多个Replicas,这几个Replicas须要选举来肯定一个Leader。选举能够发生在任什么时候间,可是一般他们仅在某个Solr实例发生故障时才会触发。当索引documents时,SolrCloud会传递它们到此Shard对应的leader,leader再分发它们到所有Shard的replicas
分片数量越多,每一片的数据就越少,每个副本的数据就越少。可是通常不要多于机器数量
分片数量越少,每一片的数据就越多,每个副本的数据就越多。
副本数量越少,总数据量越少, 这样能够减小每一台机器上的数据量,会下降高可用性,提升数据存储上限。
副本数量越多,总数据量越多,会增长每一台机器上的数据量,可是会提升整个集群的高可用性。
咱们须要三台服务器,也就是三台虚拟机。分别是:
192.168.56.101
192.168.56.102
192.168.56.103
每台及其上都须要部署如下环境:
JDK:基本Java运行环境
Tomcat:装载Solr服务
Solr-4.10.2:Solr服务
Zookeeper:对Solr云进行管理
理论上应该给每台机器分别安装,可是咱们是虚拟机,咱们能够先安装一台,而后把虚拟机进行复制!
tar -zxvf zookeeper-3.4.5.tar.gz
某些机器没法识别标点,所以咱们能够把目录的名称作修改:
mv zookeeper-3.4.5 zookeeper
A:进入zookeeper/conf目录
B:复制模板文件
cp zoo_sample.cfg zoo.cfg
C:修改配置文件信息,添加如下内容
vi zoo.cfg
要添加的内容:
dataDir=/usr/local/myapp/zookeeper/data dataLogDir=/usr/local/myapp/zookeeper/log server.1=192.168.56.101:2888:3888 server.2=192.168.56.102:2888:3888 server.3=192.168.56.103:2888:3888
注意:模板文件中已经有一个dataDir参数,咱们必定要把这个删除,或者在这个基础上修改
dataDir:数据目录
dataLogDir:日志目录
server.1=x.x.x.x:port1:port2 指定全部zookeeper的节点信息
server后的数字是节点ID,port1是心跳端口,port2是数据端口
咱们在配置文件里指定了数据和日志目录。因此咱们须要建立这些目录
A:先进入zookeeper目录
B:建立目录
mkdir –m 755 data
mkdir –m 755 log
这样两个命令能够在建立目录的同时指定文件夹的权限
进入data目录,建立文件myid,而且写上ID信息:1
vi myid
插入id:1
注意,其它节点的ID必须与配置文件中的ID一致,分别是2和3
A:vi /etc/profile(修改文件)
B:添加内容:
export ZOOKEEPER_HOME=/usr/local/myapp/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
C:从新编译文件:
source /etc/profile
启动zookeeper:
zkServer.sh start
中止zookeeper:
zkServer.sh stop
查看状态:
zkServer.sh status
先stop 掉原zk
zkServer.sh stop
而后以./zkServer.sh start-foreground方式启动,会看到启动日志
zkServer.sh start-foreground
修改:tomcat文件夹下的bin目录中的catalina.sh文件,添加如下信息:
export JAVA_OPTS="-Dsolr.solr.home=/usr/local/myapp/solr-4.10.2/example/solr -DzkHost=192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"
-Dsolr.solr.solr.home指定的是Solr索引库位置
-DzkHost指定的是三个zookeeper的ip和客户端端口信息
这样tomcat启动后,solr服务就能够到zookeeper中注册本身的信息,或者获取其它节点信息。
分别为192.168.56.102和192.168.56.103
修改zookeeper目录中 data/myid的内容,分别为2和3
zkServer.sh start
查看状态:
zkServer.sh status
中止:
zkServer.sh stop
Zookeeper提供了本身的客户端命令行工具,与Linux的命令很是类似。
A:启动客户端工具:
zkCli.sh –server ip:port
这里的参数能够省略,若是省略,默认访问的是本机的zookeeper节点即:localhost:2181
B:显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
C:显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
D:建立文件,并设置初始内容: create /zk "test" 建立一个新的 znode节点“ zk ”以及与它关联的字符串
E:获取文件内容: get /zk 确认 znode 是否包含咱们所建立的字符串
F:修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置
G:删除文件: delete /zk 将刚才建立的 znode 删除
H:退出客户端: quit
I:帮助命令: help
<solrcloud> <str name="host">192.168.56.101</str> <int name="hostPort">8080</int> <str name="hostContext">${hostContext:solr}</str> <int name="zkClientTimeout">${zkClientTimeout:30000}</int> <bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool> </solrcloud>
咱们访问一台Solr服务的地址,通常是这样的:http://192.168.56.101:8080/solr
而在这里的几个参数,分别对应这个地址的一些信息:
host:就是Solr服务的IP地址,每台机器配置为本身的IP
hostPort:就是监听端口,咱们是Tomcat服务,所以是8080
hostContext:就是访问的路径,这里缺省值是solr,咱们不用改
因为zookeeper统一管理solr的配置文件(主要是schema.xml、solrconfig.xml), solrCloud各各节点使用zookeeper管理的配置文件。之后不管建立任何的core,本地的配置文件都没用了,使用的都是zookeeper的配置文件
执行下边的命令将/usr/local/myapp/solr-4.10.2/example/solr/collection1/conf/下的配置文件上传到zookeeper:
sh /usr/local/myapp/solr-4.10.2/example/scripts/cloud-scripts/zkcli.sh -zkhost 192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181 -cmd upconfig -confdir /usr/local/myapp/solr-4.10.2/example/solr/collection1/conf/ -confname solrconf
解释:
/usr/local/myapp/solr-4.10.2/example/scripts/cloud-scripts/zkcli.sh : Solr提供的访问Zookeeper的脚本文件 -zkhost 192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181 : 指定Zookeeper的地址信息 -cmd upconfig : 指定操做的命令。这里是上传配置 -confdir /usr/local/myapp/solr-4.10.2/example/solr/collection1/conf/ : 指定要上传的配置文件目录,咱们上传Solr的样例中的配置 -confname solrconf : 指定注册到Zookeeper中后配置文件目录名称
Solr采用的是相似WebService的API接口,采用Http方式进行访问,所以,其操做命令都是一些URL联接及对应参数
http://192.168.56.101:8080/solr/admin/collections?action=CREATE&name=myCollection1&numShards=3&replicationFactor=2&maxShardsPerNode=8&property.schema=schema.xml&property.config=solrconfig.xml
参数说明:
name :指明collection名称
numShards :指明分片数
replicationFactor :指明副本数
maxShardsPerNode : 每一个节点最大分片数(默认为1)
property.schema :指定使用的schema.xml,这个文件必须在zookeeper上。
property.config :指定使用的solrconfig.xml,这个文件必须在zookeeper上。
http://192.168.56.101:8080/solr/admin/collections?action=DELETE&name=collection1
http://192.168.56.101:8080/solr/admin/collections?action=LIST
http://192.168.56.101:8080/solr/admin/collections?action=CLUSTERSTATUS
http://192.168.56.101:8080/solr/admin/collections?action=SPLITSHARD&collection=myCollection2&shard=shard2
http://192.168.56.101:8080/solr/admin/collections?action=DELETESHARD&collection=myCollection2&shard=shard1
更多的命令请参数官方文档:
apache-solr-ref-guide-4.10.pdf
注意:
启动solrCloud须要先启动solrCloud依赖的全部zookeeper服务器,再启动每台solr服务器。
若是服务器跟服务器之间没法通信,查看每台服务器的/etc/hosts 里面是否配置了其余服务器的IP地址和hostname
测试:在一台Solr上建立的索引,从其它solr服务上能够查询到
从任意一台Solr上查询索引,选择任意的一个分片,都会返回一个完整的结果
三台服务器,任意挂掉一台,依然不会影响使用,事实上,只要剩余的机器上,有完整的shard分片信息,都不影响使用。无论剩余几台服务器
当一个节点挂掉时,若是有索引的更新,那么这个节点启动后,会自动同步新的数据
若是咱们启动新的Solr服务,那么这个服务也能够融入集群中。
与单机Solr相比,API仅仅是在建立SolrServer时发生了改变,其它没有变化。
单机采用的是:HttpSolrServer
SolrCloud采用的是:CloudSolrServer
@Test public void testWrite() throws Exception{ // 建立SolrServer CloudSolrServer server = new CloudSolrServer("192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"); // 指定要访问的Collection名称 server.setDefaultCollection("collection1"); // 建立Document对象 SolrInputDocument document = new SolrInputDocument(); // 添加字段 document.addField("id", "20"); document.addField("title", "duang手机,自带特效的手机,值得拥有"); // 添加Document到Server server.add(document); // 提交 server.commit(); }
@Test public void testDelete() throws Exception{ // 建立SolrServer CloudSolrServer server = new CloudSolrServer("192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"); // 指定要访问的Collection名称 server.setDefaultCollection("collection1"); // 根据ID删除 server.deleteById("20"); // 提交 server.commit(); }
@Test public void testSearch() throws Exception { // 建立SolrServer CloudSolrServer server = new CloudSolrServer("192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"); // 指定要访问的Collection名称 server.setDefaultCollection("collection1"); // 查找数据 QueryResponse response = server.query(new SolrQuery("title:手机")); // 以document形式解析数据 SolrDocumentList documentList = response.getResults(); // 遍历 for (SolrDocument solrDocument : documentList) { System.out.println(solrDocument.getFieldValue("id")); System.out.println(solrDocument.getFieldValue("title")); } }