SolrCloud原理

SolrCloud 是基于 Solr 和 Zookeeper 的分布式搜索方案,是正在开发中的 Solr4.0 的核心组件之一,它的主要思想是使用 Zookeeper 作为集群的配置信息中心。

它有几个特色功能:①集中式的配置信息 ②自动容错 ③近实时搜索 ④查询时自动负载均衡。

solr-main

下面看看 wiki 的文档:

1、SolrCloud
SolrCloud 是指 Solr 中一套新的潜在的分发能力。这种能力能够通过参数让你建立起一个高可用、
容错的 Solr 服务集群。当你需要大规模,容错,分布式索引和检索能力时使用 SolrCloud(solr 云)。

看看下面“启动”部分内容,快速的学会怎样启动一个集群。后面有 3 个快速简单的例子,它们展现怎样启动一个逐步越来越复杂的集群。检出例子之后,需要翻阅后面的部分了解更加细节的信息。

2、关于 SolrCores 和 Collections 的一点儿东西
对于单独运行的 Solr 实例,它有个东西叫 SolrCore(Solr.xml 中配置的),它是本质上独立的索引块。如果你打算多个索引块,你就创建多个 SolrCores。当同时部署SolrCloud 的时,独立的索引块可以跨越多个 Solr 实例。这意味着一个单独的索引块能由不同服务器设备上多个 SolrCore 的索引块组成。我们把组成一个逻辑索引块的所有 SolrCores 叫做一个独立索引块儿(collection)。一个独立索引块是本质上一个独立的跨越多个 SolrCore 索引块的索引块,同时索引块尽可能随着多余的设备进行缩放。如果你想把你的两个 SolrCore Solr 建立成 SolrCloud,你将有 2 个独立索引块,每个有多个独立里的 SolrCores 组成。

3、启动
下载 Solr4-Beta 或更高版本。

如果你还没了解,通过简单的 Solr 指南让自己熟悉 Solr。注意:在通过指南了解云特点前,重设所有的配置和移除指南的文档.复制带有预先存在的 Solr 索引的例子目录将导致文档计数关闭Solr 内嵌使用了Zookeeper 作为集群配置和协调运作的仓储。协调考虑作为一个包含所有 Solr 服务信息的分布式文件系统。

如果你想用一个其他的而不是 8983 作为 Solr 端口,去看下面’ Parameter Reference’部分下的关于solr.xml 注解

例 A:简单的 2 个 shard 集群
solr-shard
这个例子简单的创建了一个代表一个独立索引块的两个不同的 shards 的两个 solr 服务组成的集群。从我们将需要两个 solr 服务器,简单的复制例子目录副本作为第二个服务器时,要确保没有任何索引存在。

1
2
rm -r example /solr/collection1/data/ *
cp -r example example2

下面的命令启动了一个 solr 服务同时引导了一个新的 solr 集群

1
2
3
cd example
java -Dbootstrap_confdir=. /solr/collection1/conf
-Dcollection.configName=myconf -DzkRun -DnumShards=2 -jar start.jar

•-DzkRun 该参数将促使一个内嵌的 zookeeper 服务作为 Solr 服务的部分运行起来。
•-Dbootstrap_confdir=./solr/collection1/conf 当我们还没有 zookeeper 配置时,这个参数导致本地路径./solr/conf 作为“myconf”配置被加载.“myconf”来自下面的“collection.configName” 参数定义。
•-Dcollection.configName=myconf 设置用于新集合的配置名。省略这个参数将导致配置名字为默认的“configuration1”
•-DnumShards=2 我们打算将索引分割到逻辑分区的个数。

浏览 http://localhost:8983/solr/#/~cloud 地址,看看集群的状态。你从 zookeeper 浏览程序能看到 Solr 配置文件被加载成”myconf”,同时一个新的叫做”collection1”的文档集合被创建.collection1 下是碎片列表,这些碎片组成了那完整的集合。

现在我们想要启动我们的第二个服务器;因为我们没明确设置碎片 id,它将自动被设置成 shard2,启动第二个服务器,指向集群

1
2
cd example2
java -Djetty.port=7574 -DzkHost=localhost:9983 -jar start.jar

•-Djetty.port=7574 只是一种用于让 Jetty servlet 容器使用不同端口的方法
•-DzkHost=localhost:9983 指向全体包含集群状态的 Zookeeper 服务.这个例子中,我们运行的是一个内嵌在第一个 solr 服务器中的独立的 Zookeeper 服务.默认情况下,一个内嵌的Zookeeper 服务运行在 9983 端口上。

如果你刷新浏览器,你现在在 collection1 下应该看到两个shard1 和 shard2。

接下来,索引一些文档。如果你想要快速完成一些,像 java 你能够使用 CloudSolrServer solrj 的实现和简单的用 Zookeeper 地址初始化它就可以了.或者也可以随便选择某个 solr 实例添加文档,这些文档自动的被导向属于他们的地方。

1
2
3
4
cd exampledocs
java -Durl=http: //localhost :8983 /solr/collection1/update -jar post.jar ipod_video.xml
java -Durl=http: //localhost :8983 /solr/collection1/update -jar post.jar monitor.xml
java -Durl=http: //localhost :8983 /solr/collection1/update -jar post.jar mem.xml

现在,发起一个获得覆盖整个集合的分布式搜索服务搜索到的任何一个服务的结果的请求:

如果在任一个点你希望重新加载或尝试不同的配置,你能通过关闭服务器后简单的删除solr/zoo_data 目录方式删除所有 zookeeper 的云状态。

例 B:简单的支持副本的两个碎片集群
solr-shard2

有先前的例子,这个例子通过再创建 shard1 和 shard2 副本很容易创建起来。额外的 shard 副本用于高可用性和容错性,或用于提高集群的检索能能力。

首先,通过前一个例子, 我们已经有两个碎片和一些文档索引在里面了。然后简单的复制那两个服务:

1
2
cp -r example exampleB
cp -r example2 example2B

然后在不同的端口下启动这两个新的服务,每个都在各自的视窗下执行

1
2
3
4
cd exampleB
java -Djetty.port=8900 -DzkHost=localhost:9983 -jar start.jar
cd example2B
java -Djetty.port=7500 -DzkHost=localhost:9983 -jar start.jar

刷新 zookeeper 浏览页面,核实 4 个 solr 节点已经启动,并且每个 shard 有两个副本,因为我们已经告诉 Solr 我们想要 2 个逻辑碎片,启动的实例 3 和 4 自动的被负值为两个 shards 的副
本。

现在,向任何一个服务器发送请求来查询这个集群

多次发送这个请求,来研究 solr 服务的日志。你应该能够发现 Solr 实现跨副本的负载均衡请求,用不同的服务满足每一个请求。 浏览器发送请求的服务器里有一个顶层请求的日志描述,也会有被合并起来生成完成响应的子请求的日志描述。

为了证明故障切换的可用性,在任何一个服务器(除了运行 Zookeeper 的服务器)运行窗口下按下CTRL-C。一旦那个服务实例停止运行,就向剩余运行的服务器的任何一个发送另一个查询请求,你应该仍然看到完整的结果。

SolrCloud 能够持续提供完整查询服务直到最后一个维护每一个碎片的服务器当机.你能通过明确地关闭各个实例和查询结果来证明这种高可用性。如果你关掉维护某一个碎片的所有服务器,请求其他服务器时将会返回 503 错误结果。要想从依然运行的碎片服务中返回可用的正确文档,需要添加shards.tolerant=true 查询参数。

SolrCloud 用多主服务+监控者服务实现。这意味着某写节点或副本扮演一种特殊角色。你不需要担忧你关掉的是主服务或是集群监控,如果你关掉它们中的一个,故障切换功能将自动选出新的主服务或新的监控服务,新的服务将无缝接管各自的工作。任何 Solr 实例都能被升级为这些角色中的某个角色。

例 C:支持副本和完整 zookeeper 服务的两个碎片集群
solr-shard3
例 B 的问题是可以 有足够多的服务器保证任何一个损坏的服务器的信息幸存下来,但确只有一个包含集群状态的 zookeeper 服务器。如果那台 zookeeper 服务器损坏,分布式查询将仍然工作在上次zookeeper 保存的集群状态下,可能没有机会改变集群的状态了。

在 a zookeeper ensemble(zookeeper 集群)中运行多个 zookeeper 服务器保证 zookeeper 服务的高可用性。每个 zookeeper 服务器需要知道集群中其他服务器,且这些服务器中的一个主服务器需要提供服务。例如: 3 台组成的 zookeeper 集群允许任一个故障,而后通过剩余 2 个协商一个主服务继续提供服务。5 台的需要允许一次 2 个服务器故障。

