สถาปัตยกรรมแบบผู้เช่าหลากหลาย Multi-tenancy Architecture

multi-tenancy architecture concept, kksEHR

การบริการคลาวด์ในปัจจุบัน มีบริการหนึ่งคือ SaaS หรือ Software as a Service ซึ่งผู้ให้บริการ SaaS รายใหญ่ๆ ในการบริการให้กับลูกค้า หรือผู้เช่า โดยส่วนมากและให้ความสำตัญไปที่การใช้สถาปัตยกรรม Multi-tenancy การบริการนี้สามารถใช้ทรัพยากร(resources)ร่วมกัน ที่ยังคงมีการแยกความแตกต่างระหว่างผู้เช่า(tenant)แต่ละรายไว้

ตัวอย่างง่ายๆ: ลองนึกถึงอาคารสำนักงาน — ตึกเดียว แต่มีหลายบริษัทเช่าพื้นที่อยู่ แต่ละบริษัทมีห้องและกุญแจของตัวเอง ใช้ลิฟต์และล็อบบี้ร่วมกัน แต่ไม่สามารถเข้าห้องของบริษัทใดบริษัทหนึ่งที่ไม่ใช่เจ้าของได้

การแยกระหว่างผู้ใช้

การออกแบบ multi-tenancy application จะต้องมีการแยกระหว่าง tenant เป็นสิ่งที่ขาดไม่ได้

Application แบบ multi-tenancy จะเป็น single instant (เป็น 1 instant application ที่ทำงานได้หลายๆ tenant) และส่งต่อไปยังฐานข้อมูล ระบบฐานข้อมูลจะแยกตามแต่ละ tenant ในการเข้าถึงการใช้งาน วิธีการแยกตามฐานข้อมูลสามารถทำได้หลายรูปแบบ เช่น

1. แยกฐานข้อมูลเฉพาะ (Database per Tenant)

สร้างฐานข้อมูลแยกสำหรับแต่ละ tenant

Tenant A  →  Database A
Tenant B  →  Database B
Tenant C  →  Database C
ข้อดี ข้อเสีย
แยกข้อมูลได้สมบูรณ์ที่สุด ใช้ resources มากที่สุด
ปรับแต่งตาม tenant ได้ง่าย ต้นทุนสูงขึ้นตามจำนวน tenant
Backup/Restore แยกรายได้ การ scale จำนวนมาก ต้องเพิ่ม resource

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

2. แยกด้วย Schema (Shared Database, Separate Schema)
Database เดียว
├── Schema: tenant_a
│     └── table: patients, appointments, ...
├── Schema: tenant_b
│     └── table: patients, appointments, ...
└── Schema: tenant_c
      └── table: patients, appointments, ...
ข้อดี ข้อเสีย
ประหยัด resources กว่าแบบแรก การย้าย tenant ซับซ้อนกว่า
ยังคงมีการแยกที่ชัดเจน ต้องจัดการ schema migration ทุก tenant
ง่ายต่อการ query ข้ามบาง use case  

เหมาะกับ: ระบบที่ต้องการสมดุลระหว่างการแยกข้อมูลและการประหยัดต้นทุน

3. แยกด้วยคอลัมน์ / Sharding (Shared Database, Shared Schema)

ใช้ฐานข้อมูลและตารางเดียวกัน แต่มีคอลัมน์ tenant_id เพื่อระบุว่าข้อมูลแถวนี้เป็นของ tenant ใด

ตาราง patients (ร่วมกัน)
┌────────────┬─────────────┬────────────┐
│ tenant_id  │ patient_id  │ name       │
├────────────┼─────────────┼────────────┤
│ tenant_a   │ 001         │ สมชาย      │
│ tenant_b   │ 001         │ John       │
│ tenant_a   │ 002         │ สมหญิง      │
└────────────┴─────────────┴────────────┘
ข้อดี ข้อเสีย
ประหยัด resources มากที่สุด ความเสี่ยง data leak สูงสุด
ง่ายต่อการพัฒนาและ deploy ประสิทธิภาพอาจลดลงเมื่อข้อมูลมาก
Scale จำนวน tenant ได้ง่าย ต้องระวัง query ทุกครั้ง

Database Sharding เป็นอีกรูปแบบที่ขยายจากแนวคิดนี้ โดยแบ่งข้อมูลตามช่วง tenant_id ออกเป็นหลาย shard เพื่อกระจาย load

เหมาะกับ: SaaS ขนาดใหญ่ที่มี tenant จำนวนมาก และ tenant แต่ละรายมีข้อมูลไม่มาก

สถาปัตยกรรม

