配置 MongoDB 数据库更新同步到 ElasticSearch

安装并配置 MongoDB

安装 5.0.6 版本

(20条消息) ubuntu20.04下的mongodb安装(5.0版本)(傻瓜教程)_Abandon-Lv的博客-CSDN博客_ubuntu20.04安装mongodb

配置公网访问

找到 mongd.conf 文件,按照上面的安装过程的话,位于 /etc/mongod.conf

配置:

1
2
3
net:
port: 27017
bindIp: 0.0.0.0

启动副本集(用于同步 es)

这个操作本意是做 mongo 集群模式的,不过同步到 es 也有点类似吧,利用产生的日志。

找到 mongd.conf 文件,添加副本信息:

1
2
replication:
replSetName: "rs0"

重启 mongo:

1
2
sudo service mongod stop
sudo service mongod start

在 MongoDB 命令行中输入:

1
rs.initiate()

成功启动后如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "127.0.0.1:27017",
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1577545731, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1577545731, 1)
}

安装并配置 ElasticSearch

安装

ElasticSearch 软件包和 OpenJDK 一起打包,所以你不需要去安装 Java。

ElasticSearch 7.x 确实和 OpenJDK 一起打包,但 5.x 还是要自己安装 Java 的。

首先,升级软件包索引,并且安装必要的依赖软件包,来添加一个新的 Https 软件源:

1
2
sudo apt update
sudo apt install apt-transport-https ca-certificates wget

导入软件源的 GPG key:

1
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -

上面的命令应该会输出OK,它意味着 key 已经被成功导入,这个软件源的软件包也被认为是被信任的。

下一步, 添加 Elasticsearch 软件源 到系统, 输入:

1
sudo sh -c 'echo "deb https://artifacts.elastic.co/packages/5.x/apt stable main" > /etc/apt/sources.list.d/elastic-5.x.list'

如果你想安装前一个版本的 Elasticsearch,将上面命令中的5.x替换成你需要的版本。

注意啦!mongo-connector 的依赖 elastic2-doc-manager 只支持到 es 5.x,再高了会出 bug。

一旦软件源被启用,输入下面的命令,安装Elasticsearch:

1
2
sudo apt update
sudo apt install elasticsearch

Elasticsearch 服务在安装完成后不会自动启动。想要启动服务,并且启用开机启动:(之后启动也使用此命令)

1
sudo systemctl enable --now elasticsearch.service

想要验证 Elasticsearch 正在运行,使用curl来发送一个 HTTP 请求给端口9200:

1
curl -X GET "localhost:9200/"

