关于elasticsearch:使用elasticsearch作为唯一存储源问题整理

5次阅读

共计 3513 个字符,预计需要花费 9 分钟才能阅读完成。

在以前的一个我的项目中,对系统进行架构设计后,须要把 es 当做惟一存储源,
记录下其中踩到的坑:
1,首先 es 不反对事务,所以在架构设计的时候肯定要思考这一点。

      特地的,es 在生产环境个别不容许应用脚本,更新操作都是在业务 Java 零碎内存中去更新,而后再刷新到 es 数据库,所以当多个线程并发批改时,只会有最初一条更新胜利(其实其余的线程也更新胜利了,只是被最初一个线程笼罩了),解决办法是上接口的调用者加分布式锁,或者把申请放到保障串行的音讯队列(比方 kafka 的同一个分区)

2,es 不反对动静批改 mapping,在做具体的 index 设计时,应该把业务须要的字段都剖析完,什么字段应用什么类型

3,非非凡状况,所有字段都应该采纳 keyword 类型,否则将产生劫难!!!在 mapping 一个 index 的时候,肯定要查看业务 Java 要操作的字段,在 mapping 中是否都有定义。比方新建一个 index,在 JavaBean 中定义了一个 Person 类,有个 String  name 的字段,在 mapping 的时候,漏掉了 name,于是在我的项目跑起来后,第一个插入的会把它 mapping 成 text 类型,后续依照 trem 查问的时候一条都查不出,或者查出谬误的数据,所以肯定要器重 mapping!!!

  另外须要留神的是,在我的项目启动的时候,应该先查看 es 对应的 index 是否存在,而后在运行我的项目 (能够利用 spring 的 InitializingBean 接口),这样根本就能保障 mapping 是正确的了。

@Configuration
@ConfigurationProperties(prefix = "elastic.search.index")
public class ElasticSearchIndexConfig implements InitializingBean {


 @Override
    public void afterPropertiesSet() {
        // ...
        this.checkAllIndexExist();
        // ...
    }


    /**
     * 服务器启动的时候,查看所有 index 是否都在
     */
    private void checkAllIndexExist() {// 判断 index,不存在就抛出异样}

}

4,举荐应用 elasticsearch-rest-high-level-client 作为 Java 操作 es 的 api,尽管写起来比拟繁琐,然而查不到数据,能够 debug 出他拼装的查问语句,而后到 kibana 工具台上执行,进而发现问题,须要留神版本。

5,依照条件查问的时候(排除含糊查问),倡议应用 trem API。

6,保留数据后,保障立即再次可见,须要把同步刷新策略改为:IMMEDIATE(强制刷新),es 作为一个分布式的搜索引擎,不会对每条数据都实时刷新到磁盘,而是先缓存,再依据策略去刷新。所以改成了强制刷新能保障保留胜利后数据可见性,然而他对性能影响重大,须要依据业务去抉择。


    /**
         * Don't refresh after this request. The default.
         */
        NONE("false"),
        /**
         * Force a refresh as part of this request. This refresh policy does not scale for high indexing or search throughput but is useful
         * to present a consistent view to for indices with very low traffic. And it is wonderful for tests!
         */
        IMMEDIATE("true"),
        /**
         * Leave this request open until a refresh has made the contents of this request visible to search. This refresh policy is
         * compatible with high indexing and search throughput but it causes the request to wait to reply until a refresh occurs.
         */
        WAIT_UNTIL("wait_for");

7,es 的 bulk 操作不反对刷新策略,他们都是默认的,之所以这样是因为 bulk 不晓得你要操作的类型是什么和你要操作的数据量。比方应用了一个 indexRequest 之前为了保证数据可见性,策略改为强制刷新,前面有个批量插入的需要,复用了这个 indexRequest,就会报异样,须要小心。

8,es 能存储海量数据,在查问这些数据的时候,可能会用分页,举荐应用 searchAfter API 一步到位。sortValues 其实就了解为游标。下次查问的时候,es 依照这个游标去查。


   public void pageQuery(int age) {
        int resultLength;
        Object[] sortValues = null;
        boolean hasLogTotal = true;
        do {SearchResponse response = this.pageQueryData(age, sortValues);
            SearchHit[] searchHits = response.getHits().getHits();
            if (searchHits.length > 0) {this.processData(searchHits);
                int index = searchHits.length - 1;
                SearchHit searchHit = searchHits[index];
                sortValues = searchHit.getSortValues();}
            resultLength = searchHits.length;
        } while (resultLength > 0);
    }


  private SearchResponse pageQueryData(int  age, Object[] sortValues) {BoolQueryBuilder boolQueryBuild = QueryBuilders.boolQuery();
        QueryBuilder matchQuery = QueryBuilders.matchQuery("age", age);
        boolQueryBuild.must(matchQuery);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(boolQueryBuild);
        builder.sort(SortBuilders.fieldSort("id").order(SortOrder.ASC));
        builder.size(100);
        if (sortValues != null && sortValues.length > 0) {builder.searchAfter(sortValues);
        }

        SearchRequest searchRequest = new SearchRequest("person");
        searchRequest.source(builder);
        SearchResponse response = null;
        try {response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {e.printStackTrace();
        }
        return response;
    }

private void processData(SearchHit[] searchHits){// 转换成 Java 对象,实现业务操作}

9,es 不反对像 mysql 丰盛的索引,他自身就不是干这一行的,然而当做惟一数据源的时候,有些数据要保障惟一,所以要建惟一索引,比方 person,须要保障每个用户身份证号惟一。es 实际中那么能够把身份证号当做 id,须要小心 id 不反对批改,意味着用户身份证号发生变化了,须要先删除再创立,而不能希图更新来实现,这里有删除的逻辑,所以要问这样的数据重要吗?用户是否要关怀,如果是,那么能够把这样的数据放在 backup 表。

10,有些时候须要同步数据,在应用 mysql 的时候,能够利用 binlog 日志,然而在用 es 的时候不再反对相似的同步形式,能够应用 mq。

11,须要思考数据备份的状况,个别运维会每天备份一次 es,不是热备份,所以通过各种工具链接 es 的时候肯定要小心操作生产环境的数据,否则当天的数据无奈复原!!!

12,当数据量大了当前,分组的 count() 查问会比较慢。

正文完
 0