ลองเล่น Stackdriver Trace บน Django

หลังจาก implement AWS X-Ray ให้ที่บริษัทไป ผมก็เลยว่าอยากจะ implement ระบบคล้ายๆ กันให้ TipMe บ้าง แต่ TipMe อยู่บน Google Cloud ก็เลยจะต้องใช้บริการของเค้าคือ Stackdriver Trace

(Note: ถ้ายังไม่ได้อ่านตอนของ X-Ray แนะนำให้อ่านก่อนเพื่อเข้าใจ concept ของ Tracing ครับ)

Zipkin

สำหรับการใช้งาน Stackdriver Trace นั้นจะแตกต่างกับของ X-Ray ตรงที่ Trace มี API ให้เราเลือกใช้ถึง 3 แบบ คือ

  1. REST API ซึ่งจะเป็น API เฉพาะของ Trace เอง เช่นเดียวกับของ X-Ray
  2. gRPC API เป็น custom API เช่นกัน แต่ตอนนี้ยังไม่มี client library ให้ใช้
  3. Zipkin API ซึ่ง Zipkin เป็นโปรแกรมสำหรับทำ tracing แบบ open source แล้ว Google Cloud นำมาแก้ให้ใช้ gRPC API ของเค้าเป็น backend อีกทีหนึ่ง (จะเรียกว่าเป็น adapter ก็ได้)

เพื่อไม่ให้ vendor lock in เราก็จะเลือกใช้ Zipkin API ฉะนั้นอย่างแรกที่จะต้องทำคือติดตั้ง Zipkin Collector ของเค้าก่อน สำหรับบน Kubernetes ก็ใช้ Deployment ประมาณนี้

apiVersion: v1
kind: ReplicationController
metadata:
  name: zipkin
spec:
  replicas: 1
  selector:
    app: zipkin
  template:
    metadata:
      labels:
        app: zipkin
    spec:
      containers:
      - name: zipkin
        image: gcr.io/stackdriver-trace-docker/zipkin-collector
        ports:
        - containerPort: 9411
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /secrets/service-account
        livenessProbe:
          httpGet:
            path: /health
            port: 9411
          initialDelaySeconds: 120
        readinessProbe:
          httpGet:
            path: /health
            port: 9411
        resources:
          requests:
            memory: "0Mi"
            cpu: "3m"
          limits:
            memory: "256Mi"
        volumeMounts:
        - name: secret
          mountPath: /secrets
          readOnly: true
      volumes:
      - name: secret
        secret:
          secretName: zipkin
---
apiVersion: v1
kind: Service
metadata:
  name: zipkin
  labels:
    app: zipkin
spec:
  selector:
    app: zipkin
  ports:
    - port: 9411
---
apiVersion: v1
kind: Secret
metadata:
  name: zipkin
type: Opaque
data:
  service-account: แปะ service account เป็น base64

เนื่องจากบน Kubernetes เราจะใช้ instance role ไม่ได้ (เพราะไม่ได้เซตสิทธิ์ไว้ตอนเปิด cluster) ก็เลยจะต้องใช้ Service account แทน วิธีการสร้าง Service account ก็คือ

  1. เข้าไปที่ Service Accounts
  2. กด Create service account ด้านบน
  3. กรอก Service account name ตามชอบ และเลือก Role เป็น Cloud Trace > Cloud Trace Agent
  4. ติ๊ก Furnish a new private key และเลือก JSON
  5. กด Create
  6. เมื่อได้ JSON มา ให้เอาไปเข้ารหัส Base64 แล้วแปะใน Secret ด้านบน (cat file.json | base64 -w0)

พอเสร็จแล้วก็ kubectl apply -f zipkin.yaml เป็นอันเรียบร้อย

Integrate กับ Django

ถัดมาเราจะต้องติดตั้ง Tracer ลงในโปรแกรมของเรา ซึ่งถ้าเป็น Node.js แบบที่วงในก็คงจะง่าย แต่พอเป็น Python แล้วก็พบว่าเราคงจะต้องทำเอง -_-!! ซึ่งของที่ผมออกแรงนั่งทำมาก็ปล่อยเป็น open source แล้วครับ ฟีเจอร์หลักๆ ก็คือ

  • Trace request ได้
  • Trace request ออกไปทาง urllib3 (request module) ได้ รวมทั้งจะแปะ X-B3-TraceId ส่งไปให้ด้วย
  • Trace template render time ได้
  • Trace database query ได้ (แต่จะไม่ log parameter ของ query เพื่อความปลอดภัย)

วิธีการติดตั้งก็คือ

  1. เพิ่ม django-zipkin-trace==1.0.0 ลงใน requirements.txt
  2. pip install -r requirements.txt
  3. แก้ไข settings.py ของเราในส่วนของ MIDDLEWARES เติม zipkin_trace.ZipkinMiddleware ไปเป็นอันบนสุด
  4. เพิ่ม ZIPKIN_SERVER='http://zipkin:9411' ลงใน settings.py