你应该能看到类似下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name" : "vagrant",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "IJqDxPfXSrmFQ27KbXbRIg",
"version" : {
"number" : "7.8.0",
"build_flavor" : "default",
"build_type" : "deb",
"build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
"build_date" : "2020-06-14T19:35:50.234439Z",
"build_snapshot" : false,
"lucene_version" : "8.5.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}

它将会花费 5-10 秒来启动服务。如果你看到curl: (7) Failed to connect to localhost port 9200: Connection refused,请稍等几秒钟并且再次尝试。

配置公网访问

打开elasticsearch.yml配置文件:

1
sudo vim /etc/elasticsearch/elasticsearch.yml

搜索包括network.host的这一行,取消它的注释,并且修改值为0.0.0.0:

1
network.host: 0.0.0.0

但是这样配了之后,es 启动会报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
● elasticsearch.service - Elasticsearch
Loaded: loaded (/lib/systemd/system/elasticsearch.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Fri 2022-12-02 22:54:56 CST; 2min 20s ago
Docs: https://www.elastic.co
Process: 284821 ExecStart=/usr/share/elasticsearch/bin/systemd-entrypoint -p ${PID_DIR}/elasticsearch.pid --quiet (code=exited, s>
Main PID: 284821 (code=exited, status=78)

Dec 02 22:54:23 iZbp176hnjobc7he4yu60xZ systemd[1]: Starting Elasticsearch...
Dec 02 22:54:56 iZbp176hnjobc7he4yu60xZ systemd-entrypoint[284821]: ERROR: [1] bootstrap checks failed. You must address the points d>
Dec 02 22:54:56 iZbp176hnjobc7he4yu60xZ systemd-entrypoint[284821]: bootstrap check failure [1] of [1]: the default discovery setting>
Dec 02 22:54:56 iZbp176hnjobc7he4yu60xZ systemd-entrypoint[284821]: ERROR: Elasticsearch did not exit normally - check the logs at /v>
Dec 02 22:54:56 iZbp176hnjobc7he4yu60xZ systemd[1]: elasticsearch.service: Main process exited, code=exited, status=78/CONFIG
Dec 02 22:54:56 iZbp176hnjobc7he4yu60xZ systemd[1]: elasticsearch.service: Failed with result 'exit-code'.
Dec 02 22:54:56 iZbp176hnjobc7he4yu60xZ systemd[1]: Failed to start Elasticsearch.

搜索发现,还需要配两条:

1
2
3
etwork.host: 0.0.0.0
node.name: node-1
cluster.initial_master_nodes: ["node-1"]

即可成功启动并允许公网访问。

5.x 版本和 7.x 的配置可能略有不同,大致是这么几项。

安装并配置 mongo-connector

安装

根据Elasticsearch的版本,选择合适的同步工具版本,执行下表中的安装命令即可:

Target System Install Command
Elasticsearch 1.x pip install ‘mongo-connector[elastic]’
Elasticsearch 2.x pip install ‘mongo-connector[elastic2]’
Elasticsearch 5.x pip install ‘mongo-connector[elastic5]’

> 5.x 的 es 也使用 pip install ‘mongo-connector[elastic5]’

这样会把依赖也一起下好,但是其中的 pymongo 版本与其他依赖不匹配,导致运行错误,手动卸载并安装旧版本:

1
2
pip3 uninstall pymongo
pip3 install pymongo==3.12.0

运行

1
mongo-connector -m 127.0.0.1:27017 -t 127.0.0.1:9200 -d elastic2_doc_manager

这个是前台运行的命令,后台运行考虑 nohup <instruction> &

参数细节:

1
2
3
4
5
6
7
8
-m   mongodb_host:port    —— 数据源地址,mongodb数据库地址。
-t target_host:port —— 数据目的地地址,elasticsearch集群地址。
-d xxx_doc_manager —— 数据目的地的document类型,elastic2_doc_manager或elastic_doc_manager。
-n db.collection ... —— 待同步的数据库及其collection。默认同步所有数据库。
-a admin-username —— admin用户名
-p password —— 密码

更过参数,请通过mongo-connector -h 命令查看

至此,我们可以发现,在 mongo 中增删数据,es 中都会立刻同步更新。

查看 es 内所有索引:

1
2
3
4
$ curl beet.asia:9200/_cat/indices?pretty
green open .geoip_databases xNaVgv2ZQ7u1pcYievjLIg 1 0 41 0 38.9mb 38.9mb
yellow open beet kS_iVZn4TDONrLNEhB0GPQ 1 1 1 0 3kb 3kb
yellow open mongodb_meta t4u3JAW6TDSyJTYnKspiFw 1 1 1 0 4.2kb 4.2kb

beet 为我创建的测试索引。

查看 beet 内所有数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ curl beet.asia:9200/beet/_search?pretty
{
"took" : 9,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "beet",
"_type" : "test",
"_id" : "638a095dbc15709039561e5a",
"_score" : 1.0,
"_source" : { }
}
]
}
}

过程中遇到的杂碎问题

卸载 ElasticSearch 7.x 后,安装 5.x,apt update 源被 ignore

因为有 7.x 的源,所以 apt 觉得 5.x 没用。

/etc/apt/sources.list.d 下把 7.x 的源删了,加入 5.x 的源。

ElasticSearch 5.x 启动失败

Java 路径

虽然我的路径里已经有 java 命令了,但是 es 不服,他要求必须在 /usr/local/sbin 下,所以创建一个软连接:

1
sudo ln -s /home/beet/jdk8/jdk1.8.0_202/bin/java /usr/local/sbin/java

删除 7.x 的遗产

即使我是用

1
apt-get purge elasticsearch

卸载了 7.x,但数据文件还留着,必须删掉,不然会让新装的启动不了。

1
sudo rm -rf /var/lib/elasticsearch/

For Debug: 默认 es log 路径 /var/log/elasticsearch

一个简单的 es 搜索范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
GET /doublec/_search
{
"query": {
"bool": {
"should": [
{
"query_string": {
"query": "史纲"
}
},
{
"query_string": {
"query": "跳跳鱼"
}
}
],
"minimum_should_match": 1,
"filter": [
{
"terms": {
"_type": ["issues", "pulls"]
}
},
{
"term": {
"repos_id": 62156403
}
}
]
}
}
}

