Elastic APM: Application Performance Monitoring ด้วย Elastic Stack

Elastic APM เป็นเครื่องมือ Application Performance Monitoring ที่ทำงานร่วมกับ ELK Stack (Elasticsearch, Kibana, Beats, Logstash) ให้ความสามารถในการเก็บ traces, metrics และ error log ของแอปพลิเคชันรวมไว้กับ log analytics ในแพลตฟอร์มเดียวกัน ไม่ต้องใช้ backend แยกหลายตัว ลดความซับซ้อนในการ deploy และค่าใช้จ่ายในการดูแล infrastructure

บทความนี้จะพาดูสถาปัตยกรรม วิธีการ deploy แบบ self-hosted ฟรี (Basic license) การติดตั้ง APM Agent ใน Node.js และ Python รวมถึงการดู trace บน Kibana เพื่อหา bottleneck ของ application ในระบบจริง

สถาปัตยกรรมของระบบ

ระบบนี้ประกอบด้วย 4 องค์ประกอบหลัก Agent ฝังใน application, Server รับข้อมูลจาก agent, Elasticsearch เก็บข้อมูล และ Kibana แสดงผลบน dashboard ตัว Agent จะ buffer ข้อมูลและส่งเป็น batch ไปยัง Server ผ่าน HTTP ทำให้ไม่กระทบ performance ของแอป

  • APM Agent — library ที่ instrument application ใน runtime ของภาษา
  • APM Server — service ที่รับ event จาก agent แล้ว validate, transform, และ index เข้า Elasticsearch
  • Elasticsearch — database ที่เก็บข้อมูล traces, metrics, errors
  • Kibana — web UI สำหรับ explore และ visualize ข้อมูล APM

Deploy ด้วย Docker Compose

วิธีการที่ง่ายที่สุดสำหรับการทดลองใช้งานหรือ dev environment คือใช้ Docker Compose รันทั้ง 3 service พร้อมกัน

version: '3'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
    ports:
      - "9200:9200"
    volumes:
      - esdata:/usr/share/elasticsearch/data

  kibana:
    image: docker.elastic.co/kibana/kibana:8.11.0
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

  apm-server:
    image: docker.elastic.co/apm/apm-server:8.11.0
    command: >
      apm-server -e
      -E apm-server.rum.enabled=true
      -E output.elasticsearch.hosts=["elasticsearch:9200"]
    ports:
      - "8200:8200"
    depends_on:
      - elasticsearch

volumes:
  esdata:

รันด้วย docker-compose up -d แล้วเข้า Kibana ที่ http://localhost:5601 ไปที่ Observability → APM เพื่อดู dashboard

ติดตั้ง Agent ใน Node.js

Agent ฝั่ง Node.js ทำ auto-instrumentation ให้ library ยอดนิยม เช่น Express, Koa, HTTP, PostgreSQL, MongoDB, Redis โดยอัตโนมัติ เพียงติดตั้งและ require ก่อน require โมดูลอื่น

npm install elastic-apm-node --save

สร้างไฟล์ apm.js ที่ต้องโหลดเป็นอันดับแรก

const apm = require('elastic-apm-node').start({
  serviceName: 'order-api',
  serverUrl: 'http://apm-server:8200',
  environment: process.env.NODE_ENV || 'development',
  captureBody: 'all',
  captureHeaders: true,
  transactionSampleRate: 1.0,
});

module.exports = apm;

ใน app.js ต้อง require apm.js เป็นบรรทัดแรกสุด

require('./apm');
const express = require('express');
const app = express();

app.get('/orders/:id', async (req, res) => {
  const order = await fetchOrder(req.params.id);
  res.json(order);
});

app.listen(3000);

ติดตั้ง Agent ใน Python

Python Agent รองรับ framework หลายตัว เช่น Django, Flask, FastAPI, Starlette สำหรับ Flask ตัวอย่างการติดตั้งเป็นดังนี้

pip install elastic-apm[flask]
from flask import Flask
from elasticapm.contrib.flask import ElasticAPM

app = Flask(__name__)
app.config['ELASTIC_APM'] = {
    'SERVICE_NAME': 'payment-service',
    'SERVER_URL': 'http://apm-server:8200',
    'ENVIRONMENT': 'production',
    'CAPTURE_BODY': 'all',
}
apm = ElasticAPM(app)

@app.route('/pay/<order_id>')
def pay(order_id):
    # business logic
    return {'status': 'ok'}

Custom Transaction และ Span

นอกจาก auto-instrumentation ยังสร้าง transaction และ span เองได้ เพื่อวัด latency ของ business logic ที่ไม่อยู่ใน library มาตรฐาน

// Node.js
const apm = require('elastic-apm-node');

async function calculateDiscount(orderId) {
  const span = apm.startSpan('calculateDiscount', 'business');
  try {
    const result = await complexCalculation(orderId);
    return result;
  } catch (err) {
    apm.captureError(err);
    throw err;
  } finally {
    if (span) span.end();
  }
}

การดูผลใน Kibana

เมื่อ agent ส่งข้อมูลไปยัง Server แล้ว สามารถเข้าไปดูใน Kibana ที่เมนู Observability จะเห็น service list, transaction duration, error rate, throughput และ service map ที่แสดงความสัมพันธ์ระหว่าง service อัตโนมัติ การคลิก trace แต่ละตัวจะเห็น waterfall ของ span ทั้งหมด ช่วยให้หา bottleneck ได้รวดเร็ว

Best Practices

  • Sampling Rate — ใน production ที่ traffic สูง ตั้ง transactionSampleRate เป็น 0.1 (10%) หรือต่ำกว่าเพื่อลด storage
  • ILM Policy — ตั้ง Index Lifecycle Management ให้ลบ index เก่าอัตโนมัติ เช่น hot 7 วัน warm 30 วัน delete 90 วัน
  • Central Config — ใช้ APM Agent central configuration บน Kibana เพื่อปรับ sampling rate แบบ real-time โดยไม่ต้อง restart แอป
  • Error Grouping — กรอบ error ตาม stack trace อัตโนมัติ ทำให้เห็นว่า error ไหน frequency สูง ควรแก้ก่อน
  • RUM Agent — ใช้ Real User Monitoring agent ฝัง JavaScript ใน frontend เพื่อวัด page load time และ JavaScript error จริงจาก browser

สรุป

เครื่องมือนี้เหมาะกับทีมที่ใช้ ELK Stack อยู่แล้วหรือองค์กรที่ต้องการ control ข้อมูลแบบ self-hosted ทั้งหมด การติดตั้งง่ายผ่าน Docker Compose และ Agent รองรับภาษายอดนิยมหลายตัว auto-instrumentation ครอบคลุม library ส่วนใหญ่

จุดที่ต้องพิจารณาคือการดูแล search cluster ที่ต้องใช้ skill พอสมควร หากทีมไม่มีประสบการณ์กับ ELK Stack การเลือกใช้ SaaS cloud ของผู้ให้บริการก็เป็นทางออกที่ลด overhead ในการ maintain ลงได้มาก