ถ้าอยากลองเทส ก็สามารถเทสบนเครื่องได้โดยใช้ Zipkin ของแท้ ดังนี้

  1. Start Zipkin ด้วยคำสั่ง sudo docker run -d -p 9411:9411 openzipkin/zipkin
  2. เช็คว่าสามารถเข้า Zipkin ได้ที่ http://localhost:9411 (ใครใช้ Docker for Mac/Windows อาจจะต้องเข้า IP ของ VM แทน)
  3. แก้ไข ZIPKIN_SERVERS ใน settings.py ให้ชี้ไปที่ http://localhost:9411 แทน
  4. ลองเข้าเว็บ Django ของเราแล้วรีเฟรชสองสามที
  5. ใน Zipkin กด Find Traces น่าจะปรากฏ Trace ขึ้นมา

(Note: py-zipkin จะสะสม trace ให้ครบ 100 อันก่อนส่ง ต้องเปิด DEBUG=true ถึงจะส่ง trace ทันที)

Trace ที่ได้จะหน้าตาประมาณนี้

สำหรับถ้าจะใช้บน Google Cloud Trace จะหน้าตาแบบนี้

เปรียบเทียบกับ X-Ray

จากที่ใช้งานมาทั้ง 2 platform แล้ว ผมพบว่าสิ่งที่ X-Ray จะนำเสนอคือความสัมพันธ์ระหว่าง service และ error ระหว่างทำงานมากกว่า เพราะมุมมองการดู Trace นั้นสามารถใช้งานได้สะดวกมาก และมีแผนภาพระหว่าง service ด้วย

สำหรับทางฝั่ง Stackdriver Trace นั้น จุดขายคือ Auto analysis ครับ

พอเราใช้ไปสักสัปดาห์นึงแล้ว URL ไหนที่ hit บ่อยที่สุด top 3 จะถูกนำมาเทียบกับสัปดาห์ที่แล้วโดยอัตโนมัติ เพื่อให้เราเห็นว่าที่เราทำไปในสัปดาห์นี้นั้นทำให้เว็บเร็วขึ้นหรือช้าลงหรือเปล่า และสามารถกดดูตัวอย่าง Trace ใน percentile ต่างๆ ได้ด้วย (ถ้าใช้ X-Ray จะต้องไปลากในกราฟเอาเอง)

โดยส่วนตัวผมชอบแบบ X-Ray มากกว่า เพราะอยากรู้เรื่อง error เป็นหลักมากกว่าซึ่งใน Trace มันดูไม่ได้ (เข้าใจว่าน่าจะให้ไปใช้ Stackdriver Error Reporting แทน แต่ผมใช้ Sentry อยู่แล้ว)

สุดท้าย Stackdriver Trace ฟรี 100% ครับ ไม่มีข้อจำกัดใดๆ ทั้งสิ้น ฉะนั้นที่ TipMe ตอนนี้ก็จะยิงทุก request เข้าหมดทุกอันได้เลย

ขออภัยในความไม่สะดวก

Note: จริงๆ บล็อคนี้เขียนไว้เป็นตอนจบของบล็อคที่แล้ว แต่รู้สึกว่าควรจะแยกเป็นตอนใหม่

ถ้าใครเคย inbox เข้ามาที่เพจ หรืออ่านเวลาผมประกาศว่าเว็บล่ม คำพูดนึงที่ใช้บ่อยมากคือ “ขออภัยในความไม่สะดวก”

ประกาศในหน้าเว็บเคยมีคำนี้ทั้งหมด 10 ครั้ง

เวลาเขียนคำนี้มันเจ็บนะ มันรู้สึกว่าเรากำลังทำลายความเชื่อมั่นของผู้ใช้งานอยู่ และคำขอโทษที่ใช้จนเฝือเกินไปมันไม่มีความหมาย


ขณะนี้ระบบสื่อสารของเว็บขัดข้อง

ขออภัยในความไม่สะดวก

ผมจำไม่ได้ว่าประโยคประมาณนี้เคยพูดไปกี่รอบ โดยเฉพาะในช่วงเดือนก่อนย้ายเว็บ

หลายต่อหลายครั้งเข้า ประกาศจึงต้องเปลี่ยนรูปแบบไป

ตอนนี้ระบบสื่อสารมีปัญหา อยู่ในระหว่างแก้ไขครับ น่าจะใช้เวลาประมาณ 30 นาที – 1 ชั่วโมง

ระยะหลังเราเริ่มมีปัญหาลักษณะนี้กับผู้ให้บริการ ซึ่งเรากำลังพิจารณาเปลี่ยนไปใช้บริการ Google Cloud ครับ

สิ่งที่ควรพูดมากกว่าในตอนนี้แล้วคือ ในเมื่อมีปัญหาเกิดขึ้นบ่อยครั้งมาก จะทำอย่างไรไม่ให้เกิดปัญหา

คนที่ให้แนวคิดนี้ก็ไม่ใช่ใครแต่ก็คือ Google Cloud ที่เราย้ายเข้ามา

เมื่อปีที่แล้ว Google Cloud ล่มพร้อมกันทั่วโลก แต่หลังจากอ่านรายงานนั้นแล้วผมรู้สึกว่าผมไว้ใจระบบของเค้ามากกว่าเดิมเสียอีก

