ES之snapshot备份->HDFS

小序

最新有收到一些小伙伴的反馈,说他们在测试Solr的Backup功能的时候,发现单机模式的Solr在一个Collection一个分片的情况下可以备份,但是多个分片和SolrCloud模式下备份失败,报“Could not backup all replica”的错误。
Solr也是好久没接触,我一时还没反应过来原因,于是去看官方Reference,找到snapshot的API对了一下,发现他们也没用错。于是继续阅读文档,其中的一个字眼让我立刻想到了原因:“Shared File System”。于是我问他们你们的数据没有存在HDFS或者NFS吧,他们说是,那我就知道原因了,因为snapshot API只能应用于共享文件系统
这一点跟我负责的组件ES是一样的,ES也有snapshot的功能,也只能应用于共享文件系统,例如Azure、S3、NFS或者HDFS等。于是自己试着也玩了一把,留做笔记。

版本

  • Centos7.4
  • ES:7.3.2
  • HADOOP:3.2.1
  • JAVA:1.8
  • 用到的ES插件为repository-hdfs-7.3.2.zip,“The HDFS snapshot/restore plugin is built against the latest Apache Hadoop 2.x (currently 2.7.1).” 官网说这个插件的版本基于2.7.1的内核,但我想作为客户端应该也用不了多少个API,暂且使用了3.2.1版本去验证,暂时未发现兼容性问题。网速好的可以去这里下载这个插件,像我网速不好的,每秒钟几个b的,干脆选择了使用本地的源码gradlew assemble --parallel编译了一把,找到了打包好的repository-hdfs-7.3.2.zip插件(注意,这个插件默认没有打包到ES的安装包中)。

测试过程

为了简单起见,我采用了伪分布式的部署方式部署Hadoop在自己的虚拟机上(小本本开两个虚拟机都发烫,就跑一个吧。。),其他部署方式可以参考这里

  1. 解压hadoop-3.2.1.tar.gz包(tar xzvf)
  2. cd到解压好的目录(hadoop:hadoop权限),vim etc/hadoop/hadoop-env.sh,set一下JAVA_HOME,如果想要使用hdfs dfs命令方便的话,可以再在/etc/profile中设置一下HADOOP_HOME,我这里并未执行这个。
# set to the root of your Java installation
  export JAVA_HOME=/opt/jdk1.8.0_121
  1. 配置好SSH,测试一下ssh localhost是否需要密码,需要密码的话,执行以下命令
  $ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
  $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
  $ chmod 0600 ~/.ssh/authorized_keys
  1. 配置hadoop
  • etc/hadoop/core-site.xml:
<configuration>

    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://192.168.82.133:9000</value>
    </property>

    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/hbase/hadoop-3.2.1/hadoop</value>
    </property>

</configuration>
  • etc/hadoop/hdfs-site.xml:
<configuration>

    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
    <property>
        <name>dfs.client.read.shortcircuit</name>
        <value>true</value>
    </property>
    <property>
        <name>dfs.domain.socket.path</name>
        <value>/opt/hbase/hadoop-3.2.1/dn_socket</value>
    </property>

</configuration>
  1. 启动hadoop
    ./sbin/start-dfs.sh
    没有问题的话这里一切正常启动,有问题查找原因并解决。
  2. 安装ES以及hdfs-repo插件
    解压elasticsearch-7.3.2.tar.gz
    chown elastic:elastic elasticsearch-7.3.2 -R
    bin/elasticsearch-plugin install file:///opt/repository-hdfs-7.3.2.zip
    启动ES,看到启动日志中已经正常加载了repository-hdfs 插件。
  3. 发送命令创建仓库
curl -X PUT "http://192.168.82.133:9200/_snapshot/my_hdfs_repository?pretty" -H 'Content-Type: application/json' -d'
{
  "type": "hdfs",
  "settings": {
    "uri": "hdfs://192.168.82.133:9000/",
    "path": "elasticsearch/repositories/my_hdfs_repository"
  }
}
'
  1. 发送命令备份所有索引,目前我的ES里面只有一个my_index索引
curl -X PUT "http://192.168.82.133:9200/_snapshot/my_hdfs_repository/all_indices_snapshot_1?pretty"
  • 这里我遇到一个报错:
Caused by: java.io.UncheckedIOException: Cannot create HDFS repository for uri [hdfs://192.168.82.133:9000/]
	at org.elasticsearch.repositories.hdfs.HdfsRepository.createBlobstore(HdfsRepository.java:146) ~[?:?]
	at org.elasticsearch.repositories.hdfs.HdfsRepository.lambda$createBlobStore$1(HdfsRepository.java:232) ~[?:?]
	at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_121]
	at org.elasticsearch.repositories.hdfs.HdfsRepository.createBlobStore(HdfsRepository.java:231) ~[?:?]
	at org.elasticsearch.repositories.hdfs.HdfsRepository.createBlobStore(HdfsRepository.java:54) ~[?:?]
	at org.elasticsearch.repositories.blobstore.BlobStoreRepository.blobStore(BlobStoreRepository.java:338) ~[elasticsearch-7.3.2.jar:7.3.2]
	... 6 more
Caused by: org.apache.hadoop.security.AccessControlException: Permission denied: user=elastic, access=WRITE, inode="/user":hadoop:supergroup:drwxr-xr-x
	at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:399)
	at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:255)
	at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:193)
	at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1879)
	at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1863)
  • 说的原因也很明显,是我创建的/user目录,elastic用户没有权限访问。
  • 一个简单的解决方案就是使用hdfs命令给elastic用户赋予权限即可
[hadoop@insight1 root]$ hdfs dfs -mkdir /user/elastic
[hadoop@insight1 root]$ hdfs dfs -chown elastic:hdfs /user/elastic
[hadoop@insight1 root]$ hdfs dfs -ls /
Found 1 items
drwxr-xr-x   - hadoop supergroup          0 2020-03-25 11:24 /user
[hadoop@insight1 root]$ hdfs dfs -ls /user
Found 1 items
drwxr-xr-x   - elastic hdfs          0 2020-03-25 11:24 /user/elastic
  1. 再次执行命令
curl -X PUT "http://192.168.82.133:9200/_snapshot/my_hdfs_repository/all_indices_snapshot_1?pretty"
{
  "accepted" : true
}
  1. 删除ES索引
[root@insight1 ~]# curl -X GET "http://192.168.82.133:9200/_cat/indices?v"
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   my_index K4L6Be-pR9ebSQJBstOdcQ   1   1          4            0      7.7kb          7.7kb
[root@insight1 ~]# curl -X DELETE "http://192.168.82.133:9200/my_index?pretty"
{
  "acknowledged" : true
}
  1. 执行restore
[root@insight1 ~]# curl -X POST "http://192.168.82.133:9200/_snapshot/my_hdfs_repository/all_indices_snapshot_1/_restore?pretty"
{
  "accepted" : true
}
[root@insight1 ~]#
[root@insight1 ~]# curl -X GET "http://192.168.82.133:9200/_cat/indices?v"
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   my_index T0s7m1fRR6KGhGsgnnmE2Q   1   1          4            0      7.7kb          7.7kb
以下是 `DBImpl::Get` 函数的调用关系图,每个函数的调用方式和作用在注释中有说明: ``` DBImpl::Get(const ReadOptions& options, const Slice& key, std::string* value) { Status s; MutexLock l(&mutex_); SequenceNumber snapshot; if (options.snapshot != nullptr) { snapshot = static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number(); } else { snapshot = versions_->LastSequence(); } MemTable* mem = mem_; MemTable* imm = imm_; Version* current = versions_->current(); mem->Ref(); if (imm != nullptr) { imm->Ref(); } current->Ref(); bool have_stat_update = false; Version::GetStats stats; // Unlock while reading from files and memtables { mutex_.Unlock(); LookupKey lkey(key, snapshot); if (mem->Get(lkey, value, &s)) { // 在 memtable 中查找 key // Done } else if (imm != nullptr && imm->Get(lkey, value, &s)) { // 在 immutable memtable 中查找 key // Done } else { // 在 version 中查找 key s = current->Get(options, lkey, value, &stats); have_stat_update = true; } mutex_.Lock(); } if (have_stat_update && current->UpdateStats(stats)) { MaybeScheduleCompaction(); // 更新 version 的统计信息,如果需要,则进行压缩操作 } mem->Unref(); if (imm != nullptr) { imm->Unref(); } current->Unref(); return s; // 返回查找结果 } ``` 在 `DBImpl::Get` 函数中,首先通过 `options` 参数中传入的快照获取当前 `snapshot`,然后分别获取当前的 `memtable`、`imm` 和 `version` 对象,并对其进行引用计数。接着使用 `LookupKey` 类构造一个 `lkey`,然后依次在 `memtable` 和 `imm` 中查找 `lkey`,如果找到则直接返回结果,否则需要在 `version` 中查找。在查找过程中,为了避免锁的粒度过大,需要先解锁再进行查找操作,最后再加锁。 如果在 `version` 中查找成功,则需要更新 `version` 的统计信息,并根据需要进行压缩操作。最后对 `memtable`、`imm` 和 `version` 进行引用计数的减少,并返回查找结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值