โครงสร้่างของ multi-tenancy architecture ลักษณะการออกแแบแสดงตามรูปข้างล่าง เป็นดังนี้

  1. Application - โปรแกรมใช้งาน ทำหน้าที่ติดต่อกับผู้ใช้ตามแต่ละ tenant และเชื่อมไปยังส่วนหลัง middle ware
    การปรับหรือ customize ของแต่ละ tenant จะทำที่ชั้น application นี้ และโปรแกรมออกแบบมาให้ทำงานลักษณะ multi-concurrency
  2. Middleware - ทำหน้าที่เชื่อมกับ application และ mapping เข้ากับ database
  3. Database - ฐานข้อมูลของผู้ใช้งานตามแต่ละ tenant
  4. Virtual machine/container - สำหรับทำหน้าที่ให้โปรแกรมทำงานโดยใช้ resources จากส่วนกลาง ซึ่งสามารถเป็นได้ทั้ง virtual machine หรือ container(เข่น docker หรือ podman) ในหนึ่ง virtual machine หรือ container สามารถทำงานได้หลายๆ tenant ขึ้นอยู่กับ resources ที่ได้กำหนดไว้
  5. Common-resources(hardware, networking, etc) - resources ส่วนกลางที่ผู้ให้บริการ(service provider)จัดหาให้ และส่วน networking เชื่อมต่อไปยังปลายทางที่ต่างๆ

นอกจากนี้การออกแบบ multi-tenancy ยังสามารถสร้าง database กลางเพื่อใช้กับ tenant ต่างๆ ซึ่งเป็นข้อมูลที่ต้องการแบ่งปันการใช้ระหว่าง tenant(เป็นข้อมูลเปิด) เช่น ICD-9(Procedure), ICD-10, ICD-11

multi-tenancy architecture, kksEHR

ประโยชน์

การใช้ multi-tenancy ได้ประโยชน์ดังนี้

  1. การใช้ resources ได้มีประสิทธิภาพ
  2. อัปเดตและบำรุงรักษาง่าย    แก้ไข bug หรือเพิ่ม feature ครั้งเดียว ทุก tenant ได้รับการอัปเดตพร้อมกัน ไม่ต้อง deploy แยกรายลูกค้า
  3. Scale ได้ง่าย    เพิ่ม tenant ใหม่ได้โดยไม่ต้องตั้งค่า infrastructure ใหม่ทั้งหมด เพียงเพิ่ม entry ใน routing และสร้าง database/schema ใหม่
  4. การจัดการทำได้จากศูนย์กลาง    ผู้ดูแลระบบสามารถ monitor, audit, และจัดการ tenant ทั้งหมดได้จากที่เดียว

Tenant Routing

ระบบโปรแกรมคลินิก kksEHR ใช้ Database Tenant Provider ในการเลือก Data Source ให้ถูกต้องตาม tenant ที่ส่ง request เข้ามา โดยตัวอย่าง log จากระบบจริงแสดงให้เห็นว่าในเวลาเดียวกัน (10:47:58.388) มีสอง thread ทำงานพร้อมกัน และแต่ละ thread ถูก route ไปยัง datasource ของ tenant ที่ถูกต้องอย่างอิสระจากกัน:

...10:47:58.388 [http-thread-pool::http-listener-2(1)] DatabaseTenantProvider use dataSource name: tenant2DS
...10:47:58.388 [http-thread-pool::http-listener-2(3)] DatabaseTenantProvider use dataSource name: tenant1DS

สังเกตได้ว่า:
Thread (1) → ถูก route ไปยัง tenant2DS (ฐานข้อมูลของ tenant 2)
Thread (3) → ถูก route ไปยัง tenant1DS (ฐานข้อมูลของ tenant 1)
ทั้งสอง thread ทำงานที่ เวลาเดียวกันทุกมิลลิวินาที แต่ข้อมูลไม่ปะปนกัน

นี่คือหลักฐานว่าระบบสามารถรองรับการใช้งานแบบ concurrent multi-tenant ได้อย่างถูกต้องและปลอดภัย

Tenant Routing คือหัวใจของ Multi-tenancy — มันทำให้ระบบเดียวรองรับผู้เช่าได้หลายราย โดยที่ข้อมูลของแต่ละรายยังคงแยกกันอย่างชัดเจนในทุกสถานการณ์การใช้งาน

สรุป

ในบทความนี้กล่าวถึงระบบโครงสร้างของ multi-tenancy และประโยชน์จากการใช้ โดยโปรแกรมคลินิก kksEHR เป็น Online Cloud-based Application ใช้สถาปัตยกรรมนี้ด้วยเทคโนโลยี Jakarta EE

Data Compliance: ในบางธุรกิจ เช่น การแพทย์หรือการเงิน กฎหมาย PDPA/HIPAA อาจกำหนดให้ต้องแยก database ตามแต่ละผู้เช่า