ลองมาดูรายงานไปพร้อมๆ กันนะครับ

  • วันที่ 11 เมษายน 2016 เวลา 14:50 วิศวกร Google ได้ลบ IP ของ Compute Engine ที่ไม่ได้ใช้ออกจากระบบ
  • เนื่องจากข้อผิดพลาดของระบบ ทำให้ไฟล์ตั้งค่า 2 อันไม่ตรงกัน ระบบควบคุมจับข้อผิดพลาดได้จึงพยายามยกเลิกการแก้ไข
  • กระบวนการยกเลิกมีบั๊ก ทำให้มันลบ IP ทั้งหมดออกจากการตั้งค่า
  • การตั้งค่าใหม่จะถูกทดลองกับ 1 ที่ก่อน ซึ่งในขั้นทดลองก็จับข้อผิดพลาดนี้ได้
  • ระบบควบคุมมีข้อผิดพลาดอีกจุดหนึ่งที่ทำให้แทนที่จะเลิก กลับไปติดตั้งให้กับระบบที่เหลือ
  • พอระบบเริ่มกระจายการตั้งค่าใหม่นี้ออกไป ระบบยังไม่ล่มในทันทีเพราะผู้ใช้งานจะถูกย้ายไปเชื่อมต่อกับจุดอื่นๆ ที่ยังไม่ได้อัพเดต
  • พอการตั้งค่าเริ่มกระจายมากขึ้นเรื่อยๆ ระบบจึงแจ้งวิศวกรจากการที่ latency เพิ่มสูงขึ้นเรื่อยๆ
  • วิศวกร Google ได้เริ่มตรวจสอบตั้งแต่ได้รับข้อความแจ้งเตือน แต่ยังหาสาเหตุไม่ได้
  • 53 นาทีต่อมา การตั้งค่าใหม่กระจายครบทั้งทั่วโลกแล้วทำให้ไม่สามารถเชื่อมต่อเข้าสู่ Compute Engine ได้โดยสมบูรณ์
  • ระบบแจ้งเตือนเห็นปริมาณข้อมูลลดลงผิดปกติจึงแจ้งเตือนอีกครั้ง
  • วิศวกรที่กำลังตรวจสอบจึงทราบว่าปัญหาเกิดขึ้นทั่วโลก เค้าจึงย้อนการตั้งค่ากลับในทันที
  • รวมแล้วจากเวลาที่ตรวจพบจนถึงเริ่มย้อนการตั้งค่า ใช้เวลา 18 นาที
  • สิ่งที่ Google จะปรับปรุงในอนาคตคือ เพิ่มการตรวจจับเมื่อ redundancy ลดลงแม้ระบบจะยังใช้งานได้อยู่, ตรวจสอบขนาด IP Block ว่ายังมีขนาดถูกต้องอยู่หลังการแก้ไข และตรวจสอบ config อัตโนมัติว่ามี IP Block ที่กำหนดไว้

ความผิดพลาดเป็นเรื่องปกติที่ใครๆ ก็เจอ สิ่งที่ผมเห็นจากรายงานนี้คือระบบที่ออกแบบมาป้องกันความผิดพลาดหลายชั้น และยังมีการแจ้งเตือนเมื่อระบบทำงานผิดพลาด แม้ปราการทั้งหมดจะล้มเหลวไปพร้อมกัน แต่เค้ามีแผนการชัดเจนว่าจะทำอย่างไรให้ไม่เกิดข้อผิดพลาดแบบนี้อีก

นั่นคือสิ่งที่ผมอยากจะทำในเว็บ อาจจะไม่ได้ถึงกับว่าล่มครั้งเดียวแล้วแก้ไขได้ใน 18 นาที เพราะคนเฝ้ามีผมคนเดียว

แต่อย่างน้อยๆ คือถ้ามันเกิดซ้ำหลายครั้งแล้วเราจะต้องสามารถแจ้งผู้ใช้งานได้ว่าจะทำยังไงไม่ให้มันเกิดขึ้นอีก


Streamlabs ขัดข้องครับ

ขออภัยในความไม่สะดวก

ก่อนระบบล่มครั้งสุดท้าย เว็บมีปัญหากับ Streamlabs เยอะมาก บางครั้งก็ Login ไม่ได้ บางครั้งส่ง Alert ไปก็ไม่ขึ้นให้

คำตอบเดียวที่ให้ผู้ใช้งานได้คือ “แจ้งไปทาง Streamlabs แล้วครับ ต้องรอทางนั้นแก้ไข” ซึ่งก็เป็นเรื่องจริง แต่ผมว่าผู้ใช้งานคงไม่ชอบ

แผนการต่อไปของเว็บคือเราจะทำระบบมาแข่งกับ Streamlabs

ซึ่งมันไม่ง่ายเลย มันเหนื่อยมากและยังมองไม่เห็นว่าจะใช้เวลากี่เดือนจึงจะถึงจุดที่ผู้ใช้งานยอมรับ

แต่ก็ต้องทำเพราะไม่อยากใช้คำขอโทษสิ้นเปลืองอีกแล้ว