注:附件在最下面
SolrCloud
认识系统架构
集群概述
为什么要使用服务器集群
此前我们在进行项目的开发时,使用的标准的Javaweb的工程开发模式,这种方式使用一个服务器部署和发布服务器程序,又称为单点服务器,在这种状况下,如果单点服务器出现故障,将直接影响系统的使用。而停止服务可能会带来非常严重的问题,造成重大损失,所以这种项目架构的方式显然存在较大的风险。
在此基础上出现了,服务器的集群架构模式,这里我们可以总结一下,传统的单点服务器上存在的问题:
- 单服务器的处理能力有限,尤其在高并发环境下,单服务器的并发处理能力的瓶颈很难突破,每台服务器都存在有限的最大连接数。
- 单服务器的容错率低,如果服务器发生故障,那么整个服务将无法访问
- 单服务器运算能力有限,逐渐无法满足高性能服务器的需求。
以上就是我们在进行项目架构时需要考虑的三高:高并发,高可用和高性能,而这也是我们在实际项目中使用分布式集群的主要原因。
什么是集群
集群就是将多个系统连接到一起,使多台服务器能够像一台机器那样工作或者看起来好像一台机器的一种技术。集群的主要任务是为了提高系统的稳定性和网络中心的数据处理能力及服务能力。
从以上集群的主要看出,集群可以协调和统筹多台服务器的处理,提供高效稳定的服务。那么这是怎么来实现的呢?在集群中实现高并发和可扩展的方案是采用负载均衡技术,而为了提供高可用的服务则采用数据冗余技术。
负载均衡就是通过集群架构多台服务器,通过技术实现对用户并发请求进行均衡操作,以分担单个服务器的压力,常见的负载均衡的实现方式事通过反向代理,有反向代理服务器对用户的请求进行处理,分发给被代理的哥哥服务器进行处理。
数据冗余技术主要指对可能出现单点故障的服务器进行冗余处理,提供多台服务器,按照特定的机制进行相互的同步以保持数据的一致性,当一台服务器出现故障之后,可以实现自动的快速切换,提供高可用的服务器支持。
分布式架构
1.2.1、为什么使用分布式
传统的web架构采用单个工程进行处理,系统功能比较繁杂,业务之间的耦合性高,不理单个模块的开发和维护,也不利于功能的水平扩展。在集群部署中,也不理于集群的管理。
分布式架构
分布式是指将多台服务器集中在一起,每台服务器都实现总体中的不同业务,做不同的事情。并且每台服务器都缺一不可,如果某台服务器故障,则网站部分功能缺失,或导致整体无法运行。存在的主要作用是大幅度的提高效率,缓解服务器的访问和存储压力。
1.3、分布式集群综合架构
一般分布式中的每一个节点,都可以做集群。这样的系统架构,我们通常称为分布式集群架构。
代理技术
1.4.1、正向代理(Forward Proxy)
一般情况下,如果没有特别说明,代理技术默认说的是正向代理技术。关于正向代理的概念如下: 正向代理(forward)是一个位于客户端【用户A】和原始服务器(origin server)【服务器B】之间的服务器【代理服务器Z】,为了从原始服务器取得内容,用户A向代理服务器Z发送一个请求并指定目标(服务器B),然后代理服务器Z向服务器B转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
1.4.2、反向代理(reverse proxy)
反向代理正好与正向代理相反,对于客户端而言代理服务器就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端。 使用反向代理服务器的作用如下:
用户A始终认为它访问的是原始服务器B而不是代理服务器Z,但实用际上反向代理服务器接受用户A的应答,从原始资源服务器B中取得用户A的需求资源,然后发送给用户A。由于防火墙的作用,只允许代理服务器Z访问原始资源服务器B。在这个虚拟的环境下,防火墙和反向代理的共同作用保护了原始资源服务器B,但用户A并不知情。
当反向代理服务器不止一个的时候,我们甚至可以把它们做成集群,当更多的用户访问资源服务器B的时候,让不同的代理服务器Z(x)去应答不同的用户,然后发送不同用户需要的资源。而且反向代理服务器像正向代理服务器一样拥有CACHE的作用,它可以缓存原始资源服务器B的资源,而不是每次都要向原始资源服务器B请求数据,特别是一些静态的数据,比如图片和文件。
Zookeeper分布式协调服务
什么是Zookeeper
Zookeeper是集群分布式中大管家,分布式集群系统比较复杂,子模块很多,但是子模块往往不是孤立存在的,它们彼此之间需要协作和交互,各个子系统就好比动物园里的动物,为了使各个子系统能正常为用户提供统一的服务,必须需要一种机制来进行协调——这就是ZooKeeper。Zookeeper 是为分布式应用程序提供高性能协调服务的工具集合,也是Google的Chubby一个开源的实现,是Hadoop 的分布式协调服务。
Zookeeper的集群结构
在ZooKeeper集群当中,集群中的服务器角色有两种:1个Leader和多个Follower,具体功能如下:
1)领导者(leader),负责进行投票的发起和决议,监控集群中的节点是否存活(心跳机制),进行分配资源
2)follower用于接受客户端请求并向客户端返回结果,在选主过程中参与投票
Zookeeper集群的特点:
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可用,整个系统保持可用
2.3、Zookeeper的作用
Zookeeper包含一个简单的原语集,分布式应用程序可以基于它实现命名服务、配置维护、集群选主等:
命名服务:注册节点信息,形成有层次的目录结构(类似Java的包名)。
配置维护:配置信息的统一管理和动态切换
集群选主:确保整个集群中只有一个主,其它为从。并且当主挂了后,可以自动选主
SolrCloud概述
什么是SolrCloud
单点的Solr服务的问题:
A:能存储的数据量有限,如果是海量数据,无法存储
B:容易出现单点故障
C:对高并发的处理能力差
如果我们的需要处理海量数据、应对高并发请求,并且让我们的服务实现高可用。那么就必须要搭建SolrCloud了。反之,如果数据量很少,请求并发低的情况下,是不需要SolrCloud的,单点Solr就够了。
SolrCloud(solr 云)是Solr提供的分布式搜索方案,可以解决海量数据的 分布式全文检索,因为搭建了集群,因此具备高可用的特性,同时对数据进行主从备份,避免了单点故障问题。可以做到数据的快速恢复。并且可以动态的添加新的节点,再对数据进行平衡。
SolrCloud结构简介
为了实现海量数据的存储,我们会把索引进行分片(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。
SolrCloud的搭建
基本环境
我们需要三台服务器,也就是三台虚拟机。分别是:
192.168.57.101
192.168.57.102
192.168.57.103
每台及其上都需要部署以下环境:
JDK:基本Java运行环境
Tomcat:装载Solr服务
Solr-4.10.2:Solr服务
Zookeeper:对Solr云进行管理
单机部署
4.2.1、Solr安装
上传依赖包到solr/WEB-INF/下
修改tomcat的bin目录下的catalina.sh文件,添加启动的参数,指向solr的索引文件夹。
启动tomcat,访问:http://192.168.8.10:8080/solr 查看单点Solr部署情况。
4.2.2、zookeeper安装
上传zookeeper的安装包
解压缩安装包
修改配置文件
A:进入zookeeper/conf目录
B:复制模板文件
cp zoo_sample.cfg zoo.cfg |
C:修改配置文件信息vi zoo.cfg,添加以下内容
要添加的内容:
dataDir=/usr/local/ zookeeper-3.4.5/data dataLogDir=/usr/local/ zookeeper-3.4.5/log server.1=192.168.8.10:2888:3888 server.2=192.168.8.11:2888:3888 server.3=192.168.8.12:2888:3888 |
模板文件中已经有一个dataDir参数,我们一定要把这个删除,或者在这个基础上修改
dataDir:数据目录 dataLogDir:日志目录 server.1=x.x.x.x:port1:port2 指定所有zookeeper的节点信息 server后的数字是节点ID,port1是心跳端口,port2是数据端口 |
在zookeeper中创建数据目录和日志目录
A:先进入zookeeper目录
B:创建目录
mkdir -m 755 data mkdir -m 755 log |
添加节点ID信息,进入data目录,创建文件myid,并且写上ID信息:1,注意,其它节点的ID必须与配置文件中的ID一直,分别是2和3。
配置zookeeper的环境变量,可以在任何位置使用zookeeper命令
A:vi /etc/profile(修改文件)
B:添加内容:
export ZOOKEEPER_HOME=/usr/local/zookeeper-3.4.5 export PATH=$PATH:$ZOOKEEPER_HOME/bin |
C:重新编译文件:source /etc/profile
zookeeper命令:
启动zookeeper: zkServer.sh start 停止zookeeper: zkServer.sh stop 查看状态: zkServer.sh status zkServer.sh start-foreground |
集群部署
4.3.1、修改tomcat启动文件,添加zookeeper的地址信息
修改:tomcat文件夹下的bin目录中的catalina.sh文件,添加以下信息:
export JAVA_OPTS="-Dsolr.solr.home=/usr/local/solr-4.10.2/example/solr -DzkHost=192.168.8.10:2181,192.168.8.11:2181,192.168.8.12:2181" |
这样tomcat启动后,solr服务就可以到zookeeper中注册自己的信息,或者获取其它节点信息。
4.3.2、启动zookeeper集群
修改102和103机器中的zookeeper的节点ID,修改zookeeper目录中 data/myid的内容,分别为2和3。
分别启动三台虚拟机中的zookeeper,使用zookeeper的客户端控制台,查看zookeeper信息。Zookeeper提供了自己的客户端命令行工具,与Linux的命令非常相似。
A:启动客户端工具:zkCli.sh –server ip:port 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 |
4.3.3、修改Solr配置文件,配置集群的中每台Solr服务的IP和端口
进入/usr/local/myapp/solr-4.10.2/example/solr目录,修改solr.xml文件
<solrcloud> <str name="host">192.168.8.10</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> |
4.3.4、将Solr配置文件上传到Zookeeper中统一管理
由于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/solr-4.10.2/example/scripts/cloud-scripts/zkcli.sh -zkhost 192.168.8.10:2181,192.168.8.11:2181,192.168.8.12:2181 -cmd upconfig -confdir /usr/local/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.8.10:2181,192.168.8.11:2181,192.168.8.12:2181: 指定Zookeeper的地址信息
-cmd upconfig: 指定操作的命令。这里是上传配置
-confdir /usr/local/myapp/solr-4.10.2/example/solr/collection1/conf/ :指定要上传的配置文件目录,我们上传Solr的样例中的配置
-confname solrconf :指定注册到Zookeeper中后配置文件目录名称
4.3.5、启动SolrCloud
启动每一台服务器中的Solr服务,访问SolrCloud,查看云的状态。
通过管理界面查看和操作SolrCloud
4.4.1、SolrCloud的操作命令:
Solr采用的是类似WebService的API接口,采用Http方式进行访问,因此,其操作命令都是一些URL联接及对应参数
- 创建core命令
参数说明:
name:指明collection名称
numShards:指明分片数
replicationFactor:指明副本数
maxShardsPerNode: 每个节点最大分片数(默认为1)
property.schema:指定使用的schema.xml,这个文件必须在zookeeper上。
property.config:指定使用的solrconfig.xml,这个文件必须在zookeeper上。
- 删除Collection命令
http://192.168.8.10:8080/solr/admin/collections?action=DELETE&name=collection1
- 查询所有的Collection
http://192.168.8.10:8080/solr/admin/collections?action=LIST
- 显示集群的状态
http://192.168.8.10:8080/solr/admin/collections?action=CLUSTERSTATUS
- 分裂shard
- 删除shard
4.4.2、SolrCloud测试
创建索引:在一台Solr上创建的索引,从其它solr服务上可以查询到
查询索引:从任意一台Solr上查询索引,选择任意的一个分片,都会返回一个完整的结果
使用SolrJ访问SolrCloud
与单机Solr相比,API仅仅是在创建SolrServer时发生了改变,其它没有变化。单机采用的是:HttpSolrServer,SolrCloud采用的是:CloudSolrServer。
添加或修改数据
@Test public void testWrite() throws Exception{ // 创建SolrServer CloudSolrServer server = new CloudSolrServer("192.168.8.10:2181,192.168.8.11:2181,192.168.8.12:2181"); // 指定要访问的Collection名称 server.setDefaultCollection("collection1"); // 创建Document对象 SolrInputDocument document = new SolrInputDocument(); // 添加字段 document.addField("id", "1"); document.addField("title", "solrcloud写入的数据"); // 添加Document到Server server.add(document); // 提交 server.commit(); } |
5.2、删除数据
@Test public void testDelete()throws Exception{ // 创建SolrServer CloudSolrServer server = new CloudSolrServer("192.168.8.10:2181,192.168.8.11:2181,192.168.8.12:2181"); // 指定要访问的Collection名称 server.setDefaultCollection("collection1"); // 根据ID删除 server.deleteById("1"); // 提交 server.commit(); } |
5.3、查询数据
@Test public void testSearch() throws Exception { // 创建SolrServer CloudSolrServer server = new CloudSolrServer("192.168.8.10:2181,192.168.8.11:2181,192.168.8.12:2181"); // 指定要访问的Collection名称 server.setDefaultCollection("collection1"); // 查找数据 QueryResponse response = server.query(new SolrQuery("title:solrcloud")); // 以document形式解析数据 SolrDocumentList documentList = response.getResults(); // 遍历 for (SolrDocument solrDocument : documentList) { System.out.println(solrDocument.getFieldValue("id")); System.out.println(solrDocument.getFieldValue("title")); } } |