社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Elasticsearch

一次惊心动魄的ElasticSearch集群灾难恢复记!

石杉的架构笔记 • 5 年前 • 603 次点击  

公众号后台回复“学习”,获取作者独家秘制精品资料


多年好友心血力作,阿里资深技术专家十余年JVM生产实践经验

《从开始带你成为JVM实战高手》

限时优惠:88元正在进行ing

专栏目录参见文末

扫下方海报进行试读


本文来自头条号:Wooola


1. 背景

生产es集群共12台服务器,5个索引数据总量为2亿,每个索引都有设置replicas=1-3不等。

正常情况下12台服务器down掉一两台甚至是依次挂掉过半服务器都不会有问题。

服务器配置为8-12核 48-96G内存,由于利用率不高,因此决定下线6台服务器,在实际操作过程中由于内部沟通问题导致集群数据丢失、索引损坏等一系列问题。


本文对本次灾难如何发生、怎样恢复做下回顾,以期警示大家在对生产环境做操作一定要细致谨慎、做好备份、避免此类问题发生。

给万一出现此类问题的朋友们提供下应对处理此类问题的一种思路。如有更好的解决方案,欢迎提出,共同探讨。

2. 灾难发生时间轴

2017-6-09 周五下午——运营将6台服务器拉出集群❷,此时通过域名访问不到这6台服务器,但是实际上这6台服务器仍然处于es集群中,看起来一切正常。

2017-6-12 周一上午9点——经过周末几天的观察没发现问题,运营将6台服务器下线重装系统。

2017-6-12 周一上午10点——负责从db更新数据到es的job应用大量报错(见下图),开发收到相关报错信息报警。


整个过程很简单,暴露的问题也很明显,如果沟通清楚的话在6台服务器下线重装前,开发将该6台服务器es实例依次停掉,就不会有问题,不过这一切都只是后知后觉了~

3.灾难分析

3.1. 检查集群健康状态❸:


3.2. 以索引a_index为例,查看shards情况:


可以看到集群共有12个未分配shards,a_index的0号shard主副共计2个全部丢失,因此3个分片只有2个可用,很确定的是已有数据丢失。

查看集群数据总量,2亿数据现仅存1.2亿~

3.3. 错误日志分析

class java.net.SocketTimeoutException
Read timed out
null
java.net.SocketInputStream.socketRead0:-2
java.net.SocketInputStream.socketRead:116
java.net.SocketInputStream.read:170
java.net.SocketInputStream.read:141
java.io.BufferedInputStream.fill:246
java.io.BufferedInputStream.read1:286
java.io.BufferedInputStream.read:345
sun.net.www.http.HttpClient.parseHTTPHeader:704
sun.net.www.http.HttpClient.parseHTTP:647
sun.net.www.protocol.http.HttpURLConnection.getInputStream0:1535
sun.net.www.protocol.http.HttpURLConnection.getInputStream:1440
java.net.HttpURLConnection.getResponseCode:480
com.xxx.xx.search.utils.EsSearcher.bulk:166

通过日志结合集群状态很容易得出结论——job通过bulk方式向es集群push数据,试图访问失联的shard(为了表述方便,实际上应该是该shard所在的node),导致timed out~

4. 灾难恢复

现在面临如下几个问题:

  • 数据丢失——既定的事实,好在还可以通过job同步丢失的数据来弥补

集群状态red,索引损坏部分shards失联导致job同步数据部分失败大量报错

因此,如何恢复集群以及索引状态成为解决这些问题的关键,怎样对客户端查询影响最小是难点。

4.1 尝试恢复方法一——重启es

寄希望于es会不会有很牛逼的恢复机制,原本倒是也没有抱太大希望,6台服务器依次重启之后果然是没啥用。

4.2 尝试恢复方法二——转移分片

把失联的shards分配到其它可用的nodes,梦想总是有的,结果却依旧失败,分片都没了谈何转移~

# curl -XPOST "http://ESnode:9200/_cluster/reroute' -d '{
"commands" : [ {
"move" : {
"index" : "xxx",
"shard" : 1,
"from_node" : "es_node_one",
"to_node" : "es_node_two"
}
}]
}'

4.3 尝试恢复方法三——索引删除重建

仅仅是个想法,不可行,2亿的数据,删掉重建要花费大量时间,各客户端会哭~领导会疯掉~

无论如何幸存的1.2亿数据要保住~

4.4 复制索引之后通过添加别名替换原索引——可行!

感谢es提供的reindex api,详见:Reindex API | Elasticsearch Reference [5.2] | Elastic

详细step如下,以a_index为例:

  • 创建a_index_copy索引

curl -XPUT ‘http://xxxx:9200/a_index_copy/‘ -d ‘{
 “settings”:{
 “index”:{
 “number_of_shards”:3,
 “number_of_replicas”:2
 }
 }
}
  • 通过reindex api将a_index数据copy到a_index_copy

POST _reindex
{
 "source": {
 "index": "a_index"
 },
 "dest": {
 "index": "a_index_copy",
 "op_type": "create"
 }
}
  • 删除a_index索引,这个必须要先做,否则别名无法添加

curl -XDELETE 'http://xxxx:9200/a_index'
  • 给a_index_copy添加别名a_index

curl -XPOST 'http://xxxx:9200/_aliases' -d '
 {
 "actions": [
 {"add": {"index": "a_index_copy", "alias": "a_index"}}
 ]
 }'

5. Notes

❶. 集群有服务器down掉,丢失的shard会通过其replicas shard复制并重新分配到其它可用节点。强调“依次”,是因为如果不是大量服务器同时down掉的情况(严谨点来说应该这样表述:索引的某个shard的所有主副shard均损坏/丢失),es灾备机制完全可以应付。


❷. 软负载,客户端通过域名+软负载服务器访问集群中各服务器。


❸. es集群健康状态

  • green 最健康得状态,说明所有的分片包括备份都可用。


  • yellow 主分片(primary)可用,但是副本分片(replicas)不可用(或者是没有副本)


  • red 部分的分片可用,表明分片有一部分损坏,有的分片所有主副分片损坏/丢失的情况。此时执行查询部分数据仍然可以查到。

6. 名词释义

  • node——节点,服务器运行的一个es实例,一般情况下一个es集群会有多个node


  • shard——分片,一个shard就是一个Lucene实例,是一个完整的搜索引擎。一个索引可以只包含一个shard,只是一般情况下会用多个分片,可以拆分索引到不同的node上,分担索引压力

replicas——副本数量,e.g.如果索引Aindex设置shard=2 replicas=2则表示其分片总数=2*(2+1)=6,每条数据都会有3条相同记录。


END

如有收获,请划至底部,点击“在看”,谢谢!


《从开始带你成为JVM实战高手》

专栏详细目录



欢迎长按下图关注公众号石杉的架构笔记,后台回复“学习

获取作者独家秘制精品资料

BAT架构经验倾囊相授




Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/36200
 
603 次点击