ELK Stack tổng quan, Elasticsearch vs OpenSearch
Tiếp đi: ELK cho log, nhưng không phải trên Kubernetes. shop-app của mình đang chạy order, payment, inventory trên 3 VM Ubuntu. Mỗi lần có lỗi là phải SSH vào từng máy rồi grep file log. Có cách nào đỡ cực hơn không?
Có. Đây đúng là bài toán ELK sinh ra để giải. Ở bài 17.11 bạn đã thấy ELK chạy trong Kubernetes bằng operator. Phần 19.7 → 19.12 nhìn ELK như một hệ thống độc lập: chạy được trên VM, on-prem, cloud và cả K8s. Bài này là bức tranh tổng.
1. Bài toán
shop-app hiện tại:
vm-app-1 (10.0.1.11) order-service /var/log/shop/order.json
vm-app-2 (10.0.1.12) payment-service /var/log/shop/payment.json
vm-app-3 (10.0.1.13) inventory-service /var/log/shop/inventory.json
Khách báo: "Đơn ORD-1042 trừ tiền rồi mà báo lỗi". Bạn phải làm thế này:
ssh vm-app-1 'grep ORD-1042 /var/log/shop/order.json*'
ssh vm-app-2 'zgrep ORD-1042 /var/log/shop/payment.json*.gz' # file đã rotate
ssh vm-app-3 'grep ORD-1042 /var/log/shop/inventory.json'
# rồi tự ghép theo thời gian bằng mắt...
2. Vấn đề
- Chậm: 3 máy là đã mệt, 30 máy thì không thể.
- Mất log: logrotate xóa file cũ; VM chết thì log chết theo.
- Không có quyền: dev không được SSH vào production (đúng ra không nên được).
- Không trả lời được câu hỏi tổng: "payment có bao nhiêu ERROR trong 1 giờ qua, theo từng loại?" thì
grep | wc -lkhông đủ. - Không ghép được: log của 3 service phải nối nhau qua
trace.id(bài 19.1), grep tay rất khó.
3. Giải pháp: gom log về một chỗ có index
ELK = Elasticsearch + Logstash + Kibana. Sau này có thêm Beats nên hay gọi là Elastic Stack.
| Thành phần | Vai trò | Chạy ở đâu |
|---|---|---|
| Elasticsearch | Lưu và index log, trả lời query (full-text, filter, aggregation) | Cụm riêng, 1–N node |
| Logstash | Pipeline xử lý: nhận → parse/biến đổi → gửi đi. Nặng (JVM), mạnh | Máy trung gian |
| Kibana | Giao diện web: tìm log, dashboard, alert, quản trị | Cạnh cụm ES |
| Filebeat | Agent nhẹ (Go) đọc file log, gửi đi. Không mất chỗ khi restart nhờ registry | Mỗi VM app |
| Metricbeat | Agent lấy metric hệ thống/service | Mỗi VM |
| Elastic Agent + Fleet | Một agent duy nhất thay cho nhiều Beats, cấu hình tập trung từ Kibana (Fleet) | Mỗi VM |
Lưu ý: Elasticsearch ở đây là kho log. Cùng một engine với bài 6.11 (search sản phẩm), nhưng cách dùng khác: log là dữ liệu chỉ ghi thêm, theo thời gian, xóa theo tuổi.
4. Code từng bước: chạy ES + Kibana ở máy dev
Bước 1: file .env (không commit, thêm vào .gitignore):
ELASTIC_PASSWORD= # tự sinh: openssl rand -base64 24
KIBANA_PASSWORD= # mật khẩu cho user kibana_system
STACK_VERSION=8.15.3
Bước 2: docker-compose.yml (single-node, bật security):
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
environment:
- discovery.type=single-node
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=false # chỉ ở máy dev; production bật TLS (bài 19.11)
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports: ["127.0.0.1:9200:9200"] # chỉ bind localhost
volumes: [esdata:/usr/share/elasticsearch/data]
healthcheck:
test: ["CMD-SHELL", "curl -s -u elastic:$${ELASTIC_PASSWORD} localhost:9200/_cluster/health | grep -q status"]
interval: 10s
retries: 30
setup: # đặt mật khẩu cho user kibana_system rồi thoát
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
depends_on: { es: { condition: service_healthy } }
environment:
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- KIBANA_PASSWORD=${KIBANA_PASSWORD}
command: >
bash -c 'curl -s -u "elastic:$${ELASTIC_PASSWORD}" -H "Content-Type: application/json"
-X POST http://es:9200/_security/user/kibana_system/_password
-d "{\"password\":\"$${KIBANA_PASSWORD}\"}"'
kibana:
image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
depends_on: [setup]
environment:
- ELASTICSEARCH_HOSTS=http://es:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
ports: ["127.0.0.1:5601:5601"]
volumes:
esdata:
Kibana không được dùng user elastic (superuser), nên phải có bước setup.
Bước 3: log JSON từ Spring Boot (Boot 3.4+ có sẵn structured logging theo ECS):
# application.yml của payment-service
spring:
application:
name: payment-service
logging:
file:
name: /var/log/shop/payment.json
structured:
format:
file: ecs # ghi file theo Elastic Common Schema
console: logfmt # console vẫn dễ đọc cho người
structured.ecs.service:
environment: ${APP_ENV:prod}
Một dòng log ra sẽ như sau:
{"@timestamp":"2026-10-14T08:15:02.113Z","log.level":"ERROR","process.thread.name":"http-nio-8080-exec-7",
"service.name":"payment-service","service.environment":"prod","log.logger":"com.shop.payment.ChargeService",
"message":"charge failed orderId=ORD-1042","trace.id":"4bf92f3577b34da6a3ce929d0e0e4736",
"error.type":"java.net.SocketTimeoutException","ecs.version":"8.11"}
Bước 4: test bằng curl
source .env
curl -s -u "elastic:$ELASTIC_PASSWORD" localhost:9200/_cluster/health?pretty
# "status" : "green" (single-node, index không có replica)
# ghi thử một document log
curl -s -u "elastic:$ELASTIC_PASSWORD" -H 'Content-Type: application/json' \
-X POST localhost:9200/logs-shop-dev/_doc -d '{"@timestamp":"2026-10-14T08:15:02Z","service.name":"payment-service","message":"hello"}'
# mở http://localhost:5601 đăng nhập elastic / mật khẩu trong .env
Cách đưa file log thật từ 3 VM vào là bài 19.9.
5. Cách hoạt động
vm-app-1 order vm-app-2 payment vm-app-3 inventory
[order.json] [payment.json] [inventory.json]
│ Filebeat │ Filebeat │ Filebeat
└──────────┬────────────┴───────────┬───────────┘
▼ (tùy chọn: Kafka làm buffer)
┌──────────────┐
│ Logstash │ parse, thêm field, lọc DEBUG
└──────┬───────┘
▼
┌───────────────────────────────┐
│ Elasticsearch cluster │ index theo ngày / data stream
│ es-1 es-2 es-3 │
└──────────────┬────────────────┘
▼
┌────────────┐
dev ───► │ Kibana │ Discover, dashboard, alert
└────────────┘
Logstash không bắt buộc. Log đã là JSON thì Filebeat có thể gửi thẳng ES, dùng ingest pipeline để xử lý nhẹ (bài 19.9).
6. So sánh: Elasticsearch vs OpenSearch
Năm 2021 Elastic đổi license Elasticsearch/Kibana từ Apache 2.0 sang SSPL + Elastic License, để cloud provider không bán lại dịch vụ miễn phí. AWS fork bản 7.10.2 cuối cùng còn Apache 2.0 thành OpenSearch và OpenSearch Dashboards. Năm 2024 Elastic thêm AGPL làm một lựa chọn license nữa. OpenSearch giờ thuộc OpenSearch Software Foundation (Linux Foundation).
| Elasticsearch (Elastic) | OpenSearch | |
|---|---|---|
| License | Elastic License / SSPL / AGPL | Apache 2.0 |
| UI | Kibana | OpenSearch Dashboards (fork Kibana 7.10) |
| Security | Có sẵn từ bản free (user, role, TLS) | Security plugin có sẵn |
| Vòng đời index | ILM, data stream | ISM (cú pháp khác), có data stream |
| Alerting | Kibana alerting rules | Alerting plugin (monitor, trigger) |
| Agent | Beats, Elastic Agent, Fleet | Không có Fleet; dùng Fluent Bit, Data Prepper, Logstash |
| Tính năng riêng | ES|QL, APM, Elastic Security, LogsDB | PPL, SQL, Security Analytics, plugin cộng đồng |
| Managed | Elastic Cloud (AWS/GCP/Azure) | Amazon OpenSearch Service, Aiven… |
Tương thích: API REST cơ bản (_search, _bulk, mapping, query DSL) gần giống. Nhưng hai bên đã tách xa từ 7.10:
- Client: Java client mới của Elastic (
co.elastic.clients) kiểm tra header sản phẩm, không nói chuyện với OpenSearch. OpenSearch cóopensearch-javariêng. - Beats 7.13+ từ chối gửi vào OpenSearch. Dùng Filebeat OSS 7.12.1, hoặc tốt hơn là Fluent Bit / Logstash với plugin
opensearch. - Snapshot không khôi phục chéo ngoài nhóm phiên bản 7.10. Đổi bên phải reindex.
- Version: ES 8.x/9.x, OpenSearch 2.x/3.x, số version không so sánh được với nhau.
7. Khi nào nên dùng / không nên dùng
- Chọn Elasticsearch khi: muốn Elastic Agent/Fleet, APM, Elastic Cloud, tính năng mới nhất; công ty chấp nhận license Elastic.
- Chọn OpenSearch khi: cần Apache 2.0 thuần, đã ở AWS và muốn Amazon OpenSearch Service, hoặc on-prem không muốn trả subscription cho tính năng nâng cao.
- Không cần ELK khi: 1–2 service, log ít, chỉ cần xem theo label và time; Loki hoặc log của cloud rẻ hơn (bài 19.12).
Vậy mình có cần cả Logstash không, hay Filebeat gửi thẳng vào Elasticsearch là đủ? Logstash nghe nói ăn RAM lắm.
Bạn hiểu đúng: Logstash là JVM, thường cần 1–2GB heap mỗi instance. Với shop-app thì bắt đầu không cần Logstash.
| Tình huống | Kiến trúc |
|---|---|
| Log đã là JSON ECS, chỉ cần thêm vài field | Filebeat → ES (ingest pipeline) |
| Nhiều nguồn lạ: Nginx text, syslog thiết bị mạng, log app cũ | Filebeat → Logstash (grok) → ES |
| Cần gửi một bản sang nơi khác (S3, SIEM) hoặc định tuyến phức tạp | Logstash |
| Lượng log lớn, ES hay bảo trì, cần replay | Filebeat → Kafka → Logstash → ES |
Ý chính: Spring Boot đã ghi đúng ECS thì phần "parse" gần như không còn. Logstash chỉ thêm khi có lý do cụ thể.
Công ty mình đang ở AWS. Sếp bảo dùng Amazon OpenSearch cho đỡ phải vận hành. Nhưng tài liệu trên mạng toàn ghi Elasticsearch với Kibana, vậy mình làm theo có được không?
Được phần lớn, chỉ cần chỉnh vài điểm:
- Query DSL, mapping,
_bulk,_cat: hầu như giống, làm theo được. - Kibana → OpenSearch Dashboards: Discover, visualize, dashboard giống; "data view" gọi là "index pattern".
- ILM → ISM: ý tưởng giống (hot → delete), JSON policy khác (bài 19.11).
- Agent: đừng dùng Filebeat 8.x; dùng Fluent Bit hoặc Logstash với
logstash-output-opensearch. Trên AWS còn có OpenSearch Ingestion (Data Prepper managed). - Auth: Amazon OpenSearch dùng IAM (SigV4) hoặc fine-grained access control, không phải user
elastic. - Client Java: dùng
opensearch-java, không phải Elastic Java client.
Nên viết tài liệu nội bộ bằng thuật ngữ trung tính ("search cluster", "dashboard") để đổi bên không phải sửa hết.
Phỏng vấn hỏi về ELK Stack và Elasticsearch vs OpenSearch thì trả lời sao?
Q1. ELK Stack gồm những gì, vai trò từng phần?
🇻🇳 Tiếng Việt:
ELK gồm Elasticsearch để lưu và index log, Logstash để xử lý pipeline, Kibana để tìm kiếm và vẽ dashboard. Thực tế còn có Beats như Filebeat làm agent nhẹ trên từng máy, hoặc Elastic Agent quản lý tập trung qua Fleet. Với log đã là JSON, tôi thường cho Filebeat gửi thẳng Elasticsearch và dùng ingest pipeline, chỉ thêm Logstash khi cần parse phức tạp hay định tuyến nhiều nơi.
🇬🇧 English:
ELK is Elasticsearch for storing and indexing logs, Logstash for processing pipelines, and Kibana for search and dashboards. In practice we add Beats such as Filebeat as lightweight agents on each host, or Elastic Agent managed centrally through Fleet. When logs are already structured JSON, I ship them from Filebeat straight to Elasticsearch with an ingest pipeline and only add Logstash for heavy parsing or multi-destination routing.
Q2. Elasticsearch và OpenSearch khác nhau thế nào?
🇻🇳 Tiếng Việt:
Năm 2021 Elastic đổi license sang SSPL và Elastic License, AWS fork bản 7.10 thành OpenSearch theo Apache 2.0. API cơ bản vẫn giống, nhưng đã tách xa: Kibana thành OpenSearch Dashboards, ILM thành ISM, client Java và Beats mới không tương thích, snapshot không khôi phục chéo. Tôi chọn theo license, nơi chạy managed và tính năng cần, ví dụ Fleet và APM thì Elastic, đã ở AWS thì Amazon OpenSearch Service.
🇬🇧 English:
In 2021 Elastic moved to SSPL and the Elastic License, and AWS forked version 7.10 into OpenSearch under Apache 2.0. The core APIs are still similar, but they have diverged: Kibana became OpenSearch Dashboards, ILM became ISM, the new Java client and recent Beats are not compatible, and snapshots do not restore across them. I choose based on licensing, the managed offering available, and features: Fleet and APM point to Elastic, being all-in on AWS points to Amazon OpenSearch Service.
Q3. Vì sao cần log tập trung thay vì SSH grep?
🇻🇳 Tiếng Việt:
Vì log trên máy bị rotate, mất khi máy chết, dev không nên có quyền SSH production, và grep không trả lời được câu hỏi tổng hợp như số lỗi theo service. Log tập trung cho phép tìm theo trace ID qua mọi service, giữ log theo chính sách retention, phân quyền và làm dashboard, alert.
🇬🇧 English:
Because local logs get rotated, disappear when the host dies, developers should not have SSH access to production, and grep cannot answer aggregate questions like error counts per service. Centralized logging lets us search by trace ID across all services, keep logs under a retention policy, control access, and build dashboards and alerts.
Cách nhớ ngắn gọn
- Beats/Agent thu, Logstash xử lý (tùy chọn), Elasticsearch lưu, Kibana xem.
- Log JSON ECS từ Spring Boot → bỏ được phần lớn việc parse.
- OpenSearch = fork 7.10, Apache 2.0; API giống, công cụ quanh nó khác.
- Bật security ngay cả ở dev; mật khẩu từ
.env, bind 127.0.0.1.
Tự kiểm tra
Logstash có bắt buộc trong ELK không?
Không. Filebeat có thể gửi thẳng ES, dùng ingest pipeline. Logstash cho parse nặng, nhiều đích, hoặc đọc từ Kafka.
Vì sao Kibana không dùng user elastic?
elastic là superuser. Kibana dùng user hệ thống kibana_system với quyền tối thiểu.
OpenSearch fork từ bản Elasticsearch nào, vì sao?
7.10.2, bản cuối Apache 2.0, sau khi Elastic đổi license năm 2021.
Filebeat 8.x gửi vào OpenSearch được không?
Không ổn định: Beats 7.13+ kiểm tra sản phẩm và từ chối. Dùng Fluent Bit, Logstash plugin opensearch hoặc Data Prepper.
Spring Boot 3.4+ bật log ECS thế nào?
logging.structured.format.file: ecs (hoặc console: ecs).