元数据平台解决方案

一 遇到的问题

数据平台中元数据的管理一般有离线数据元数据 实时数据元数据,本次主要解决了离线的元数据。也就是hive的metastore信息。
但是metastore数据存储在mysql中,而且数据之间关联性比较强比如存储数据库的dbs,存储表的tbls,存储字段信息的colums_v2等等。想要获取到一个字段需要关联大量的表。
造成了查询速度过慢,而且对于hive的元数据库也会有比较大的压力。所以准备将元数据信息迁移到ES上进行检索。

二 为什么是ES

ES的优点很多,网上一搜一堆。主要是考虑到需要进行对于字段的comment,对于表的comment进行全文检索。不仅限于用户通过db.table 的搜索模式。可以直接搜索字段,搜索字段的中文注释。
目前支持的如下:

  • 数据库名
  • 表中文名称
  • 表英文名
  • 字段名称
  • 字段中文名
  • owner

三 Mysql2ES

Mysql数据实时同步至ES有比较好的解决方案
比如 go-mysql-elasticsearch 或者 logstash-input-jdbc 上面两个插件各有各的优缺点。但是我们需要多表JOIN,需要多个hive的metasotre表join后的数据,没有必要将数据全部同步过去。而且各个表之间有以来关系。
到最后我也没弄明白ES表的以来关系是怎么创建的,所以上面的表无法满足情况只能自己写同步的代码。
因为元数据这块对实时性要求不是特别高,所以我准备每5分钟同步一次增量的。每天凌晨同步一次全量的(也可以手动),基本满足要求。
但是同步的时候不能影响用户的使用 所以需要用到ES的别名。

四 具体的实现

具体的步骤 从mysql获取到数据 -> 创建新的索引 -> 导入数据 -> 添加别名 -> 删除别名下其他的索引只保留今天刚创建的索引

1. 每天凌晨同步全量数据

a.获取所有同步的表的数据

List<SyncWideTable> syncWideTableList = syncDao.getSyncInfo();

b.判断索引是否存在

public boolean isExists(String index) {
    Client client = elasticsearchTemplate.getClient();
    IndicesExistsResponse response = client.admin().indices().prepareExists(index).get();
    boolean exists = response.isExists();
    return exists;
}

c.索引不存在则创建新的索引

public boolean createIndex(String index, String type, String mapping) {
    Client client = elasticsearchTemplate.getClient();

    //创建索引
    CreateIndexResponse indexResponse = client.admin().indices().prepareCreate(index.toLowerCase()).get();
    //如果创建成功则创建mapping
    boolean exists = indexResponse.isAcknowledged();
    if (exists) {
        AcknowledgedResponse acknowledgedResponse = client.admin().indices().preparePutMapping(index.toLowerCase())
                .setType(type)
                .setSource(mapping, XContentType.JSON)
                .get();
        //返回mapping是否创建成功
        boolean acknowledged = acknowledgedResponse.isAcknowledged();
        return acknowledged;
    }
    //否则返回失败
    return false;
}

d.导入数据

    public void bulkIndex(String index, String type, List<SyncWideTable> syncWideTables) throws Exception {
        Client client = elasticsearchTemplate.getClient();
        //批处理
        BulkRequestBuilder bulkRequest = client.prepareBulk();
        for (SyncWideTable syncWideTable : syncWideTables) {
            String id = syncWideTable.getDbName() + ":" + syncWideTable.getTbName();
            UpdateRequestBuilder requestBuilder = client.prepareUpdate(index, type, id);
            requestBuilder.setDoc(XContentFactory.jsonBuilder()
                    .startObject()
                    .field("TABLE_COMMENT", syncWideTable.getTableComment() == null ? "" : syncWideTable.getTableComment())
                    ...
                    .endObject());
            //有则更新无则插入
            requestBuilder.setDocAsUpsert(true);
            bulkRequest.add(requestBuilder);
        }
        bulkRequest.execute().actionGet();
//        client.close();
    }

e.添加别名

public boolean addAlias(String index, String alias) {
    Client client = elasticsearchTemplate.getClient();
    IndicesAliasesRequestBuilder aliasesRequestBuilder = client.admin().indices().prepareAliases().addAlias(index, alias);
    boolean acknowledged = aliasesRequestBuilder.execute().actionGet().isAcknowledged();
    return acknowledged;
}

f.删除别名下其他的索引

List<String> indexes = syncDao.getIndexFromAlias(ALIAS);
for (String indexTmp : indexes) {
    if (!indexTmp.equals(newIndex)) {
        try {
            syncDao.removeAlias(indexTmp, ALIAS);
        } catch (Exception e) {
            logger.info(ALIAS + " 中不存在索引 " + indexTmp);
            continue;
        }
    }
}
2. 每五分钟同步一次

直接用的springboot的调度器

private void getTbls() throws Exception {
    List<SyncWideTable> syncWideTableList = syncDao.getSyncInfo();
    logger.info("need to sync size is :" + syncWideTableList.size());
    List<String> indexes = syncDao.getIndexFromAlias(ALIAS);
    for (String index : indexes) {
        syncDao.bulkIndex(index, TYPE, syncWideTableList);
    }
    logger.info("save syncWideTableList success !!!");
}

五 注意事项

1.需要定时清理过期索引。

2.实时性要求高的无法满足。

3.如果修改表结构了 只能删除索引重新call第一个每天同步一次的接口 或者等第二天自动创建

4.10000+表同步时间基本就10几秒 所以可以不用设置为5分钟

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值