对于用于生产服务时,推荐运行一个额外的 zookeeper 集群而不是运行内嵌在 Solr 里面的 zookeeper服务。在这里你能阅读更多关于建立 zookeeper 集群的知识。对于这个例子,为了简单点我们将用内嵌的 zookeeper 服务。

首先停止 4 个服务器并清理 zookeeper 数据

1
rm -r example* /solr/zoo_data

我们将分别在 8983,7574,8900,7500 端口运行服务。默认的方式是在主机端口+1000 运行内嵌的 zookeeper 服务,所以如果我们用前 3 个服务器运行内嵌 zookeeper,地址分别是 localhost:9983,localhost:8574,localhost:9900。

为了方便,我们上传第一个服务器 solr 配置到集群。你将注意到第一个服务器阻塞了,直到你启动了第二个服务器。这是因为 zookeeper 需要达到足够的服务器数目才允许操作。

1
2
3
4
5
6
7
8
cd example
java -Dbootstrap_confdir=. /solr/collection1/conf -Dcollection.configName=myconf -DzkRun -DzkHost=localhost:9983,localhost:8574,localhost:9900 -DnumShards=2 -jar start.jar
cd example2
java -Djetty.port=7574 -DzkRun -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar
cd exampleB
java -Djetty.port=8900 -DzkRun -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar
cd example2B
java -Djetty.port=7500 -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar

现在我们已经运行起由 3 个内嵌 zookeeper 服务组成的集群,尽管某个服务丢失依然保持工作。通过 CTRL+C 杀掉例 B 的服务器然后刷新浏览器看 zookeeper 状态可以断定 zookeeper 服务仍然工作。注意:当运行在多个 host 上时,在每个需要设置对应的 hostname,-DzkRun=hostname:port,-DzkHosts 使用准确的 host 名字和端口,默认的 localhost 将不能工作。

4、ZooKeeper
为了容错和高可用多个 zookeeper 服务器一起运行,这种模式叫做 an ensemble。对于生产环境,推荐额外运行 zookeeper ensemble 来代替 solr 内嵌的 zookeeper 服务。关于下载和运行 ensemble的更多信息访问 Apache ZooKeeper 。 更特殊的是,试着启动和管理 zookeeper。它的运行实际上非常简单。你能容银让 Solr 运行 Zookeeper,但是记住一个 zookeeper 集群不容易进行动态修改。除非将来支持动态修改,否则最好在回滚重启时进行修改。与 Solr 分开处理通常是最可取的。

当 Solr 运行内嵌 zookeeper 服务时,默认使用 solr 端口+1000 作为客户端口,另外,solr 端口+1 作为 zookeeper 服务端口,solr 端口+2 作为主服务选举端口。所以第一个例子中,Solr 运行在 8983端口,内嵌 zookeeper 使用 9983 作为客户端端口,9984 和 9985 作为服务端口。

鉴于确保 Zookeeper 搭建起来是非常快速的,要记住几点:Solr 不强烈要求使用 Zookeeper,很多情况优化可能不是必须的。另外,当添加更多的 Zookeeper 节点对读数据性能会有帮助,但也轻微的降低了写的性能。再有,当集群处于稳定运行时,solr 与 Zookeeper 没有太多的交互。如果你需要优化 zookeeper,这里有几个有益的要点:

1.ZooKeeper在专用的机器上运行效果最好。ZooKeeper 提供的是一种及时服务,专用设备有助于确保及时服务的响应。当然,专用机器并不是必须的。
2.ZooKeeper在事务日志和快照在不同的硬盘驱动器上工作效果最好
3.如果配置支持 solr 的 Zookeeper,各自使用独立的硬盘驱动器有助于性能。

5、通过集合 api 管理集合
你可以通过集合 API 管理集合。在这个 API 壳下,一般使用 CoreAdmin API 异步管理每台服务器上的 SolrCores,对于如果你自己处理使独立的 CoreAdmin API 通过替换 action 参数就能调用每个服务器来说,这无疑是一个必不可少好东西。

①创建接口

相关参数:

name:将被创建的集合的名字
numShards:集合创建时需要创建逻辑碎片的个数
replicationFactor:每个文档副本数。replicationFactor(复制因子)为 3 意思是每个逻辑碎片将有 3 份副本。注:Solr4.0 中,replicationFactor 是 additional * 副本数 ,而不是副本总数
maxShardsPerNode:一个创建操作将展开创建 numShards*replicationFactor 碎片副本遍布在你的 Solr 节点上,公平分布,同一个碎片的两个副本不会在同一个 Solr 节点上。如果创建操作完成时 Solr 损坏,该操作不会创建出新集合的任何部分。该参数用来防止在同一个 Solr 节点创建太多副本,默认参数 1.如果它的值与整体集合中 numShards*replicationFactor 副本数分布到正常活跃的Solr 节点的数不符,将不能创建任何东西
createNodeSet:如果不提供该参数,创建操作将创建碎片副本展开分布到所有活跃的 Solr 节点上。提供该参数改变用于创建碎片副本的节点集合。参数值的格式是:"<node-name1>,<node-name2>,...,<node-nameN>",
例如:createNodeSet=localhost:8983_solr,localhost:8984_solr,localhost:8985_solr
collection.configName:用于新集合的配置文件的名称。如果不提供该参数将使用集合名称作为配置文件的名称。

Solr4.2
相关参数:

name:将被创建的集合别名的名字
collections:逗号分隔的一个或多个集合别名的列表

②删除接口

相关参数:

1
<strong>name</strong>:将被删除的集合的名字

③重新加载接口

相关参数:
name:将被重载的集合的名字

④分割碎片接口

Solr4.3
相关参数:

collection:集合的名字
shard:将被分割的碎片 ID

这个命令不能用于使用自定义哈希的集群,因为这样的集群没有一个明确的哈希范围。 它只用于具有plain 或 compositeid 路由的集群。

该命令将分割给定的碎片索引对应的那个碎片成两个新碎片。通过将碎片范围划分成两个相等的分区和根据新碎片范围分割出它在父碎片(被分的碎片)中的文档。新碎片将被命名为 appending_0 和_1。例如:shard=shard1 被分割,新的碎片将被命名为 shard1_0 和 shard1_1。一旦新碎片被创建,它们就被激活同时父碎片(被分的碎片)被暂停因此将没有新的请求到父碎片(被分的碎片)。

该特征达到了无缝分割和无故障时间的要求。原来的碎片数据不会被删除。使用新 API 命令重载碎片用户自己决定。

该特性发布始于 Solr4.3,由于 4.3 发布版本发现了一些 bugs,所以要使用该特性推荐等待 4.3.1。

6、集合别名
别名允许你创建独立的指向一个或多个真是集合的虚拟集合,你能够在运行时修改别名。

①创建别名

创建或修改别名。用于发送修改的别名应该只映射一个独立的集合。读的别名能映射一个或多个集合。

②移除存在的别名

移除存在的别名

7、经 CoreAdmin 创建 cores
经过 CoreAdmin 可以创建新的 Solrcores 和使新的 Solrcores 与一个集合关联,创建时附加云相关参数

•collection 这个 core 所属的集合的名字。默认 core 的名字
•shard 这个 core 代表的碎片的 id(可选-通常自动设置一个碎片 id)
•numShards 集合碎片个数。该参数只在集合第一个 core 创建时有用
•collection.<param>=<value> 集合创建时设置属性值,用 collection.configName=<configname>指明新集合的配置文件

8、分布式请求
查询一个集合的所有碎片(注意:那个集合已经隐含在 URL 中了)

查询一个兼容集合的所有碎片,明确详述如下:

查询多个兼容集合的所有碎片

查询集合的某些碎片。例子中,用户已经按日期对索引进行分割了,每月创建一个新的碎片

明确指明以想要查询碎片的地址

明确指明以想要查询碎片的地址,同时为负载均衡和故障切换给出可选的地址

1
http://localhost:8983/solr/collection1/select?shards=localhost:8983/solr|localhost:8900/solr,localhost:7574/solr|localhost:7500/solr

9、必须的配置
所有必须的配置已经安装在 Solr 的例子中。下面是如果你正在迁移旧的配置文件你需要添加什么,或不应该删除什么

10、schema.xml
字段_version_是必须定义的

1
<field name="_version_" type="long" indexed="true" stored="true" multiValued="false"/>

11、solrconfig.xml
必要有一个更新日志的定义,这个应该被定义在 updateHandler 标签中