查询 doublec 索引中,_type 字段为 issuespullsrepos_id 字段为 62156403,任意字段内容包含 史纲跳跳鱼,且至少其中一项有模糊相似的所有结果。注意,在 es 中,与或非的表达为:

  • 与:must
  • 或:should
  • 非:must_not
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{
"took": 18,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 17.05184,
"hits": [
{
"_index": "doublec",
"_type": "pulls",
"_id": "638cb35a1ad63df6ec914204",
"_score": 17.05184,
"_source": {
"id": 178308582,
"url": "https://github.com/QSCTech/zju-icicles/pull/41",
"number": 41,
"state": "closed",
"title": "PUll from TTfish",
"isLocked": false,
"body": "跳跳鱼添加了微积分和军事理论 之后还会再添加 : )",
"created_at": "2018-03-29T12:04:58Z",
"updated_at": "2018-03-29T23:36:44Z",
"closed_at": "2018-03-29T12:07:37Z",
"is_merged": true,
"repos_id": 62156403,
"user_id": "33076808",
"labels": [],
"repo_owner": "QSCTech",
"repo_name": "zju-icicles",
"__v": 0
}
},
{
"_index": "doublec",
"_type": "pulls",
"_id": "638cb3591ad63df6ec91405f",
"_score": 11.0693035,
"_source": {
"id": 303798743,
"url": "https://github.com/QSCTech/zju-icicles/pull/104",
"number": 104,
"state": "closed",
"title": "更新马原、物化、程设、ode、史纲",
"isLocked": false,
"body": """
- 新增马原历年考试题
- 新增物化课后习题解答
- 新增物化历年考试题
- 新增程设参考教学用书资料
- 新增常微分方程历年考题
- 新增史纲基本复习提纲资料
""",
"created_at": "2019-08-02T13:57:37Z",
"updated_at": "2019-08-06T05:13:05Z",
"closed_at": "2019-08-06T05:12:58Z",
"is_merged": true,
"repos_id": 62156403,
"user_id": "44317758",
"labels": [],
"repo_owner": "QSCTech",
"repo_name": "zju-icicles",
"__v": 0
}
},
{
"_index": "doublec",
"_type": "issues",
"_id": "638cb3531ad63df6ec913f34",
"_score": 6.7473845,
"_source": {
"id": 1210569712,
"number": 221,
"url": "https://github.com/QSCTech/zju-icicles/issues/221",
"title": "找不到在哪里上传",
"state": "closed",
"body": """
<img width="354" alt="image" src="https://user-images.githubusercontent.com/96061852/164389706-eae144b0-0a3e-48d5-b7ce-1ca471aaae20.png">
点击fork就跳转到另外神奇的地方
<img width="897" alt="image" src="https://user-images.githubusercontent.com/96061852/164389799-e55338b6-6c24-407f-b491-f3e3d863fcdd.png">

""",
"created_at": "2022-04-21T06:38:58Z",
"updated_at": "2022-04-21T06:48:29Z",
"closed_at": "2022-04-21T06:48:29Z",
"repos_id": 62156403,
"user_id": 96061852,
"user_name": "teddyab666",
"comment_count": 0,
"labels": [],
"repo_owner": "QSCTech",
"repo_name": "zju-icicles",
"__v": 0
}
}
]
}
}

总共命中了 3 个结果,最后一项因为 跳转 被和 跳跳鱼 模糊关联,所以被计入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"_index": "doublec",
"_type": "pulls",
"_id": "638cb35a1ad63df6ec914209",
"_score": 3.4644349,
"_source": {
"id": 445383601,
"url": "https://github.com/QSCTech/zju-icicles/pull/157",
"number": 157,
"state": "closed",
"title": "编译原理与计网资料添加",
"isLocked": false,
"body": """
添加编译原理期末考试试卷
添加编译原理部分课后题参考答案
添加计网课后题参考答案
""",
"created_at": "2020-07-07T12:34:56Z",
"updated_at": "2020-07-10T10:37:43Z",
"closed_at": "2020-07-10T10:37:43Z",
"is_merged": true,
"repos_id": 62156403,
"user_id": "37428146",
"labels": [],
"repo_owner": "QSCTech",
"repo_name": "zju-icicles",
"__v": 0
}
}

搜索关键词 网络 ,发现 计网 也可以被计入。

调试搜索语句工具

elastic 官方给出的 kibana,很好用,在本地起了一个测试 web。版本号需要和 es 完全一致。

image-20221204232706604

MongoDB 内存占用过高

很不幸,当你把 mongo 放在公网随便访问,虽然课程作业方便,但吃枣被人删库+勒索比特币一条龙。

更不幸的是,我开了 mongo-connector,mongo 里一删库,es 里直接同步删库。

于是我需要拿 dump 的数据重启一下。然鹅,mongorestore 的时候直接卡死了,此时我意识到事情不对。都删库了,内存占用还是奇高无比??到底是谁占用了这么多内存呢?

对 es 和 mongo 分别进行了一番检索,最后目标确定到 mongo 的副本集日志 local->oplog.rs 上。这是 mongodb 的副本同步日志,也是 mongo-connector 监听的对象。一看有四十几万条,一百多MB。

搜索了网上清理这个的方法,然鹅 mongo 官方手册说不要手动清理。在启动前设置好最大值,到阈值了会自动清理。

阿里云有压缩 log 的方法,但是感觉压缩了内存也未必充足,所以我就直接清空重启了。

首先,副本集模式下无法删除 local 数据库。所以先停止 MongoDB,注释掉 mongod.conf 里的副本集模式设置,再启动 mongo,删除 local。

再关闭 mongo,开启副本集模式,启动 mongo,此时 mongo 内一个数据库都没有,需要 rs.initiate()。完成。local 库被重新创建。

令人惊讶的是,内存直接爆降七八百 MB。明明 oplog.rs 原本只有一百多。十分神秘。