Solr/SolrCloud SolrConfigHandler详解

来源:互联网 发布:中国好歌曲知乎 编辑:程序博客网 时间:2024/04/29 03:46

这一个是比较神奇的Handler,生于solr-5.0,至今默默无闻。她的神奇是因为除了代码和SOLR-6924之外,好像没有一个地方提及她了,包括UserGuide和Wiki。但是呢,她又是比较实用的一个Handler,她不应该安静和沉寂,她需要被发现和使用。

她提供一个非常实用功能,至少对我来说是这样的。她提供一个实时且动态的获取和更新solrconfig.xml配置的功能。其实这么说并不准确,但可以先这么理解。因为SolrConfigHandler并没有直接更新solrconfig.xml,而且是在zookeeper中的solrconfig.xml同目录下生成一个configoverlay.json文件用于存储更新配置项。格式当然是 json 了啦。

以前我们想更新solrconfig.xml是一个比较麻烦的过程。先是更新solrconfig.xml文件,重加载对应的Collection。这个过程若是在程序中控制就更加麻烦了。
现在不用了,可以直接通过SolrConfigHandler完成,使代码变得简洁的清晰。

场景
我们知道增量索引,当然希望Solr频繁的发生soft commit,为了使索引可见嘛。我们也知道soft commit也是会消耗一定的性能的嘛,同时带来频繁的Merge嘛。
然而我们重刷索引的时候,并不希望Solr频繁的发生soft commit,甚至是hard commit。为了不影响旧索引完整性也好,为了性能也好。总之我们期望Solr的commit频率可控嘛,此时就需要更新solrconfig.xml或者其它方式来控制commit的配置。

SolrConfigHandler是一个Handler,所以她也是Solr的一个Plugin,那么她就可以在solrconfig.xml上修改其配置。刚说过了,她除代码和一个ISSUE之外没有其它地方提及,连solrconfig.xml也是。她是默认存在的,而且打开可以编辑的功能。需要关闭可编辑的功能,只需要在solrconfig.xml加上如配置即可。或者在JVM加一个 -Ddisable.configEdit=true

<requestHandler name="config" class="solr.SolrConfigHandler">    <lst name="defaults">        <str name="immutable">true</str>    </lst></requestHandler>

下面介绍这个神奇的Handler,它在没任意介绍的情况下,采用一种比较新奇使用方式。我们已经知道SolrConfigHandler主要提供两个功能,查询配置信息更改配置信息。对应SolrConfigHandler也是非常清晰,获取配置信息用METHOD.GET,而更改配置信息用的是METHOD.POST。这个逻辑非常清晰。

看一下代码,我们已经知道Handler需要实现抽象类RequestHandlerBase,同时还需要实现handleRequestBody()方法,并把逻辑放在这里。

