问题
用的是阿里云Elasticsearch,数据节点3个:
节点CPU时高时低,很不稳定
解放方案
内存和cpu使用率偏高的情况,可以从以下四个方面考虑:
- 降低并发写入量、删除下无用的索引释放资源(尤其是.monitor开头的日志索引,可设置保留周期)
- 考虑清理索引缓存, POST/索引名/_cache/clear?fielddata=true
- 考虑升配集群扩容实例规格
- 查看有索引分片是否合理
删除无用的索引
考虑清除.monitor开头的索引监控数据,也可以删除一个月以前的一些日志索引,注意删除索引同时也会删除数据。
后续可以补充一个定时任务:去获取并删除超过一定时间的索引。
查看有索引分片
从索引列表中可以看到索引的分片是5,而目前集群数据节点数是3,这会导致节点之间存在不均衡的负载分布,那么具有更多分片的节点的资源使用率将更高,并且瞬时平均负载将高于其他节点。这也是导致CPU不稳定的主要原因。
所以考虑优化分片数调整为3,或者3的倍数,让数据均摊到每个数据节点上。
索引分片调整
ES默认的分片配置就是5-1,需要添加两个参数来修改:
"number_of_shards": "3",//设置主分片为3
"number_of_replicas": "1"//设置副分片为1
整个配置文件如下:
{
"order": -2147483647,
"index_patterns": [
"*"
],
"settings": {
"index": {
"search": {
"slowlog": {
"level": "info",
"threshold": {
"fetch": {
"warn": "200ms",
"trace": "50ms",
"debug": "80ms",
"info": "100ms"
},
"query": {
"warn": "500ms",
"trace": "50ms",
"debug": "100ms",
"info": "200ms"
}
}
}
},
"refresh_interval": "10s",
"unassigned": {
"node_left": {
"delayed_timeout": "5m"
}
},
"indexing": {
"slowlog": {
"level": "info",
"threshold": {
"index": {
"warn": "200ms",
"trace": "20ms",
"debug": "50ms",
"info": "100ms"
}
},
"source": "1000"
}
},
"number_of_shards": "3",
"number_of_replicas": "1"
}
}
}
修改后之影响之后创建的索引,之前创建的索引需要等过期清理。
修改后可以看到一些新建的索引已经生效,但新建Jaeger的索引还是5-1
Jaeger是做链路追踪的工具,使用elasticsearch作为存储引擎。可能Jaeger去创建ES索引的时候会指定分片,所以导致阿里云自动创建索引的配置失效了。
在ES上设置template/default为索引添加默认设置
PUT _template/default
{
"index_patterns" : ["*"],
"order" : 1,
"settings": {
"number_of_shards": "3",
"number_of_replicas": "1"
}
}
配置后执行可以看到之后的Jaeger创建的索引都是3主分片
定期删除过期索引
package main
import (
"context"
"fmt"
"time"
"github.com/olivere/elastic/v7"
)
type Elk struct {
Client *elastic.Client
}
const (
url = "http://es-cn-xxxxxxxx.elasticsearch.aliyuncs.com:9200"
user = "elastic"
password = "123456"
)
func main() {
elk, err := NewElk(url, user, password)
if err != nil {
panic(err)
}
ctx := context.Background()
columns := []string{"index", "creation.date"}
expireTime := time.Now().AddDate(0, 0, -14).Unix()
indexs, err := elk.Client.CatIndices().Columns(columns...).Do(ctx)
if err != nil {
panic(err)
}
for _, index := range indexs {
if index.CreationDate < expireTime {
_, err := elk.Client.Delete().Index(index.Index).Do(ctx)
if err != nil {
panic(err)
}
}
}
fmt.Println(indexs)
}
func NewElk(url, user, password string) (*Elk, error) {
Es, err := elastic.NewClient(
elastic.SetSniff(false),
elastic.SetURL(url),
elastic.SetBasicAuth(user, password),
)
if err != nil {
panic("New ELK client error:" + err.Error())
}
e := &Elk{
Client: Es,
}
return e, nil
}