1
2
3
4
<!-- Enables a transaction log, currently used for real-time get."dir" - the target directory for transaction logs, defaults to thesolr data directory.  -->
< updateLog >
     < str name = "dir" >${solr.data.dir:}</ str >
</ updateLog >

必须有一个复制处理调用的定义

1
< requestHandler name = "/replication" class = "solr.ReplicationHandler" startup = "lazy" />

必须有一个获取实际时间处理的调用的定义

1
2
3
4
5
< requestHandler name = "/get" class = "solr.RealTimeGetHandler" >
< lst name = "defaults" >
     < str name = "omitHeader" >true</ str >
</ lst >
</ requestHandler >

必须有管理句柄的定义

1
< requestHandler name = "/admin/" class = "solr.admin.AdminHandlers" />

DistributedUpdateProcessor 是默认更新链的部分也会被自动注入自定义更新链。

1
2
3
4
5
6
< updateRequestProcessorChain name = "sample" >
   < processor class = "solr.LogUpdateProcessorFactory" />
   < processor class = "solr.DistributedUpdateProcessorFactory" />
   < processor class = "my.package.UpdateFactory" />
   < processor class = "solr.RunUpdateProcessorFactory" />
</ updateRequestProcessorChain >

如果不想让它自动注入到你的链中(说明你想使用 SolrCloud 功能,但想自己分发修改)那么在你的链
中指明下面的更新处理工厂: NoOpDistributingUpdateProcessorFactory

12、solr.xml
必须保留 admin path 作为默认 core

1
< cores adminPath = "/admin/cores" />

13、可变集群
当你在一个集合中启动 SolrCore 时通过 numShards 参数可以控制集群的规模。 这个参数一般自动赋给关联每个实例的碎片。启动 numShards 个实例后所有的 SolrCores 都被均匀的加入每个碎片作为副本。

向集合添加 SolrCores 保证其启动是很简单的,你随时都可以进行这样的操作。新的 SolrCore 在激活前会把它的数据同步到碎片中的副本上。

如果你要在几台机器上启动集群,不仅添加副本需要花时间扩展成集群也需要时间,那么,你可以选择通过每部机器负责几个碎片的方式启动(使用多 SolrCores),然后通过对碎片启动副本的形式迁移碎片到新的设备上,最终移除原来设备上的碎片。

Solr4.3 具备新的 API 接口, SPLITSHARD,分割已存在的碎片成两份新的碎片,相关介绍前面讲过。

14、近实时搜索
如果你希望启用近实时搜索,你可能需要修改放在ZooKeeper中的solrconfig.xml文件,添加启动软件自动提交配置,或者通过向集群发送软提交。详见看近实时搜索

15、参数参考介绍
A.集群参数

numShards 默认值 1 文档被散列存储到所有碎片的数量。每个碎片有一个主碎片(领导者),每个主碎片有 N 个副本

B.Solr 云实例参数
参数在 solr.xml 中设置,实例的运行与系统环境变量也有关。重要事项:hostPort 是每个 Solr 实例运行的端口,zookeeper 通过该端口通知集群的状态(剩余等),默认值是 8983。solr.xml 例子用的是 jetty.port 环境变量,所以如果你不想用 8983,那么你启动 Solr前设置 jetty.port 变量,或修改 solr.xml 文件。

host 默认值 找到的第一个本地地址 如果自动找到的地址是错的,你可以通过这个参数修改
hostPort 默认值 jettry的系统配置 这个参数是Solr使用的,默认使用的是jettry的配置文件
host 默认值 solr Solr 部署成 web 应用时的上下文路径。(注:在 Solr4.0 中,强制要求 hostContext 不能包含”/”或”_”字符。Solr4.1 开始,没有这个限制了,并且建议以”/”开头。运行 jetty 例子时,hostContext 既是jetty 容器的 servlet 上下文地址也是 SolrCloud 上下文地址,例:-DhostContext=/solr)

C.云实例中 Zookeeper 参数

zkRun 默认值 localhost:solrPort+1000 配置该参数让 Solr 运行起内嵌的 Zookeeper 服务。参数设置了 Zookeeper 所在的服务器地址。这个值会出现在 zkHost 参数中,我们能够知道都有哪些 zk 服务器。简单模式可以使用默认值;注意:这个值必须是 zkHost 中的一个;另外,多服务器版的不能使用默认的 localhost。
zkHost 默认值 没有 ZooKeeper host 地址——你的ZooKeeper集群一般节点地址使用逗号分割
zkClientTimeout 默认值 15000 session 没有过期前提下,不和ZooKeeper交互的最长间隔

zkClientTimeout 参数在 solr.xml 设置,也可以通过系统参数设置。

D.云核参数

shard shard 的ID,默认基于numShards自动分配 允许你指定SolrCores里的shard的Id

碎片 id 可以在每个 core 元素的属性中配置

16、把配置文件给 ZooKeeper
A.配置启动引导参数

第一次启动 Solr,有两种使用系统参数加载初始化 Zookeeper 配置文件的方法。记住,只用于第一次启动或覆盖配置文件时。每次启动都要带着系统参数,系统参数会覆盖配置文件中名字相同的值。

1.看 solr.xml 文件,找到每个 SolrCore 加载的 conf 目录。 ‘config set’ (配置集)的名字就是 SolrCore的集合的名字,集合使用与它名字相同的配置集合。

bootstrap_conf 无默认值 如果启动时携带参数 -Dbootstrap_conf=true,每个 SolrCore 将把自己的配置文件加载关联到它对应的集合上。

2.通过给的配置文件名字从指定目录下加载配置集。尽管没有指定集合到配置集的关联,如果只有一个配置集,集合将自动链接到这个配置集。

bootstrap_confdir 无默认值 如果你通过 -bootstrap_confdir=<目录≶ 启动,指定的配置目录文件将会被提交到ZooKeeper,设置配置名可以用下面的参数:collection.configName
collection.configName 默认值 configuration1 通过bootstrap_confdir设置配置集的名称

B.命令行工具
CLI 工具也可以配置 Zookeeper。 它与上面两种方法一样。 它提供一些命令,能够配置集到集合关联,创建 Zookeeper 路径或移除,还能从 zookeeper 下载配置文件到本地。

1
2
3
4
5
6
7
8
9
usage: ZkCLI
-c,--collection <arg> for linkconfig: name of the collection
-cmd <arg> cmd to run: bootstrap, upconfig, downconfig,linkconfig, makepath, clear
-d,--confdir <arg> for upconfig: a directory of configuration files
-h,--help bring up this help page
-n,--confname <arg> for upconfig, linkconfig: name of the config set
-r,--runzk <arg> run zk internally by passing the solr run port -only for clusters on one machine (tests, dev)
-s,--solrhome <arg> for bootstrap, runzk: solrhome location
-z,--zkhost <arg> ZooKeeper host address

C.例子