public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {    setWt(req, CommonParams.JSON); // 返回结果以json的形式表示    String httpMethod = (String) req.getContext().get("httpMethod");    Command command = new Command(req, rsp, httpMethod);    if ("POST".equals(httpMethod)) {        if (configEditing_disabled || isImmutableConfigSet) {            final String reason = configEditing_disabled ? "due to " + CONFIGSET_EDITING_DISABLED_ARG : "because ConfigSet is immutable";            throw new SolrException(SolrException.ErrorCode.FORBIDDEN, " solrconfig editing is not enabled " + reason);        }        try {            command.handlePOST(); // 更改配置信息        } finally {            RequestHandlerUtils.addExperimentalFormatWarning(rsp);        }    } else {        command.handleGET(); // 获取配置信息    }}

先看一下获取配置信息的逻辑吧。

// class Command private Command(SolrQueryRequest req, SolrQueryResponse resp, String httpMethod) {    this.req = req;    this.resp = resp;    this.method = httpMethod;    path = (String) req.getContext().get("path");    if (path == null)        path = getDefaultPath();    parts = StrUtils.splitSmart(path, '/');    if (parts.get(0).isEmpty())        parts.remove(0);}private void handleGET() { // 代码有删减    if (parts.size() == 1) {        // this is the whole config. sent out the whole payload        resp.add("config", getConfigDetails()); // 如其名    } else {        if (ConfigOverlay.NAME.equals(parts.get(1))) { // overlay            resp.add(ConfigOverlay.NAME, req.getCore().getSolrConfig().getOverlay().toMap());        } else if (RequestParams.NAME.equals(parts.get(1))) { // params        } else {            if (ZNODEVER.equals(parts.get(1))) { // znodeVersion            } else {                Map<String, Object> m = getConfigDetails();                resp.add("config", makeMap(parts.get(1), m.get(parts.get(1))));            }        }    }}

SolrConfigHandler中的parts,在Command的构造方法里被初始化,parts是URL中path部分的以为‘/’进行切分成一个List。即以 /config开始,config为第一个元素。
1. 如果只有一个元素
2. 如果有二个元素
1. 第二个元素是 overlay : 指是读取configOverlay.json文件的内容并返回
2. 第二个元素是 params :是指读Request中RequestParams的内容并返回 (两个以上)
3. 第二个元素是 znodeVersion :读取zk相关节点的版本号
4. 第二个元素是其它的东西 :这里其它是指 solrconfig.xml 出现plugin名,则返回plugin名对应的配置信息(configOverlay.json会覆盖solrconfig.xml 的配置)

我们已经说过了,更改的配置信息不会直接更新solrconfig.xml,而是存储在configoverlay.json里。但是呢,configoverlay.json是可以修改的。Solr读取时先 solrconfig.xml的信息,然后再读configoverlay.json,并以它的最新值覆盖solrconfig.xml的信息。

SolrConfigHandler读取配置信息时,其最小粒度是plugin

例如
solr/collection_name/config/updateHandler

{  "responseHeader":{    "status":0,    "QTime":0},  "config":{"updateHandler":{      "indexWriter":{"closeWaitsForMerges":true},      "commitWithin":{"softCommit":true},      "autoCommit":{        "maxDocs":-1,        "maxTime":900000,        "openSearcher":false},      "autoSoftCommit":{        "maxDocs":-1,        "maxTime":90000}}}}

如果第二个元素不是 overlay,params,znodeVersion也不是Plugin名时,报404

示例:在Java程序中直接获取Plugin的配置,有两个方式,最佳实践是自己写一对SolrRequest和SolrResponse。方式二如下:

SolrClient client = Map<String, String> map = Maps.newHashMap();map.put(CommonParams.QT, "/config/updateHandler");SolrParams params = new MapSolrParams(map);QueryResponse query = client.query(params, METHOD.GET);

接下来看看更改配置信息部分。
其实我个人的观点,除非必要或者有兴趣可以看看源码,否则能不看就不看了吧。这里不再堆handlePost()的源码,有兴趣可以自己看看,还是比较清晰的。

上面提到获取配置信息的最小粒度是Plugin更配置信息的最小粒度是配置项。

handlePost 提供六种操作,分四大类:设置、还原配置项;更新、删除Plugin。

public static final String SET_PROPERTY = "set-property";public static final String UNSET_PROPERTY = "unset-property";public static final String SET_USER_PROPERTY = "set-user-property";public static final String UNSET_USER_PROPERTY = "unset-user-property";public static final String SET = "set";public static final String UPDATE = "update";public static final String CREATE = "create";
  • 操作配置项
    1. set 更改solrcofig配置
    2. unset 还原更改
    3. unset-property 等同于 unset-user-property;set-property 等同于 set-user-property

从语义上,user-property是指 configoverlay.json;property是指 solrconfig.xml。但是呢,我们上面已经讲过了,solrconfig.xml并不能直接修改,修改的都是configoverlay.json。因为 user-property和property实际上是一回事。

尽管有很多时候都只是语义上的差异,但我个人还是建议遵守语义的差异

  • 操作Plugin配置
    1. set/create/update 其实一回事,只是语义的不同,逻辑一样的。
    2. delete 和 update 顾名思义,但是只能操作整个plugin。

这里也是我觉得SolrConfigHandler比较新颖和神奇的地方,就是她接受的参数是一个JSON,格式上跟我们METHOD.GET时返回结果格式基本一致。

{'set-property':{'updateHandler.autoCommit.maxTime':-1}}{'unset-property':'updateHandler.autoCommit.maxTime'}

注:METHOD.POST时,参数放在Post Body中

1 0
原创粉丝点击