1
2
3
4
5
6
# try uploading a conf dir
java -classpath example/solr-webapp/WEB-INF/lib/* org.apache.solr.cloud.ZkCLI -cmd upconfig -zkhost 127.0.0.1:9983 -confdir example/solr/collection1/conf -confname conf1
# try linking a collection to a conf set
java -classpath example/solr-webapp/WEB-INF/lib/* org.apache.solr.cloud.ZkCLI -cmd linkconfig -zkhost 127.0.0.1:9983 -collection collection1 -confname conf1
# try bootstrapping all the conf dirs in solr.xml
java -classpath example/solr-webapp/WEB-INF/lib/* org.apache.solr.cloud.ZkCLI  -cmd bootstrap  -zkhost 127.0.0.1:9983  -solrhome example/solr

D.脚本
如果你不想使用jettry容器,example/cloud-scripts 目录下有系统脚本文件,它帮你处理了 classpath 和 class name,命令变成为:

1
sh zkcli.sh  -cmd linkconfig  -zkhost 127.0.0.1:9983  -collection collection1 -confname conf1

17、ZooKeeper chroot
如果其他应用已经在用 Zookeeper,你想保持原应用的管理方式,又或者有多个分开的 solrcloud 集群共用一个 zookeeper,你可以用 zookeeper 的‘chroot’选项,来自Zookeeper Session
An optional "chroot" suffix may also be appended to the connection string. This will run the client commands while interpreting all paths relative to this root (similar to the unix chroot command). If used the example would look like: "127.0.0.1:4545/app/a" or "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" where the client would be rooted at "/app/a" and all paths would be relative to this root - ie getting/setting/etc... "/foo/bar" would result in operations being run on "/app/a/foo/bar" (from the server perspective).

要使用这个特点,zkHost 参数用上”chroot”后缀,而后简单启动 solr

1
java -DzkHost=localhost:9983 /foo/bar -jar start.jar

或者

1
java -DzkHost=zoo1:9983,zoo2:9983,zoo3:9983 /foo/bar -jar start.jar

提示:Solr4.0启动时你需要预先创建ZooKeeper路径,Solr4.1以后再使用eitherbootstrap_conf 或 boostrap_confdir 的路径是自动初始化的了。

18、已知的局限性
很少 Solr 搜索框架不支持分布式搜索的。有些情况下,一个框架无法支持分布式,不过,那只是时间和努力的问题。不支持标准分布式搜索的搜索框架,它的 SolrCloud 同样不支持。通过 distrib=false控制是否使用分布式。

组群特点只能是在同一个存储碎片上的组群。必须自定义碎片特征才能使用组群特点。

如果要更新支持 SolrCloud 的 Solr4.0 到 4.1,注意 name_node 参数的定义方式已经改变了。这导致一种情况发生,由于 name_node 用 ip 地址代替了服务器的名字,使 SolrCloud 无法感知到这个name_node。你可以通过 solr.xml 配置 ip 到服务器名的关联解决问题。

19、术语

Collection: A single search index.
Shard: A logical section of a single collection (also called Slice). Sometimes people will talk about “Shard” in a physical sense (a manifestation of a logical shard)
Replica: A physical manifestation of a logical Shard, implemented as a single Lucene index on a SolrCore
Leader: One Replica of every Shard will be designated as a Leader to coordinate indexing for that Shard
SolrCore: Encapsulates a single physical index. One or more make up logical shards (or slices) which make up a collection.
Node: A single instance of Solr. A single Solr instance can have multiple SolrCores that can be part of any number of collections.
Cluster: All of the nodes you are using to host SolrCores.



相关文档:

https://cwiki.apache.org/confluence/display/solr/Getting+Started+with+SolrCloud


SolrCloud是被设计用来提供一个高可用性、可容错的环境用来索引您的数据再进行搜索。在SolrCloud里面,数据都被组织成多个“块”或者叫做“shards”(分片),使数据能够存放在多台物理机器上,并且使用replicas(复制块)提供的冗余来实现可伸缩性和容错性,该系统使用一个Zookeeper服务来帮助管理整个集群结构保证了所有的索引和搜索请求能够正确的被路由到不同的节点。

This section explains SolrCloud and its inner workings in detail, but before you dive in, it's best to have an idea of what it is you're trying to accomplish. This page provides a simple tutorial that explains how SolrCloud works on a practical level, and how to take advantage of its capabilities. We'll use simple examples of configuring SolrCloud on a single machine, which is obviously not a real production environment, which would include several servers or virtual machines. In a real production environment, you'll also use the real machine names instead of "localhost", which we've used here.

本段详细解释了SolrCloud和它的内部工作的一些细节,但在你阅读之前,你最好明白你想要通过阅读本文了解到什么。本页提供一个简单的指南用来说明SolrCloud是怎么在一个实用的水平上工作的,并且学习怎么利用它的一些功能。我们将使用简单的单机SolrCloud配置示例,很明显这并不是一个真实的生产环境,真实的生产环境通常会包含多台物理服务器或是虚拟机。在生产环境中,你也需要把我们在下面例子中使用的“localhost”替换成真实机器IP或机器名。

In this section you will learn:

  • How to distribute data over multiple instances by using ZooKeeper and creating shards.
  • How to create redundancy for shards by using replicas.
  • How to create redundancy for the overall cluster by running multiple ZooKeeper instances.

在本段你将会学习到:

  • 通过使用ZooKeeper和创建多个Shard如何将数据分布到多个实例上去。
  • 怎么通过使用Replica来为Shard构建冗余。
  • 如何通过运行多个ZooKeeper实例为整个集群创建冗余。


Simple Two-Shard Cluster on the Same Machine

在一台机器上创建一个有两个Shard的SolrCloud集群示例


Creating a cluster with multiple shards involves two steps:

  1. Start the "overseer" node, which includes an embedded ZooKeeper server to keep track of your cluster.
  2. Start any remaining shard nodes and point them to the running ZooKeeper.


创建一个带有多个shard的SolrCloud集群包含两个步骤:


  1. 启动一个“overseer”节点,这个节点包含一个内嵌的ZooKeeper服务器用来跟踪监控你的集群。
  2. 启动剩下的shard节点并且把他们连接注册到已经启动的ZooKeeper服务器实例。

Make sure to run Solr from the example directory in non-SolrCloud mode at least once before beginning; this process unpacks the jar files necessary to run SolrCloud. However, do not load documents yet, just start it once and shut it down.

请确保操作开始之前在非SolrCloud模式下至少运行一次example目录下的Solr应用;这个操作能够解压所有运行SolrCloud所必须的jar包文件。不要添加任何文档,只需要启动一次然后停止就可以了。


In this example, you'll create two separate Solr instances on the same machine. This is not a production-ready installation, but just a quick exercise to get you familiar with SolrCloud.

在这个例子中,你将在一台机器上创建两个独立的Solr实例。生产环境不会使用这样的模式,在这里只是让你能够快速的练习使用来熟悉SolrCloud。

For this exercise, we'll start by creating two copies of the example directory that is part of the Solr distribution:

为了练习,我们将通过创建Solr发布包下面的example目录的两个拷贝开始:

?
1
2
3
cd <SOLR_DIST_HOME>
cp -r example node1
cp -r example node2

These copies of the example directory can really be called anything. All we're trying to do is copy Solr's example app to the side so we can play with it and still have a stand-alone Solr example to work with later if we want.


这些example目录的拷贝可以被命名为任意名字。我们把Solr的example应用拷贝到另一个地方是为了我们能够独立使用它,假如我们稍后想要再运行Solr的话我们仍然保留了一个单独的example目录副本。

Next, start the first Solr instance, including the -DzkRun parameter, which also starts a local ZooKeeper instance:

下一步,启动第一个Solr实例,在java启动参数中加入-DzkRun 参数用来启动一个本地的ZooKeeper实例:

?
1
2
cd node1
java -DzkRun -DnumShards=2 -Dbootstrap_confdir=. /solr/collection1/conf -Dcollection.configName=myconf -jar start.jar
Let's look at each of these parameters:


我们来看一下这些参数的含义:

-DzkRun Starts up a ZooKeeper server embedded within Solr. This server will manage the cluster configuration. Note that we're doing this example all on one machine; when you start working with a production system, you'll likely use multiple ZooKeepers in an ensemble (or at least a stand-alone ZooKeeper instance). In that case, you'll replace this parameter with zkHost=<ZooKeeper Host:Port>, which is the hostname:port of the stand-alone ZooKeeper.

-DzkRun 在Solr中启动一个内嵌的ZooKeeper服务器。该服务会管理集群的相关配置。需要注意的是我们在做这个示例的时候都是在一个单独的物理机器上完成的;当你在生产环境上运行的时候,你或许会在集群中使用多个ZooKeeper示例(或者至少是一个单独的ZooKeeper实例).在上述的情况下,你可以把这个参数给替换成zkHost=<ZooKeeper服务器IP:端口>,实际上是那个单独的ZooKeeper的"主机名:端口"这种形式

-DnumShards Determines how many pieces you're going to break your index into. In this case we're going to break the index into two pieces, or shards, so we're setting this value to 2. Note that once you start up a cluster, you cannot change this value. So if you expect to need more shards later on, build them into your configuration now (you can do this by starting all of your shards on the same server, then migrating them to different servers later).

-DnumShards 该参数确定了你要把你的数据分开到多少个shard中。在这个例子中,我们将会把数据分割成两个分块,或者称为shard,所以我们把这个值设置为2。注意,在你第一次启动你的集群之后,这个值就不能再改变了,所以如果你预计你的索引在日后可能会需要更多的shard的话,你现在就应该把他们规划到到你的配置参数中(你可以在同一个服务上启动所有的shard,在日后再把它们迁移到不同的Solr实例上去。)

-Dbootstrap_confdir ZooKeeper needs to get a copy of the cluster configuration, so this parameter tells it where to find that information.

-Dbootstrap_confdir ZooKeeper需要准备一份集群配置的副本,所以这个参数是告诉SolrCloud这些配置是放在哪里。

-Dcollection.configName This parameter determines the name under which that configuration information is stored by ZooKeeper. We've used "myconf" as an example, it can be anything you'd like.

-Dcollection.configName 这个参数确定了保存在ZooKeeper中的索引配置的名字。在这里我们使用了“myconf”作为一个例子,你可以使用任意你想要使用的名字来替换。


The -DnumShards, -Dbootstrap_confdir, and -Dcollection.configName parameters need only be specified once, the first time you start Solr in SolrCloud mode. They load your configurations into ZooKeeper; if you run them again at a later time, they will re-load your configurations and may wipe out changes you have made.

-DnumShards, -Dbootstrap_confdir和-Dcollection.configName参数只需要在第一次将Solr运行在SolrCloud模式的时候声明一次。它们可以把你的配置加载到ZooKeeper中;如果你在日后重新声明了这些参数重新运行了一次,将会重新加载你的配置,这样你在原来配置上所做的一些修改操作可能会被覆盖。


At this point you have one sever running, but it represents only half the shards, so you will need to start the second one before you have a fully functional cluster. To do that, start the second instance in another window as follows:

这时候你已经有一个Solr服务在运行了,但是它仅仅代表的是你全部shard的一半,所以在你组建成一个拥有完整功能的Solr集群之前还需要启动第二个Solr服务。接下来,在新的窗口中启动第二个实例,如下:


?
1
2
cd node2
java -Djetty.port=7574 -DzkHost=localhost:9983 -jar start.jar


Because this node isn't the overseer, the parameters are a bit less complex:


因为该节点不是一个overseer节点,所以它的参数就稍微没有那么复杂了:

-Djetty.port The only reason we even have to set this parameter is because we're running both servers on the same machine, so they can't both use Jetty's default port. In this case we're choosing an arbitrary number that's different from the default. When you start on different machines, you can use the same Jetty ports if you'd like.

-Djetty.port 我们需要设置这个参数的原因只有一个,那就是我们在一台机器上运行了两个Solr实例,所以它们不能全用jetty的默认端口作为http监听端口。在这个例子中,我们使用了一个和默认端口号不相同的任意端口号。当你在不同的机器上启动Solr集群的时候,你可以使用任意的端口号作为jetty的监听端口号。

-DzkHost This parameter tells Solr where to find the ZooKeeper server so that it can "report for duty". By default, the ZooKeeper server operates on the Solr port plus 1000. (Note that if you were running an external ZooKeeper server, you'd simply point to that.)

-DzkHost 这个参数告诉Solr去哪里找ZooKeeper服务来“报到”。默认情况下,ZooKeeper服务的端口号是在Solr的端口号上加上1000。(注意:如果你运行了一个外部的ZooKeeper服务的话,你只需要简单的将这个参数值指向ZooKeeper服务的地址)

At this point you should have two Solr windows running, both being managed by ZooKeeper. To verify that, open the Solr Admin UI in your browser and go to theCloud screen:

现在你已经有两个Solr实例在运行了,它们都在同一个ZooKeeper的管理之下。为了验证一下,在你的浏览器中打开Solr Admin UI然后跳转到Cloud screen界面:

http://localhost:8983/solr/#/~cloud

Use the port of the first Solr you started; this is your overseer. You can go to the

You should see both node1 and node2, as in:

使用你启动的第一个Solr的端口号,它是你的SolrCloud集群的overseer节点。你可以在这个界面中同时看到节点1和节点2,如图所示:

Now it's time to see the cluster in action. Start by indexing some data to one or both shards. You can do this any way you like, but the easiest way is to use theexampledocs, along with curl so that you can control which port (and thereby which server) gets the updates:

现在是时候看看集群的运转情况了。开始索引若干数据到单个shard或者全部的两个shard。你可以用任意你喜欢的方式来提交数据,但是最简单的方式是使用example里面的示例文档数据连同curl一起使用,这样你就可以自己选择哪个端口(就是选择哪个Solr服务)来处理这些更新请求:


?
1
2
curl http: //localhost :8983 /solr/update ?commit= true -H "Content-Type: text/xml" -d "@mem.xml"
curl http: //localhost :7574 /solr/update ?commit= true -H "Content-Type: text/xml" -d "@monitor2.xml"


At this point each shard contains a subset of the data, but a search directed at either server should span both shards. For example, the following searches should both return the identical set of all results:


到这个时候每个shard都包含了全部文档中的一部分数据,任意一个到达Solr的搜索请求最终都会跨越两个shard处理。举个例子,下面的这两个搜索操作都会返回同样的结果集:

http://localhost:8983/solr/collection1/select?q=*:*

http://localhost:7574/solr/collection1/select?q=*:*

The reason that this works is that each shard knows about the other shards, so the search is carried out on all cores, then the results are combined and returned by the called server.

出现这样结果的原因是因为每个shard都知道集群中其他的shard的情况,所以搜索操作都会在所有的core上执行,最终结果是由最初接受请求的Solr合并并且返回给调用者的。

In this way you can have two cores or two hundred, with each containing a separate portion of the data.

通过这种方式你可以得到两个solr core,每个core都包含了整个数据集的一部分。


If you want to check the number of documents on each shard, you could add distrib=false to each query and your search would not span all shards.

如果你想要检查每个shard上面的文档数量,你可以在每个查询请求上添加一个参数 distrib=false,这样搜索操作就不会跨越每一个shard操作了。

But what about providing high availability, even if one of these servers goes down? To do that, you'll need to look at replicas.

但是在这些Slor服务中如果有一台服务宕机的情况下如何继续提供高可用性呢?为了实现这个目标,你需要了解一下Replica节点

Two-Shard Cluster with Replicas 

带有两个Shard节点以及若干Replica节点的集群


In order to provide high availability, you can create replicas, or copies of each shard that run in parallel with the main core for that shard. The architecture consists of the original shards, which are called the leaders, and their replicas, which contain the same data but let the leader handle all of the administrative tasks such as making sure data goes to all of the places it should go. This way, if one copy of the shard goes down, the data is still available and the cluster can continue to function.

为了提供高可用性,你可以创建Replica,或者可以称为和该Shard的主core并行运行的一个副本。这个结构由原始的Shard和它的一些副本构成,我们把原始的那个Shard叫做Leader,用来处理所有的管理相关的请求,例如用来确保数据去往它应该去的地方,而Replica仅仅是包含了和Leader一模一样的数据的一个副本。通过这种方式,假如该Shard的一个副本宕机了,那么整个Shard的数据仍然是可用的,并且集群仍然可用继续正常提供服务。

Start by creating two more fresh copies of the example directory:

首先创建原始example目录的两个新副本:


?
1
2
3
cd <SOLR_DIST_HOME>
cp -r example node3
cp -r example node4


Just as when we created the first two shards, you can name these copied directories whatever you want.


就像我们第一次创建两个shard一样,你可以给这些拷贝的目录命名为任意的名字。

If you don't already have the two instances you created in the previous section up and running, go ahead and restart them. From there, it's simply a matter of adding additional instances. Start by adding node3:

如果在上一段中你已经创建好的两个实例还没有启动并正常运行,先重启它们。然后,添加额外的SolrCloud实例就是一件简单的事情了。开始添加节点3:


?
1
2
cd node3
java -Djetty.port=8900 -DzkHost=localhost:9983 -jar start.jar


Notice that the parameters are exactly the same as they were for starting the second node; you're simply pointing a new instance at the original ZooKeeper. But if you look at the SolrCloud admin page, you'll see that it was added not as a third shard, but as a replica for the first:


需要注意的是这些参数恰恰是和我们启动的第二个节点的参数是一样的;简单的将你的新实例指向原来的ZooKeeper即可。这时候你看一下SolrCloud的管理页面,你就会发现新添加的节点并没有成为第三个Shard,而是第一个Shard的一个Replica(副本)

This is because the cluster already knew that there were only two shards and they were already accounted for, so new nodes are added as replicas. Similarly, when you add the fourth instance, it's added as a replica for the second shard:

这是因为集群已经知道它负责维护的Shard只有两个并且都已经存在了,所以新添加的节点只能够作为Replica存在了。同样道理,当你添加第四个实例的时候,它会被当做第二个Shard的Replica添加进集群:


?
1
2
cd node4
java -Djetty.port=7500 -DzkHost=localhost:9983 -jar start.jar




If you were to add additional instances, the cluster would continue this round-robin, adding replicas as necessary. Replicas are attached to leaders in the order in which they are started, unless they are assigned to a specific shard with an additional parameter of shardId (as a system property, as in -DshardId=1, the value of which is the ID number of the shard the new node should be attached to). Upon restarts, the node will still be attached to the same leader even if the shardId is not defined again (it will always be attached to that machine).

如果你继续添加额外的实例,集群将会继续进行重复上述的操作,必要时把它们当做Replica添加进去。每当Replica启动后它们会自动有序的附加到Leader节点上,除非它们通过一个额外的shardId参数(这个参数声明为system property参数,例如 -DshardId=1,这个参数的值就是新的节点想要附加的Shard的id值)来分配到指定的Shard。如果重启了某一个节点,它仍然会被附加到原来的Leader上(无论如何,它总会附加到同一台机器上),前提是shardId没有重新定义。

So where are we now? You now have four servers to handle your data. If you were to send data to a replica, as in:

那我们现在处在一种什么情况下?我们已经有了4个Solr服务来处理你的数据。如果你想要发送数据到replica节点的话,执行:


?
1
curl http: //localhost :7500 /solr/update ?commit= true -H "Content-Type: text/xml" -d "@money.xml"


the course of events goes like this:


  1. Replica (in this case the server on port 7500) gets the request.
  2. Replica forwards request to its leader (in this case the server on port 7574).
  3. The leader processes the request, and makes sure that all of its replicas process the request as well.

    

执行的情况可能跟下面描述的相似:

  1. Replica(在本例中是端口为7500的节点)接收到请求
  2. Replica将请求转发至它的Leader节点(在本例中是端口为7574的节点)
  3. Leader节点最终处理该请求,并且确保所有附加在它上面的Replica节点也处理这个请求。


In this way, the data is available via a request to any of the running instances, as you can see by requests to:

通过这种方式,请求到集群中任意一个实例的请求数据都能够得到有效处理,你可以通过下面的请求观察:

http://localhost:8983/solr/collection1/select?q=*:*

http://localhost:7574/solr/collection1/select?q=*:*

http://localhost:8900/solr/collection1/select?q=*:*

http://localhost:7500/solr/collection1/select?q=*:*

But how does this help provide high availability? Simply put, a cluster must have at least one server running for each shard in order to function. To test this, shut down the server on port 7574, and then check the other servers:

但是这种方式是怎么帮助我们提供高可用性的呢?简单的说,如果一个集群想要正常运行则每一个Shard都必须至少有一个节点是正常运行的。为了测试一下这种情况,关闭端口为7574的节点,然后检查其他节点:

http://localhost:8983/solr/collection1/select?q=*:*

http://localhost:8900/solr/collection1/select?q=*:*

http://localhost:7500/solr/collection1/select?q=*:*

You should continue to see the full set of data, even though one of the servers is missing. In fact, you can have multiple servers down, and as long as at least one instance for each shard is running, the cluster will continue to function. If the leader goes down – as in this example – a new leader will be "elected" from among the remaining replicas.

接下来你应该可以看到完整的数据,即便是一个节点已经挂掉。事实上,你可以停掉多个节点,只要某一个shard有一个节点处于正常运行状态,整个集群都可以正常运行。像本例中这样,如果Leader节点宕机了,一个新的Leader将会从剩下的Replica节点中被选举出来。

Note that when we talk about servers going down, in this example it's crucial that one particular server stays up, and that's the one running on port 8983. That's because it's our overseer – the instance running ZooKeeper. If that goes down, the cluster can continue to function under some circumstances, but it won't be able to adapt to any servers that come up or go down.

需要注意的是本例中所说并不是所有的节点都可以随时宕机,在本例中我们有一个特殊的重要节点需要一直保持正常运行,就是那个运行在端口8983上的节点。这是因为它是我们的overseer节点,这个节点实例中运行了维护集群状态的ZooKeeper。如果这个节点也挂掉了的话,整个集群在某些情况下可能仍然能够正常运转,但是却不能处理任何节点新增或者宕机的情况。

That kind of single point of failure is obviously unacceptable. Fortunately, there is a solution for this problem: multiple ZooKeepers.

这种单点故障的情况显然是无法接受的。幸运的是,有一个方法可以解决这个问题:多ZooKeeper集群。

Using Multiple ZooKeepers in an Ensemble


在集群中使用多ZooKeeper集群

To simplify setup for this example we're using the internal ZooKeeper server that comes with Solr, but in a production environment, you will likely be using an external ZooKeeper. The concepts are the same, however. You can find instructions on setting up an external ZooKeeper server here:http://zookeeper.apache.org/doc/r3.3.4/zookeeperStarted.html

为了使本例能够简单的安装使用,我们使用了Solr中内置的ZooKeeper服务,但是在生产环境上,你很可能会使用一个外部的ZooKeeper服务。它们的功能是一样的。你可以在下面这个网址上面找到怎么单间一个外部的ZooKeeper服务的介绍:http://zookeeper.apache.org/doc/r3.3.4/zookeeperStarted.html

To truly provide high availability, we need to make sure that not only do we also have at least one shard server running at all times, but also that the cluster also has a ZooKeeper running to manage it. To do that, you can set up a cluster to use multiple ZooKeepers. This is called using a ZooKeeper ensemble.

为了提供真正的高可用性,我们需要确保的不仅仅只是至少有一个Shard节点一直在运行,我们还要确保整个集群至少有一个ZooKeeper服务来管理这个集群。为了达到这个目的,你可以使用多个ZooKeeper服务器来搭建集群。也可以叫做使用ZooKeeper ensemble集群。

A ZooKeeper ensemble can keep running as long as more than half of its servers are up and running, so at least two servers in a three ZooKeeper ensemble, 3 servers in a 5 server ensemble, and so on, must be running at any given time. These required servers are called a quorum.

一个ZooKeeper ensemble能够在集群中有一半以上的节点存活的时候正常运行,所以在3个ZooKeeper ensemble中我们需要至少两个节点正常运行,5个的话需要3个节点正常,以此类推,必须在任意特定的时间都需要保持正常运行。这个在一个集群中必须同时正常运行的节点数叫做quorum。

In this example, you're going to set up the same two-shard cluster you were using before, but instead of a single ZooKeeper, you'll run a ZooKeeper server on three of the instances. Start by cleaning up any ZooKeeper data from the previous example:

在本例中,你将会建立一个和之前一模一样的带有两个Shard的集群,但是不是使用一个单独的ZooKeeper,ZooKeeper会在这些实例中的三个上面运行。先清除一下上一个例子中所产生的所有ZooKeeper数据:


?
1
2
cd <SOLR_DIST_DIR>
rm -r node* /solr/zoo_data


Next you're going to restart the Solr servers, but this time, rather than having them all point to a single ZooKeeper instance, each will run ZooKeeper    and    listen to the rest of the ensemble for instructions.


接下来重启所有的Solr节点,但是这次,每个节点都会运行ZooKeeper而且监听ZooKeeper ensemble中的剩下节点以执行相关指令,而不是将他们简单的指向一个单独的ZooKeeper实例。

You're using the same ports as before – 8983, 7574, 8900 and 7500 – so any ZooKeeper instances would run on ports 9983, 8574, 9900 and 8500. You don't actually need to run ZooKeeper on every single instance, however, so assuming you run ZooKeeper on 9983, 8574, and 9900, the ensemble would have an address of:

你可以使用和之前例子中使用的相同的端口号——8983,7574,8900 和7500,这样的话所有ZooKeeper实例将会分别运行在端口9983,8574,9900和8500上。事实上你并不需要在每一个实例上面都运行一个ZooKeeper服务,但是如果仅仅在993,8574和9900上运行zookeeper服务的话,ZooKeeper ensemble会拥有如下地址:

?
1
localhost:9983,localhost:8574,localhost:9900


This means that when you start the first instance, you'll do it like this:

这意味着你启动第一个实例的时候,你将这样做:


?
1
2
cd node1
java -DzkRun -DnumShards=2 -Dbootstrap_confdir=. /solr/collection1/conf -Dcollection.configName=myconf -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar


Note that the order of the parameters matters. Make sure to specify the -DzkHost parameter after the other ZooKeeper-related parameters.

注意相关参数声明的顺序问题,确保把-DzkHost声明在所有其他和ZooKeeper相关的参数之前。


You'll notice a lot of error messages scrolling past; this is because the ensemble doesn't yet have a quorum of ZooKeepers running.

你将会看到大量的错误信息滚动过屏幕;这是因为这个ZooKeeper ensemble中运行的节点数还没有达到需要的数量。

Notice also, that this step takes care of uploading the cluster's configuration information to ZooKeeper, so starting the next server is more straightforward:

同样需要注意的是,这个步骤上传了集群的相关配置信息到ZooKeeper中去,所以启动下一个节点就变得略简单了:

?
1
2
cd node2
java -Djetty.port=7574 -DzkRun -DnumShards=2  -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar


Once you start this instance, you should see the errors begin to disappear on both instances, as the ZooKeepers begin to update each other, even though you only have two of the three ZooKeepers in the ensemble running.

一旦你启动了这个实例,你应该看到错误在两个实例中都开始消失了,因为ZooKeeper开始更新了彼此的信息,即使在你的三个节点组成的ZooKeeper ensemble中只有两个节点在运行。

Next start the last ZooKeeper:

接下来启动最后一个ZooKeeper:


?
1
2
cd node3
java -Djetty.port=8900 -DzkRun -DnumShards=2 -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar


Finally, start the last replica, which doesn't itself run ZooKeeper, but references the ensemble:

最后,启动最终的Replica节点,这个节点本身不运行ZooKeeper,但是会引用到已经启动的ZooKeeper ensemble。


?
1
2
cd node4
java -Djetty.port=7500 -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar



Just to make sure everything's working properly, run a query:


为了确保所有环节都正常的工作了,执行一个查询请求:

http://localhost:8983/solr/collection1/select?q=*:*

and check the SolrCloud admin page:

然后检查SolrCloud管理界面:

Now you can go ahead and kill the server on 8983, but ZooKeeper will still work, because you have more than half of the original servers still running. To verify, open the SolrCloud admin page on another server, such as:

现在你可以返回前面的目录然后关掉在端口8983上面的节点,但是ZooKeeper将仍然正常运行,因为你拥有超过原始ZooKeeper节点数一半的节点都在正常运行。为了确保这一点,打开其他节点的SolrCloud管理页面,如下所示:

http://localhost:8900/solr/#/~cloud



“<lst name=”error”>
<str name=”msg”>no servers hosting shard:</str>
<int name=”code”>503</int>
</lst>”

 

加入下面参数,只从存活的shards获取数据:

shards.tolerant=true

例如:

<requestHandler name=”/select” class=”solr.SearchHandler”>
<lst name=”defaults”>
<str name=”echoParams”>explicit</str>
<str name=”shards.tolerant”>true</str>
<int name=”rows”>10</int>
<str name=”df”>text</str>
</lst>
</requestHandler>

 

没有打此参数,如果集群内有挂掉的shard,将显示:

no servers hosting shard


转自:http://www.solr.cc/blog/?p=44 

Apache SolrCloud安装

SolrCloud通过ZooKeeper集群来进行协调,使一个索引进行分片,各个分片可以分布在不同的物理节点上,多个物理分片组成一个完成的索引Collection。SolrCloud自动支持Solr Replication,可以同时对分片进行复制,冗余存储。下面,我们基于Solr最新的4.4.0版本进行安装配置SolrCloud集群。

1. 安装环境

我使用的安装程序各版本如下:

各个目录说明:

  • 所有的程序安装在/opt目录下,你可以依照你的实际情况下修改安装目录。
  • ZooKeeper的数据目录在:/data/zookeeper/data
  • solrhome设置在:/usr/local/solrhome

2. 规划SolrCloud

  • 单一SolrCloud数据集合:primary
  • ZooKeeper集群:3台
  • SolrCloud实例:3节点
  • 索引分片:3
  • 复制因子:2

手动将3个索引分片(Shard)的复本(Replica)分布在3个SolrCloud节点上

三个节点:

  • 192.168.56.121
  • 192.168.56.122
  • 192.168.56.123

3. 安装ZooKeeper集群

由于需要用到ZooKeeper,故我们先安装好ZooKeeper集群

首先,在第一个节点上将zookeeper-3.4.5.tar.gz解压到/opt目录:

$ tar zxvf zookeeper-3.4.5.tar.gz -C /opt/

创建zookeeper配置文件zookeeper-3.4.5/conf/zoo.cfg,内容如下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
clientPort=2181
server.1=192.168.56.121:2888:3888
server.2=192.168.56.122:2888:3888
server.3=192.168.56.123:2888:3888

zookeeper的数据目录指定在/data/zookeeper/data,你也可以使用其他目录,通过下面命令进行创建该目录:

$ mkdir /data/zookeeper/data -p

然后,初始化myid,三个节点编号依次为1,2,3,在其余节点上分别执行命令(注意修改编号)。

$ echo "1" >/data/zookeeper/data/myid

然后,在第二个和第三个节点上依次重复上面的操作。这样第一个节点中myid内容为1,第二个节点为2,第三个节点为3。

最后,启动ZooKeeper集群,在每个节点上分别启动ZooKeeper服务:

$ cd /opt
$ sh zookeeper-3.4.5/bin/zkServer.sh start

可以查看ZooKeeper集群的状态,保证集群启动没有问题:

[root@192.168.56.121 opt]# sh zookeeper-3.4.5/bin/zkServer.sh status
JMX enabled by default
Using config: /opt/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: follower

4. 安装Solr

你可以参考《Apache Solr介绍及安装》

简单来说,执行以下命令:

$ unzip apache-tomcat-6.0.36.zip  -d /opt
$ unzip solr-4.4.0.zip  -d /opt

$ cd /opt
$ chmod +x apache-tomcat-6.0.36/bin/*.sh

$ cp solr-4.4.0/example/webapps/solr.war apache-tomcat-6.0.36/webapps/
$ cp solr-4.4.0/example/lib/ext/* apache-tomcat-6.0.36/webapps/solr/WEB-INF/lib/
$ cp solr-4.4.0/example/resources/log4j.properties apache-tomcat-6.0.36/lib/

在其他节点上重复以上操作完成所有节点的solr的安装。

5. 设置SolrCloud配置文件

安装ZooKeeper集群之前,请确保每台机器上配置/etc/hosts文件,使每个节点都能通过机器名访问。

1、 创建一个SolrCloud目录,并将solr的lib文件拷贝到这个目录:

$ mkdir -p /usr/local/solrcloud/solr-lib/
$ cp apache-tomcat-6.0.36/webapps/solr/WEB-INF/lib/* /usr/local/solrcloud/solr-lib/

2、 通过bootstrap设置solrhome:

$ java -classpath .:/usr/local/solrcloud/solr-lib/* org.apache.solr.cloud.ZkCLI -zkhost 192.168.56.121:2181,192.168.56.122:2181,192.168.56.123:2181 -cmd bootstrap -solrhome /usr/local/solrhome

SolrCloud集群的所有的配置存储在ZooKeeper。 一旦SolrCloud节点启动时配置了-Dbootstrap_confdir参数, 该节点的配置信息将发送到ZooKeeper上存储。基它节点启动时会应用ZooKeeper上的配置信息,这样当我们改动配置时就不用一个个机子去更改了。

3、SolrCloud是通过ZooKeeper集群来保证配置文件的变更及时同步到各个节点上,所以,需要将配置文件上传到ZooKeeper集群中:

$ java -classpath .:/usr/local/solrcloud/solr-lib/* org.apache.solr.cloud.ZkCLI -zkhost 192.168.56.121:2181,192.168.56.122:2181,192.168.56.123:2181 -cmd upconfig -confdir /usr/local/solrcloud/conf/primary/conf -confname primaryconf

说明:

  • zkhost指定ZooKeeper地址,逗号分割
  • /usr/local/solrhome/primary/conf目录下存在schema.xml和solrconfig.xml两个配置文件,你可以修改为你自己的目录。
  • primaryconf为在ZooKeeper上的配置文件名称。

4、把配置文件和目标collection联系起来:

$ java -classpath .:/usr/local/solrcloud/solr-lib/* org.apache.solr.cloud.ZkCLI -zkhost 192.168.56.121:2181,192.168.56.122:2181,192.168.56.123:2181 -cmd linkconfig -collection primary -confname primaryconf

说明:

  • 创建的collection叫做primary,并指定和primaryconf连接

5、查看ZooKeeper上状态

在任意一个节点的/opt目录下执行如下命令:

$  zookeeper-3.4.5/bin/zkCli.sh 

[zk: localhost:2181(CONNECTED) 0] ls /
[configs, zookeeper, clusterstate.json, aliases.json, live_nodes, overseer, collections, overseer_elect]

[zk: localhost:2181(CONNECTED) 1] ls /configs
[primaryconf]

[zk: localhost:2181(CONNECTED) 1] ls /collections
[primary]

查看/configs/collections目录均有值,说明配置文件已经上传到ZooKeeper上了,接下来启动solr。

6. Tomcat配置与启动

1、修改每个节点上的tomcat配置文件,在环境变量中添加zkHost变量

编辑apache-tomcat-6.0.36/bin/catalina.sh,添加如下代码:

JAVA_OPTS='-Djetty.port=8080 -Dsolr.solr.home=/usr/local/solrhome -DzkHost=192.168.56.122:2181,192.168.56.122:2181,192.168.56.123:2181'

/usr/local/solrhome/目录创建solr.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<solr persistent="true" sharedLib="lib">
    <cores adminPath="/admin/cores" zkClientTimeout="${zkClientTimeout:15000}" hostPort="${jetty.port:8080}" hostContext="${hostContext:solr}"></cores>
</solr>

说明:

  • -Djetty.port:配置solr使用的端口,默认为8983,这里我们使用的是tomcat,端口为8080
  • -Dsolr.solr.home:配置solr/home
  • -zkHost: 配置zookeeper集群地址,多个地址逗号分隔

最后,在/opt目录下启动tomcat:

$ sh apache-tomcat-6.0.36/bin/startup.sh

通过http://192.168.56.121:8080/solr/进行访问,界面如图提示`There are no SolrCores running. `,这是因为配置文件尚未配置solrcore。

There are no SolrCores running

7. 创建Collection、Shard和Replication

手动创建Collection及初始Shard

直接通过REST接口来创建Collection,你也可以通过浏览器访问下面地址,如下所示:

$ curl 'http://192.168.56.121:8080/solr/admin/collections?action=CREATE&name=primary&numShards=3&replicationFactor=1'

如果成功,会输出如下响应内容:

<response>
<lst name="responseHeader">
    <int name="status">0</int>
    <int name="QTime">2649</int>
</lst>
<lst name="success">
    <lst>
        <lst name="responseHeader">
            <int name="status">0</int>
            <int name="QTime">2521</int>
        </lst>
        <str name="core">primary_shard2_replica1</str>
        <str name="saved">/usr/local/solrhome/solr.xml</str>
    </lst>
    <lst>
        <lst name="responseHeader">
            <int name="status">0</int>
            <int name="QTime">2561</int>
        </lst>
        <str name="core">primary_shard3_replica1</str>
        <str name="saved">/usr/local/solrhome/solr.xml</str>
    </lst>
    <lst>
        <lst name="responseHeader">
        <int name="status">0</int>
        <int name="QTime">2607</int>
        </lst>
        <str name="core">primary_shard1_replica1</str>
        <str name="saved">/usr/local/solrhome/solr.xml</str>
    </lst>
</lst>
</response>

上面链接中的几个参数的含义,说明如下:

  • name 待创建Collection的名称
  • numShards 分片的数量
  • replicationFactor 复制副本的数量

可以通过Web管理页面,访问http://192.168.56.121:8888/solr/#/~cloud,查看SolrCloud集群的分片信息,如图所示:

SolrCloud-collection-shard

实际上,我们从192.168.56.121节点可以看到,SOLR的配置文件内容,已经发生了变化,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<solr persistent="true" sharedLib="lib">
  <cores adminPath="/admin/cores" zkClientTimeout="20000" hostPort="${jetty.port:8080}" hostContext="${hostContext:solr}">
    <core shard="shard2" instanceDir="primary_shard2_replica1/" name="primary_shard2_replica1" collection="primary"/>
  </cores>
</solr>

同时,你还可以看另外两个节点上的solr.xml文件的变化。

手动创建Replication

下面对已经创建的初始分片进行复制。 shard1已经在192.168.56.123上,我们复制分片到192.168.56.121和192.168.56.122上,执行如下命令:

$ curl 'http://192.168.56.121:8080/solr/admin/cores?action=CREATE&collection=primary&name=primary_shard1_replica_2&shard=shard1'

$ curl 'http://192.168.56.122:8080/solr/admin/cores?action=CREATE&collection=primary&name=primary_shard1_replica_3&shard=shard1'

最后的结果是,192.168.56.123上的shard1,在192.168.56.121节点上有1个副本,名称为primary_shard1_replica_2,在192.168.56.122节点上有一个副本,名称为primary_shard1_replica_3。也可以通过查看192.168.56.121和192.168.56.122上的目录变化,如下所示:

$  ll /usr/local/solrhome/
total 16
drwxr-xr-x 3 root root 4096 Mar 10 17:11 primary_shard1_replica2
drwxr-xr-x 3 root root 4096 Mar 10 17:02 primary_shard2_replica1
-rw-r--r-- 1 root root  444 Mar 10 17:16 solr.xml

你还可以对shard2和shard3添加副本。

我们再次从192.168.56.121节点可以看到,SOLR的配置文件内容,又发生了变化,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<solr persistent="true" sharedLib="lib">
  <cores adminPath="/admin/cores" zkClientTimeout="20000" hostPort="${jetty.port:8080}" hostContext="${hostContext:solr}">
    <core shard="shard2" instanceDir="primary_shard2_replica1/" name="primary_shard2_replica1" collection="primary"/>
    <core shard="shard1" instanceDir="primary_shard1_replica2/" name="primary_shard1_replica_2" collection="primary"/>
  </cores>
</solr>

到此为止,我们已经基于3个节点,配置完成了SolrCloud集群。最后效果如下:

solrcloud-collection-shard-replica

8. 其他说明

8.1 SolrCloud的一些必要配置

schema.xml

必须定义_version_字段:

<field name="_version_" type="long" indexed="true" stored="true" multiValued="false"/>

solrconfig.xml

updateHandler节点下需要定义updateLog:

<!-- Enables a transaction log, currently used for real-time get.
 "dir" - the target directory for transaction logs, defaults to the
 solr data directory. -->
    <updateLog>
      <str name="dir">${solr.data.dir:}</str>
      <!-- if you want to take control of the synchronization you may specify the syncLevel as one of the
 following where ''flush'' is the default. fsync will reduce throughput.
 <str name="syncLevel">flush|fsync|none</str>
 -->
    </updateLog>

需要定义一个replication handler,名称为/replication:

<requestHandler name="/replication" class="solr.ReplicationHandler" startup="lazy" />

需要定义一个realtime get handler,名称为/get:

<requestHandler name="/get" class="solr.RealTimeGetHandler">
      <lst name="defaults">
        <str name="omitHeader">true</str>
     </lst>
    </requestHandler>

需要定义admin handlers:

<requestHandler name="/admin/" class="solr.admin.AdminHandlers" />

需要定义updateRequestProcessorChain:

<updateRequestProcessorChain name="sample">
     <processor class="solr.LogUpdateProcessorFactory" />
     <processor class="solr.DistributedUpdateProcessorFactory"/>
     <processor class="solr.RunUpdateProcessorFactory" />
   </updateRequestProcessorChain>

solr.xml

cores节点需要定义adminPath属性:

<cores adminPath="/admin/cores"

8.2 SolrCloud分布式检索时忽略宕机的Shard

<lst name=”error”>
    <str name=”msg”>no servers hosting shard:</str>
    <int name=”code”>503</int>
</lst>

加入下面参数,只从存活的shards获取数据:

shards.tolerant=true

如:http://192.168.56.121:8080/solr/primary_shard2_replica1/select?q=*%3A*&wt=xml&indent=true&shards.tolerant=true

没有打此参数,如果集群内有挂掉的shard,将显示:

no servers hosting shard

8.3 自动创建Collection及初始Shard

自动创建Collection及初始Shard,不需要通过zookeeper手动上传配置文件并关联collection。

1、在第一个节点修改tomcat启动参数

JAVA_OPTS='-Djetty.port=8080 -Dsolr.solr.home=/usr/local/solrhome -DzkHost=192.168.56.122:2181,192.168.56.122:2181,192.168.56.123:2181 -DnumShards=3 -Dbootstrap_confdir=/usr/local/solrhome/primary/conf -Dcollection.configName=primaryconf '

然后启动tomcat。这个步骤上传了集群的相关配置信息(/usr/local/solrhome/primary/conf)到ZooKeeper中去,所以启动下一个节点时不用再指定配置文件了。

2、在第二个和第三个节点修改tomcat启动参数

JAVA_OPTS='-Djetty.port=8080 -Dsolr.solr.home=/usr/local/solrhome -DzkHost=192.168.56.122:2181,192.168.56.122:2181,192.168.56.123:2181 -DnumShards=3'

然后启动tomcat。

这样就会创建3个shard分别分布在三个节点上,如果你在增加一个节点,这节点会附加到一个shard上成为一个replica,而不会创建新的shard。

9. 总结

本文记录了如何zookeeper、SolrCloud的安装和配置过程,solrcore是通过restapi进行手动创建,然后又对自动创建Collection及初始Shard进行了说明。

10. 参考文章

相关文章
相关标签/搜索