What is DevOps

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

devops เกิดขึ้นจากปัจจุบันที่แต่ละทีม มีการแข่งขันกันในการสร้าง Innovation และนำ technology ใหม่ๆ มาใช้เพื่อปรับปรุงการทำงาน และสร้าง service ต่างๆ ออกมาให้ตรงใจและพึงพอใจต่อผู้ใช้งาน

Development team มีการใช้ technology container ในการ package application ด้วยการ pack ความต้องการที่ application ต้องใช้ในการทำงานไว้ใน package เดียวทั้งที่เป็น OS, application dependency, lib และ configuration ที่จำเป็น ทำให้ container สามารถทำงานในสภาพแวดล้อมต่างๆ ได้ง่าย และการทำงานได้ผลลัพธ์ไม่แตกต่างๆกัน

ขณะเดียวกัน Operation team ก็ศึกษา Kubernetes เพื่อให้เป็น platform สำหรับ application team สามารถเรียกใช้ผ่าน APIs ในการ deploy และทดสอบ application โดยที่ไม่ต้องเสียเวลาในการขอบริการ Virtual Machine, Network, Storage ทำให้ประหยัดเวลาในการให้บริการกับทีม Developer (Kubernetes = Infra APIs)

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

ดังนั้น DevOps จึงเป็น culture ไม่ใช่ tool หรือ technology

Culture

DevOps เกี่ยวข้องกับการทำลายอุปสรรคระหว่างทีม เวลาที่เสียไประหว่างที่รอเพื่อให้ได้ resource ตามความต้องการ เอกสารและ process ที่ทำให้กระบวนการส่งมอบ software ไม่มีประสิทธิภาพ การที่ทีม Dev และ Operation มีการพูดคุยเพื่อทบทวนกระบวนการ และหา tool ที่สามารถลดขั้นตอน รวมทั้งลดอุปสรรค์ระหว่างการส่งมอบ software ให้น้อยที่สุด จะส่งผลดีโดยรวมต่อระบบ IT

Automation

เพื่อให้บรรลุเป้าหมาย การใช้ระบบอัตโนมัตินอกจากช่วยประหยัดเวลาแล้วยังป้องกันข้อบกพร่อง สร้างความสม่ำเสมอ รวมถึงการส่งเสริมการให้บริการในรูปแบบ self-service ในทีม

Measurement

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

Sharing

กุญแจสำคัญของความสำเร็จของ DevOps ในทุกองค์กรคือการแบ่งปันเครื่องมือ ความรู้ บทเรียนที่ค้นพบ เพื่อให้ทีมได้รับข้อมูลเกี่ยวกับวิธีการใหม่ๆ สร้างสรรค์สิ่งใหม่ๆ สร้างการเรียนรู้ในทีมร่วมกัน

ทุกองค์กร จำเป็นต้องมี DevOps การจะพัฒนา culture นี้ขึ้นมา จะช้าหรือเร็วนั้นขึ้นอยู่กับวัฒนธรรมองค์กรนั้นๆ ว่าเอื้ออำนวยขนาดไหน ไม่ช้าก็เร็วองค์กรก็จะต้องมี DevOps เกิดขึ้น เหมือนถนนที่ใช้เดินทางไปยังกรุงโรม ที่เมื่อออกเดินทาง ปลายทางก็จะเป็นกรุงโรม

Note:

DevOps = Developer + Operation

DevSecOps = Developer + Security + Operation เป็น term ใหม่ ที่ทีม security เข้ามาร่วมด้วยในกระบวนการส่งมอบ software โดยการใช้ทักษะและ tool ที่ทีม security มีมาใช้เป็นส่วนหนึ่งในกระบวนการส่งมอบ โดยการตรวจสอบช่องโหว่ด้านความปลอดภัยตั้งแต่เริ่มต้น develop software (shift-left security)

FinOps = Financial + Operation เป็นอีก term ที่ทีม financial ที่เป็นผู้ support เรื่อง budget ต่างๆ สำหรับทีม operation เพื่อใช้ manage application อยากรู้ข้อมูลเรื่องค่าใช้จ่าย และความสมเหตุสมผลการการลงทุน การมีข้อมูลที่ monitor เรื่อง IT spending อยู่ตลอดเวลาทำให้ทีม Finance สามารถ plan เรื่อง budget และควบคุมค่าใช้จ่ายได้ ขณะเดียวกัน operation team ก็สามารถใช้ข้อมูลนี้ในการ optimize resource ที่ใช้สำหรับ run application ได้เช่นเดียวกัน

Agile Operation

รูปแบบการจัดการทีมงาน เมื่อต้องรองรับการทำงานแบบ agile บางครั้งจะมองว่าเป็นเรื่องของทีม development ที่จริงแล้วต้องมองภาพรวมของทั้ง IT จึงจะสามารถขับเคลื่อนได้อย่างมีประสิทธิภาพ

ด้วยการแบ่ง Roles และสิ่งที่ต้อง focus ในแต่ละ layers ของ IT landscape คือ

Business Capability ต้องมี product team ที่จัดการในลักษณะ cross-functional โดยประกอบด้วย product owner, designer, dev, QA รับผิดชอบในการ develop application ตลอด life cycle เช่น plan, design, develop และ test

Platform ต้องมีผู้ที่มีหน้าที่เป็น application operators รับผิดชอบในการ config, deploy, ตรวจสอบความพร้อมของ application (QA), monitor และ scale app ผู้ที่รับผิดชอบส่วนนี้จะมาจากฝั่งทางด้าน development team ที่มีความรู้ความเข้าใจเกี่ยวกับ application พอสมควรและเข้าใจกระบวนการ CI/CD ที่เกี่ยวข้อง

Site Reliability ต้องมีผู้ที่มีหน้าที่เป็น Platform Operators ที่มีพื้นฐานทางด้าน Midle-ware หรือ Web server เพราะต้อง provide resource ที่ต้องใช้เสำหรับการ run application บริหารเรื่อง high availability, consistency และ resiliency ของ application การทำ capacity planning การ upgrade platform และขยาย platform เพื่อให้รองรับการใช้งานที่มากขึ้น

Infrastructure ต้องมีผู้ที่มีหน้าที่เป็น Engineer ที่ดูแล virtual infrastructure และ equipment ต่างๆ เช่น storage, security, network

แต่ถ้าเราจะมองในมุม functional ของงานและแบ่งแยกย่อยลงไปอีกก็สามารถใช้รูปแบบนี้เป็น model ก็ได้เช่นกัน

และเมื่อ map role กับ functions งานก็จะได้ดังรูป

การจะเลือกรูปแบบใดนั้นขึ้นอยู่กับความซับซ้อน และขนาดของระบบที่แต่ละองค์กรมีความแตกต่างกัน ดังนั้น role ของ IT ในแต่ละองค์กรจึงไม่จำเป็นต้องเหมือนกันทุกองค์กร

Engineering Standard for DevOps

สรุปมาตรฐานในการพัฒนา DevOps ในองค์กร เพื่อเป็นหลักพิจารณาในการเริ่มต้นสร้างวัฒนธรรม (culture) กระบวนการ (process) และเลือก technology ที่เหมาะสม โดยสรุปเป็นหลักการได้ดังนี้

12 Factors

Application ต้องถูกสร้างตามหลักการ 12 Factors ซึ่งเป็นหลักการในการพัฒนา cloud native application ที่สามารถทำงานในสถาพแวดล้อมที่แตกต่างๆ กันได้ง่าย โดยมีหลักการเช่น ไม่เขียน log ลง file โดยให้ผ่าน standard output สร้าง environment ที่มี component, version และ configuration เหมือนกัน (dev, sit, prod) จัดการ configuration แยกจาก application ผ่านทาง environment เป็นต้น

Git Pre-Commit Hooks

ต้องมั่นใจว่ามีการใช้ pre commit hooks ของ GIT เพื่อ validate code ก่อนที่ code จะถูกจัดเก็บใว้ใน repository การทำ hook คือทุกครั้งที่ engineer ทำการ push code ไปยัง source control นั้น code จะถูกตรวจสอบและทำการ test ก่อน เพื่อป้องกัน code ที่ไม่สมบูรณ์​​ (poor quality code) ถูกเขียนลง repository การที่มี process นี้ก่อนกระบวนการ commit จะทำให้มั่นใจได้ว่า code ที่จัดเก็บจะเป็น code ที่มีคุณภาพเสมอ แนะนำตรวจสอบตามรายการดังนี้

  • Linting เป็นการตรวจสอบ code ว่าตรงตาม coding standards หรือไม่ เช่น การตั้งชื่อ function หรือ variable การใช้ space การเขียน comment
  • Unit Tests ทำการ execute test case
  • Commit Message เช่น commit message จะต้องมีอย่างน้อย 80 ตัวอักษร เพื่อเป็นการบังคับให้ engineer สื่อความหมายของ code ที่จะเก็บใน repository ได้จัดเจน
  • Jira มีการ reference ส่วนของ code กับ ticket ใน Jira เพื่อให้สามารถ trace ได้ว่า code ชุดนี้เกี่ยวข้องกับ requirement อะไร

Source Code Management

Source code จะต้องถูกจัดการผ่าน Gitlab หรือ git version control รวมถึง Infra code หรือ technical code อื่นๆ เป็นการจัดการ code ที่เดียวเพื่อความชื่อถือและถูกต้องเสมอสำหรับ development team (one source of truth) โดยมีหลักพิจารณาคือ

  • Trunk Based Development เป็นการให้ engineer ทำงานอยู่บน development branch (main branch) ในระยะเวลาที่สั้น (short iterations) ดีกว่าให้มีหลายๆ release หรือ feature branch เพื่อลดปัญหาเรื่องความซับซ้อนและยากลำบากในการ merge code (merge conflicts)
  • Feature Toggles สำหรับ code ที่ยังใช้งานไม่ได้ หรือพัฒนายังไม่เสร็จจะต้องถูกซ่อนไว้ โดยใช้ feature toggle เพื่อป้องกันหรืออนุญาติให้มีการนำ code ไปใช้
  • Configuration in Environment ไม่เก็บ configuration ต่างๆ ใว้ใน source code เพื่อป้องกันไม่ให้ส่วนที่เป็น credential หรือข้อมูลสำคัญรั่วไหล อีกทั้งยังเป็นการทำให้ code ไม่มี dependency เรื่อง config สามารถจัดการ config ผ่านทาง environment ที่ง่ายกว่าและย้ายไปยัง environment ได้สะดวกด้วย

Continuous Integration and Delivery (CI/CD)

ทุกๆ commit ใน git จะมีการ start CD/CD pipeline เพื่อมั่นใจว่าทุก code จะมีการ run ขั้นตอนต่างๆ ที่เป็นมาตรฐานในการส่งมอบ Application ขององค์กร

  • Validate code standard อย่างเช่น space และ brackets ที่อ่านง่าย
  • Execute test case
  • Code quality metric จะต้องมั่นใจว่า code ผ่านมาตรฐานที่กำหนดไว้ เช่น ไม่มีช่องโหว่ด้านความปลอดภัย (vulnerabilities) จำนวน coverage unit จะต้องมีมากกว่า 80% จำนวน smells bug หรือ code ที่เขียนโดยไม่เป็นไปตาม practices
  • Automate end-to-end functional และ non-functional testing
  • Deploy ไปยัง environment ต่างๆ ด้วยรูปแบบที่เหมาะสมเพื่อไม่ให้กระทบกับการทำงาน เช่น bluegreen, canary

Automated Testing

ทำการ automate test ในทุกระดับทั้งที่เป็น functional และ non-functional โดยเลือกใช้ tool ที่เหมาะสมในแต่ละ test case การใช้ automate test tool จะทำให้เห็นปัญหาก่อน User ประกอบด้วย

  • Unit เป็นการทดสอบส่วนไดๆ ใน code โดยต้องมี coverage ในการ test ที่เหมาะสม
  • Integration เป็นการทำ end to end test ประกอบด้วยการทำ API test และ UI test เพื่อ simulate การใช้งานของ User
  • Security ประกอบด้วย static และ dynamic security testing เป็น simulate การโจมตี application เพื่อหาช่องโหว่ด้านความปลอดภัย (vulnerabilities)
  • Performance เป็นการ load test เพื่อให้มั่นใจว่า application สามารถทำงานได้ในภาวะการณ์ต่างๆ ได้ ทั้งกรณีที่มี request และมีการส่ง data (payload) เข้ามามากกว่าปกติ

Security Testing

Web app และ Mobile application จำเป็นต้องมีการตรวจสอบความปลอดภัยมากกว่าเดิม จากการเข้าถึงของผู้ใช้งานได้ทั่วไป ดังนั้นโดยทั่วไปจึงมีการทำ hardening และ end-to-end penetration test จากหน่วยงานภายนอกก่อนที่จะขึ้น production การทำ security testing สามารถทำได้หลายวิธี โดยการทำให้เป็นส่วนหนึ่งของ agile process และ devops

  • Dynamic Application Security Testing (DAST) และ Static Application Security Testing (SAST) เป็นเครื่องมือและวิธีการที่อยู่ในกระบวนการ Continuous Integration pipeline เพื่อให้มั่นใจว่าทุกขั้นตอนในการบวนการ code change build และ release จะมีการตรวจสอบ security อยู่เสมอ (shift-left security)
  • สำหรับการตรวจสอบจากองค์กรภายนอก (Third-Party Penetration) สามารถทำในบางจุดที่สำคัญเพื่อให้มีความคล่องตัว ลดเวลาและค่าใช้จ่ายในการตรวจสอบความปลอดภัยของ application ได้ โดยที่ไม่เป็นการเพิ่มความเสี่ยง

Dynamic App Security Testing – DAST

สามารถใช้ OWASP ZAP เพื่อ scan application ที่ทำงานอยู่ได้ (black box testing) โดยจะทดสอบความปลอดภัยด้วย test case พื้นฐานสำหรับ web application ที่เป็นมาตรฐานคือ OWASP Top 10 Vulnerabilities

ZAP สามารถเป็นขั้นตอนหนึ่งใน Continuous Integration Pipeline เพื่อให้ scan โดยอัตโนมัติเมื่อ code change, build และ release รวมถึงรายงานช่องโหว่ด้านความปลอดภัย (vulnerabilities) ให้กับทีม developer ทราบทันที ป้องกันไม่ให้ release application ที่ไม่ปลอดภัยไปยัง production

Static App Security Testing – SAST

ใช้ SonarQube เพื่อวิเคราะห์ source code และตรวจจับ code ที่อาจจะเป็นช่องโหว่ด้านความปลอดภัยของ application โดยให้ SonarQube เป็นส่วนหนึ่งของ Continuous Integration Pipeline จะทำให้มีความมั่นใจ และป้องกัน application ที่ไม่ปลอดภัยถูกใช้บน production

Independent App Penetration Testing

กระบวนการพัฒนา software ในแบบ waterfall project ส่วนใหญ่จะใช้ องค์กรอิสระที่เชื่อถือได้เพื่อตรวจสอบช่องโหว่ด้านความปลอดภัยของ software ก่อนขึ้น production ซึ่งส่งผลกระทบกับ cost ระยะเวลา และความถี่ในการ release software ทางเลือกที่เหมาะสมที่สามารถเข้าได้กับกระบวนการ agile และ devops คือรวมวิธีการของ DAST และ SAST เข้ามาใน process ก็จะทำให้ลดจำนวนที่ต้องใช้องค์การภายนอกได้ โดยมีหลักการพิจารณาคือ

  • Schedule appropriately กำหนดกรอบระยะเวลาที่ชัดเจนในการทำ penetration test หลังจากที่ทุก function มีการ implement เรียบร้อย
  • Lead time กำหนดให้ penetration test ทำในรอบ sprint ทำให้สามารถแก้ไขควบคู่กับการทดสอบ เพื่อไม่ให้ส่งผลกระทบกับการ release application
  • Cost สำหรับการทำ penetration test จะลดลงเมื่อมีการทำ penetration test แค่ครั้งเดียวก่อนที่จะ release application โดยที่ไม่พบช่องโหว่ด้านความปลอดภัย

OWASP Dependency-Check

เป็นการทำ Software composition analysis ด้วยการตรวจสอบข้อมูลของ File (file name, POM files, ZIP files, native libraries, .NET assemblies, package name ..) แล้วตรวจสอบกับฐานข้อมูล National Vulnerability Database – NVD เพื่อแจ้งเตือนถึงความเสี่ยงในการใช้งาน package หรือ library ใน source code ปัจจุบัน OWASP Dependency-Check สามารถใช้ร่วมกับหลายๆ tool เช่น

  • Ant Task
  • Command line tool – Windows, *nix
  • Gradle plugin
  • Jenkins plugin
  • Maven plugin

Semantic Versioning

ใช้ Semantic versioning เพื่อจัดการ version ของ release สำหรับหลาย ๆ microservice และ application โดยการ tag version number ที่ release branch ที่สร้างใน git repository

version ของ release ใช้หลักการที่ง่ายเพื่อให้ผู้ใช้ microservice หรือ application เข้าใจ change ที่เกิดขึ้น รวมถึงทีม tester การจัดการ version สามารถใช้หลักการดังต่อไปนี้

  • Major เป็นการเปลี่ยนแปลงที่สำคัญ หรือส่งผลกระทบต่อภายนอกเช่นการเปลี่ยนการเรียกใช้ API หรือ Interface
  • Minor การแก้ไขเพิ่มเติม function ที่มีอยู่แล้ว หรือเพิ่มความสามารถของ function เดิมให้สมบูรณ์และดียึ่งขึ้น
  • Patch เป็นการแก้ข้อผิดพลาดของ code (bug)
  • Chore เป็นการเปลี่ยนแปลงไดๆ ที่ไม่จำเป็นต้องเปลี่ยน version เช่นการทำ code refactoring

ข้อมูลเพิ่มเติมเกี่ยวกับ semantic version ได้จาก https://semver.org

Application & Platform Monitoring

Application ที่ทำงานบน environment มีการตรวจสอบสถานะการทำงานของ application และ platform และแจ้งเตือนเมื่อมีปัญหาไดๆ เกิดขึ้นแบบ realtime ด้วยการเก็บข้อมูลในรูปแบบ matrics อาจจะใช้ Prometheus และแสดงผลใน grafana dashboard เพื่อให้ทีมสามารถเห็นการทำงานของ application ที่เป็นปัจจุบันและสถิติที่ผ่านมาได้ ขอมูลจำเป็นที่ต้องจัดเก็บเช่น

  • Uptime/Downtime
  • CPU memory utilization
  • Failed network request 4xx 5xx response
  • Latency slow running request
  • Request Frequency (DDoS Protection)
  • Error message logged by application
  • Disk space usage

Collaboration

ช่องทางการติดต่อสือสารในทีม ทั้งที่เป็น internal และ external เป็นสิ่งสำคัญ และต้องใช้ tool ที่เหมาะสม เช่น

  • Slack ทีมสามารถ share ข้อมูลเกี่ยวกับ project พวก knowledge ต่างๆ ระหว่างทีม และสามารถใช้แจ้ง alert ได้กรณีที่ pipeline มีปัญหา อีกทั้งยัง invite business หรือ stakeholder เข้ามาในทีมด้วยเพื่อการรับรู้ข่าวสารต่างๆ ภายในทีม
  • Jira เป็น tool ที่ใช้ในการจัดการ product backlogs จัดการ sprint รวมถึง report ต่างๆ เพื่อให้ทีมเห็นถึง progress ในแต่ละงานได้

Cloud Platform

การทำ devops ให้สะดวกราบรื่นจำเป็นต้องมี platform ที่ช่วยอำนวยสะดวกในการ release, deploy, run และ manage application ได้ง่าย ปัจจุบันจะใช้ container technology ในการ packaging software และ run บน kubernetes environment เพราะสะดวกในการใช้งานเพราะการใช้งานจะผ่าน APIs ไม่มี manual process โดยใช้ Cloud Environment เป็น infrastructure เพื่อให้ platform สามารถ scale ได้ง่าย และ cloud environment ยังช่วยในเรื่องการจัดการ high availability , consistency และ resilent ของ application ได้ง่ายอีกด้วย

App Modernization Approach – Swift Process

หลักการในการพัฒนา modern app นั้นมีค่อนข้างหลากหลาย และถูกใช้ในแบบที่แตกต่างกันในแต่ละที่ แต่ละสภาพแวดล้อมของ App และทีม Development ส่วนตัวชอบ process การออกแบบโดยใช้ Swift เพราะเป็นวิธีการที่ prove แล้วว่าใช้ได้จริงในองค์กรใหญ่ๆ โดยใช้ concept DDD และมีขั้นตอนคร่าวๆ ดังนี้

  1. กำหนด OKR เพื่อให้ทีมเข้าใจในทิศทางเดียวกันว่ากำลังจะทำอะไร เพื่ออะไร แล้วจะวัดผลด้วยอะไร
  2. ทำ session Event Storming เป็นการร่วมกัน explore ว่าในเรื่องที่ทำนั้น (context) มีเหตุการณ์ (event) อะไรบ้างเรียงตามเวลาที่เกิดขึ้น session นี้จะทำให้ทั้งทีมเข้าใจในสิ่งที่จะ build ขึ้นมาว่ามีกระบวนการทำงานยังไง
  3. เลือกตัดส่วนที่เข้าใจชัดเจนที่สุด หรือมี impact มากสุดมาทำก่อน
  4. สร้าง diagram เพื่ออธิบาย architect ของแต่ละ module ที่อยู่ใน system (BORIS) ว่ามีความสัมพันธ์กันยังไง มีการแลกเปลี่ยนข้อมูล หรือให้บริการอะไรบ้าง รวมทั้งระบบภายนอกที่เกี่ยวข้อง (external system)
  5. ลงรายละเอียดเบื้องต้นของแต่ละ service (SNAP) เช่น APIs, Data, PUB/SUB, External System, User stories, UI และ Risk แล้วใช้ Project Management tools (Jira) เพื่อขยายรายละเอียดพร้อมสำหรับการนำไป Implement และเข้าสู่กระบวนการ agile
  6. พัฒนา Code
  7. Document กระบวนการ วิธีการพัฒนา ปัญหา วิธีการแก้ไข เพื่อให้ครั้งแต่ไปสามารถนำไปใช้ได้และ ไม่ต้อง research อีกครั้ง อีกทั้งช่วยทำให้คนใหม่ที่เข้ามาในทีมสามารถเรียนรู้ และ follow สิ่งที่ทำผ่านมาแล้วได้

สรุปรูปแบบข้างต้นจากบนลงล่าง

Enterprise Architecture Map

ในการออกแบบ IT system ของแต่ละองค์กรต่างมีแบบแผนที่ยึดหลักมาตรฐานต่างๆ เช่น TOGAF หรือไม่ก็ eTOM แต่วิธีการพวกนี้อาจจะเข้าใจยากและใช้เวลามาก เพื่อที่จะได้ landscape ของทั้ง IT ในมุมของการ invest และจัด priority วิธีที่ง่ายที่สุดในการสร้าง IT Enterprise Architecture คือการมองเรื่อง capability และ impact ที่ได้ต่อ business เมื่อมีการ invest และสามารถเห็นภาพรวมในสิ่งที่มีแล้วและสิ่งที่ขาด diagram นี้เป็น diagram หนึ่งที่ช่วยทำให้เราเข้าใจภาพรวมของระบบ IT ได้ง่ายขึ้น

จาก diagram นี้ถือเป็น diagram เริ่มต้น โดยเราต้องใส่ platform ที่เราใช้อยู่ปัจจุบันเข้าไปเช่น Container บน cloud ถ้าใช้ AKS ก็ระบุเข้าไปในกล่อง หรือมี service มากกว่านี้ที่ใช้บน cloud ก็สามารถเพิ่มกล่องเข้าไปได้ หลังจากทำเสร็จแล้วเราจะรู้ว่าปัจจุบันระบบ IT มีอะไรในส่วนไหนบ้าง แล้วยังขาดอะไรที่ต้องเติมเต็ม และสามารถใช้เป็นแผนงานสำหรับในแต่ละปีได้

DDD in Action

หลังจากที่ได้เรียนรู้ Domain Driven Design (DDD) แล้ว ลองเอา concept ของ DDD มาใช้เพื่อออกแบบ Software Architect โดยใช้หลักการของ Swift Method ซึ่งเป็น framework สำหรับการพัฒนา Modernization Software

เริ่มจากสิ่งที่เราเข้าใจ และอธิบายความหมายของคำว่า Item อย่างไร

Item สำหรับแต่ละคนมีความหมายที่แตกต่างกัน แล้วแต่ประสบการณ์และมุมมอง

Item เมื่อไปอยู่ในแต่ละ context ที่แตกต่างกัน ก็จะมีลักษณะไม่เหมือนกัน หรือเป็นคนละอย่างกันเลย เช่น Item ที่อยู่ใน Cart ก็อาจจะเป็นสินค้า แต่ Item ที่อยู่ใน Order ก็จะหมายถึงคำสั่งซื้อ โดยที่อาจจะมีข้อมูลและลักษณะใช้แทนกันไม่ได้เลยทีเดียว ดังนั้นการออกแบบ Software ที่หลายๆ Application ใช้ share data model เดียวกันจึงเป็นการออกแบบที่ไม่เหมาะสม เพราะจะมีปัญหาเรื่องของการ scale หรือแก้ไขเพิ่มเติม จะส่งผลกระทบกับหลายๆ Application ในภายหลัง

สิ่งสำคัญต่อมาคือการพัฒนาการสื่อสารที่เป็น common language ระหว่าง Business และ IT เพราะปัญหาของนักพัฒนา Application ส่วนใหญ่จะเป็นเรื่องของความเข้าใจที่คลาดเคลื่อน (misaligned) จากผู้ที่เป็น Business หรือเจ้าของ Project (Domain Experts) เพราะคนกลุ่มนี้จะไม่ค่อยเข้าใจเรื่อง IT ดังนั้น Software Developer จะต้องใช้ภาษาที่ Business เข้าใจง่าย รวมถึงการออกแบบจะต้องใช้รูปแบบที่แสดงให้เห็นถึงสิ่งที่เกิดขึ้นในชีวิตจริง จึงจะสามารถพัฒนา Code ตาม Business Concept ได้อย่างถูกต้อง

ซึ่งก็คือการใช้ ubiquitous language หรือที่เรียกว่าการใช้ภาษาเดียวกันภายใน bounded context ที่ทีมได้ร่วมกันพัฒนาอยู่

นอกจากนี้ยังต้องพิจารณาเรื่องของ integration ระหว่าง context อื่นๆ ที่ต้องมีรูปแบบการสื่อสารและความสำพันธ์ขึ้นอยู่กับ context นั้นๆ

และกรณีที่ต้องมีการแปลงการสื่อสารเพื่อให้สื่อสารได้ตรงกัน ก็จำเป็นต้องมี Anti-Corruption Layer ACL เข้ามาร่วมด้วย เช่นการสื่อสารระหว่าง 2 ทีม ที่เป็น upstream และ downstream โดยที่ downstream มีส่วนของ ACL เพื่อให้การสื่อสารสามารถเข้ากันได้ เป็นต้น

บางกรณีอาจจะพิจารณาใช้ Aggregates เพื่อให้ข้อมูลถูกนำไปใช้ได้เลย

อาจจะมองเป็นลักษณะของ transaction ที่ข้อมูลประกอบด้วยหลายๆ business entity เช่น Policy, Order, Customer, Account ที่ถูก Aggregates ไว้ด้วยกัน ซึ่งแสดงความสัมพันธ์เป็นลำดับชั้นของกราฟที่มี Root entity และ entity อื่นๆ รวมถึง value object

ตัวอย่างของ Aggregate ของ Item

Item เป็น transaction ที่ประกอบด้วยหลาย entity ภายใต้ขอบเขตเดียวกัน (consistency boundary) สามารถมีได้มากกว่าหนึ่ง entity และ value object โดยมีการ reference ผ่าน ID (ไม่ใช่ reference object) ดังนั้นเมื่อมีการเปลี่ยนแปลงใดๆ กับ Item ก็จะทำให้ผู้ที่เรียกใช้ Item นี้เห็นการเปลี่ยนแปลงนี้ด้วยเช่นกัน (eventually consistent)

Domain Events เป็นเหตุการณ์ที่เกิดขึ้นใน Business เนื่องจากเป็นเหตุการณ์ที่เกิดขึ้นแล้ว จึงนิยมใช้ในรูปแบบ Past Tense การเขียนจะต้องใช้ภาษาที่เข้าใจง่ายทั้ง dev และ domain expert โดยชนิดของ event มีทั้งที่เป็น การแจ้งเตือน (Notification) และ การเปลี่ยนสถานะ (State transfer)

Command ใช้เพื่อระบุว่าเกิดการ request หรือ trigger เพื่อให้เกิดเหตุการณ์ใดๆ ขึ้นใน Business

เมื่อนำ item, domain event และ command เพื่อแสดงสิ่งที่เกิดขึ้นใน domain มารวมกันจะทำให้ทั้ง business expert และ developer เข้าใจตรงกัน สื่อสารกันได้ง่ายและถูกต้อง

Event Storming

ในการออกแบบ software ควรต้องเริ่มต้นจาก events ที่เกิดขึ้นในแต่ละ business โดย event เองเป็น common language ที่ทั้ง business และ IT สามารถสื่อสารและเข้าใจกันได้ง่าย

ข้อดีของการทำ Event Storming

  • ทำให้ Business และ IT เข้าใจในทิศทางเดียวกัน
  • เป็นวิธีที่มีประสิทธิภาพในการทำงานกับ Business
  • ทำให้เข้าใจรายละเอียดของ Domain และ Sub Domain
  • พูดคุย แลกเปลี่ยนความคิดเห็น
  • วิธีการที่เร็ว ทำให้เห็นปัญหา แก้ไข และปรับปรุงให้ดีขึ้น
  • สามารถมองเห็นว่าควรจะทำอะไรก่อนหลัง (priority) และการ deliver
  • สามารถมองเห็นปัญหาได้แต่เนินๆ
  • ตัดสินใจเริ่มทำสิ่งใดสิ่งหนึ่งได้ง่าย

ในการทำ session Event Storming จำเป็นต้องจัดสถานที่ที่เหมาะสม เพื่อให้ business และ IT ได้ทำกิจกรรมด้วยกัน โดยมีกระดาน (board) ที่มีเนื้อที่ขนาดใหญ่ และ sticky note สำหรับแต่ละคนใช้เพื่อเขียน event ลงใน sticky note เพื่อแปะบนกระดาน (board) มีการอธิบายรูปแบบของสีที่ใช้ ว่าสื่อความความหมายถึงอะไร

ในการแปะ event ลงใน board จะต้องเรียงตามลำดับเวลาจากสิ่งที่เกิดขึ้นก่อน แล้วตามด้วยสิ่งที่เกิดขึ้นภายหลัง

ตัวอย่างการแปะ event โดยแบ่งตามสี ถ้าสีส้มคือ event ส่วนสี ชมพู หมายถึง note และแปะตามเวลาก่อนหลัง

ทั้งนี้อาจจะมีสีอื่นๆ เพื่ออธิบาย event ที่เกิดขึ้นได้ชัดเจน เช่น

ตัวอย่างการแปะ event เพื่อแสดง aggregate และ command ด้วย

Value Stream Scenario

ตัวอย่างของการใช้ Event Storming สำหรับระบบ E-Commerce ที่ลูกค้าสามารถเลือกสินค้าเข้าไปยังตะกร้า (cart) ทำการสั่งซื้อ (checkout) มีการส่ง order ไปยังระบบส่งของไปยังที่อยู่ปลายทาง (Shippping)

ลำดับเหตุการณ์ของระบบ purchase แบะ fulfillment จากการทำ Event Storming

จากลำดับเหตุการณ์ทำการ Grouping ให้ event ประเภทเดียวกันอยู่ด้วยกันเพื่อให้เข้าใจง่ายขึ้น และแปะชื่อกลุ่ม รวมถึง note ถ้ามี

แต่ละ group คือ sub domain ใน DDD ที่เคยเรียนมา ทำการแปะเพิ่มเติมในแต่ละกลุ่ม เพื่อให้ event มีความสมบูรณ์มากขึ้น โดยใช้สีแทนความหมาย (DDD – Tactical design)

หลังจากนั้นนำแต่ sub domain มาสร้างเป็นความสัมพันธ์ว่าในแต่ context นั้นมีการเรียกใช้ data หรือบริการอะไรจาก context อื่น เรียกแบบ Sync call หรือ Async event ด้วยวิธีการนี้จะทำให้เราเห็นภาพรวมของระบบ รวมถึงปัญหาที่อาจจะเกิดขึ้นจากการ integration ข้อมูลที่จำเป็นที่จำเป็นจะต้องรู้จากระบบภายนอก (external sytem) เป็นต้น

ตัวอย่างข้างต้นคือการทำ BORIS ซึ่งเป็นกระบวนการหนึ่งใน Swift Method

ขั้นตอนสุดท้ายคือการลงรายละเอียดของ APIs, Data, Pub/Sub, External System/UI, Agile Stories และ Risk เพื่อให้เข้าใจว่าในแต่ sub domain มีกระบวนการ ขั้นตอนการทำงานที่เป็น specification คร่าวๆ เพื่อนำไปเข้าระบบ project management tool (Jira) และทีม developer ก็สามารถจะเริ่มทำการ develop software ได้ตาม sprint หรือ agile process

ขั้นตอนนี้เรียกว่า SNAP ในกระบวนการของ Swift Method

ภาพรวมของทุก sub domain

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

และการมี diagram ที่ติดไว้ใน board จะทำให้ทีมที่เกี่ยวข้อง เข้าใจในส่ิงที่กำลัง develop และไม่เสียเวลามากนักในขั้นตอน document

Cloud Native Design – 12 Factors

หลักการพิจารณาเพื่อให้การออกแบบ Application สามารถทำงานบน Cloud Environment ได้อย่างราบรื่น และใช้ความสามารถของ Cloud ใด้อย่างมีประสิทธิภาพ ประกอบด้วย 12 ข้อดังนี้

  1. Codebase ใช้ code base เดียว เพื่อ track ในแต่ละ revision control และ deploy ไปยังแต่ละ environment ต่าง

2. Dependencies ระบุความต้องการ lib และ dependencies อื่นๆ ใน project และไม่ share

3. Configuration เก็บ configuration ของ application ใน environment ของระบบ แยกจาก code

4. Backing services สร้าง resource adapter ไปยัง external service อื่นๆ โดยมองว่าเป็นหนึ่ง resource ที่ application เรียกใช้งาน ทำให้การสลับแต่ล่ะ resource ทำได้ด้วยการ attach resource ใหม่ โดยไม่กระทบกับ code

5. Build, release, run แยกขั้นตอน build และ run จากกัน ทำให้ build ครั้งเดียวสามารถ deploy ไปยังหลายๆ ที่

6. Processes ต้อง run app ในรูปแบบ stateless process กรณีที่ต้องมีการจัดเก็บ state การทำงานสามารถเก็บไว้ใน cache โดยใช้หลักการ Backing Services

7. Port Binding ต้อง expose service ออกมาในรูป service port ให้ภายนอกเรียกใช้

8. Concurrency สามารถรอบรับปริมาณงานด้วยการเพิ่มจำนวน process

9. Disposability กระบวนการ start/stop service ต้องทำได้ด้วยความรวดเร็ว โดยไม่ต้องการ manual process หรือ script

10. Dev/Prod Parity สร้าง environment dev และ prod โดยใช้ config และ components version เดียวกัน

11. Logs ใช้ระบบเพื่อจัดการ application log ไม่เป็นส่วนหนึ่งของ application

12. Admin Processes แยก process สำหรับงาน admin และจัดการอื่นๆ

Ref:

the twelve-factor app

Domain Driven Design (DDD)

เป็นรูปแบบการออกแบบ Software System ที่แก้ปัญหาความซับซ้อน (complexity) โดยเทียบเคียงกับหน่วยงานหรือองค์กรที่การดำเนินงานธุรกิจ ที่มีความถนัดในเรื่องใดเรื่องหนึ่งเฉพาะ (expert domain) การใช้วิธีการนี้เป็นการนำไปสู่การออกแบบ microservice application ได้อย่างดีรวมถึงเป็นการสื่อสาร สร้างความเข้าใจกับทีม Business อย่างมีประสิทธิภาพ (Business first approach)

Domain Driven design แบ่งออกเป็น 2 ส่วนคือ Strategic design และ Tractical Design โดยที่ Strategic Design เป็นการออกแบบเชิงกลยุทธ์ เน้นถึงสิ่งที่สำคัญเชิงกลยุทธ์ต่อธุรกิจ โดยแบ่งตามความสำคัญและผสมผสานตามความจำเป็น

Strategic Domain Driven Design ประกอบด้วย

  • Domain
  • Sub-Domain
  • Bounded Context
  • Ubiquitous Language
  • Context Map

Tactical Domain Driven Design เป็นวิธีปฏิบัตที่จะทำให้บรรลุเป้าหมายตามกลยุทธ์ ส่วนนี้จะลงลึกถึงขั้นตอนในเชิงปฏิบัติ

ประกอบด้วย

  • Entities
  • Value Objects
  • Aggregates
  • Services
  • Modules
  • Factories
  • Repositories

Domains ประกอบด้วย sub-domains และ bounded context

Core Domain คือส่วนของธุรกิจหลัก ซึ่งเป็นสิ่งที่มีคุณค่าและโดดเด่นกว่าคู่แข่ง ไม่ต้องการแชร์หรือให้ใครก็ตามใช้โมเดลหลักนี้ รวมถึงการทำให้โมเดลนี้ไปติดกับ framework ใดๆ (Hibernate Entities) โดยจะมีการพัฒนาในส่วนนี้เองทั้งหมด

Supporting Domain เป็น domain ที่ช่วยทำให้ธุรกิจสามารดำเนินการได้โดยปกติ ตัวอย่างเช่น ในการอนุมัติสินเชื้อ เราต้องการข้อมูลเครดิตบูโรร่วมด้วยในการพิจารณา ทั้งนี้ควรพิจารณาเครื่องมือที่มีอยู่แล้วเพื่อเป็นส่วนเสริมให้กับธุรกิจหลัก หรือนำจากแหล่งอื่นๆ มาใช้ หรือไม่ก็พิจารณาสร้างเท่าที่เห็นว่าจำเป็น

Generic Domain เป็นสิ่งที่มีทั่วไป หรือกระบวนการธุรกิจทั่วไป ที่เราไม่ควรสร้างขึ้นมาใหม่ เช่น SMTP server สำหรับส่ง email หรือ cloud platform สำหรับ run application ควรพิจารณาลงทุนในส่วน core domain เป็นหลัก

Bounded Contexts

  • เป็นขอบเขตบริบทเชิงความหมาย ซึ่งเมื่อพูดถึงสิ่งไดสิ่งหนึ่งแล้วคนฟังจะเข้าใจทันทีว่าเป็นเรืองอะไร
  • เมื่อเป็นคนละเรื่อง สามารถมองได้ว่าจะต้องใช้ software package แยกกัน
  • ในแต่ละ Bounded Context จะมี components อยู่ข้างในที่มีความหมายและทำงานเฉพาะตัว
  • มีการพัฒนาเพื่อให้องค์กรมีความแตกต่างและแข่งขันกับองค์กรภายนอกอื่นๆ
  • ต้องมีหลักในการพิจารณาว่าอะไรควรหรือไม่ควรจะเป็นส่วนหลักของ core domain

ยกตัวอย่างทีม Developer ที่ทำงานกับเรื่องไดเรื่องหนึ่ง เช่น Bounded Context A

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

ทำไม Bounded context จึงสำคัญ ถ้าเราพิจารณาเรื่อง Account ในความหมายของ Account สำหรับ Banking ก็จะหมายถึงบัญชีธนาคาร ยอดเงินฝาก ดอกเบี้ย แต่ถ้าในมุมมอง Security จะหมายถึง User Login สิทธิการเข้าถึง service ต่างๆ ดังนี้การมีหลายทีมที่ทำเรื่องเดียวกัน สิ่งเดียวกันแต่อาจจะเป็นคนละอย่างกันได้

Ubiquitous Language

เป็นพัฒนาภาษาที่คุยทั่วไปภายในทีม เช่นคำย่อ เพื่อให้การสื่อสารได้ด้วยความรวดเร็ว และเข้าใจตรงกัน ซึ่งมีทั้งที่เชิงเทคนิค และในเชิงธุรกิจ ของบริบทและในขอบเขตของเรื่องนั้นๆ (Bounded context) แต่ต้องระวังเมื่อนำไปคุยสื่อสารในกลุ่มอื่นๆ เพราะอาจจะเกิดความไม่เข้าใจได้

Context Maps

เป็นภาพรวมความสัมพันธ์ของธุรกิจระหว่าง bounded contexts ต่างๆ ในองค์กร (domain) ซึ่งเป็นส่วนสำคัญ ทำให้ทราบการเชื่อมโยงและวิธีการจัดการในแต่ละ contexts อย่างเช่น Banking ที่เชื่อมโยงไปในหลาย context ตามรูป

Context mappings ประกอบด้วย

  • Partnership
  • Shared kernel
  • Customer-Supplier
  • Conformist
  • Anti-corruption layer
  • Open host service
  • Published language
  • Big ball of mud
  • Separate ways

Context Mapping – Partnership

เป็นความสัมพันธ์ที่มีการร่วมือ และยอมรับอย่างเติมที่ contexts ทั้งสองขึ้นอยู่กับกันและกัน สามารถสื่อสารอย่างเปิดเผย เป็นกรณี success หรือ fail ไปด้วยกัน

Context Mapping – Shared Kernel

เป็นความสัมพันธ์ที่ทั้งสองทีมแบ่งส่วนใดส่วนหนึ่งเพื่อใช้ร่วมกัน ส่งผลให้เกิดการแยกส่วนร่วมนี้เป็นก้อนใหม่ (artifact) เพื่อการ deliver

Context Mapping – Customer-Supplier

เงื่อนไขความสำเร็จของ Supplier บางส่วนขึ้นอยู่กับความสำเร็จของ Customer เช่นระบบกู้ยืมจำเป็นต้องได้ข้อมูลทางด้านการเงินเพื่อพิจารณา

Context Mapping – Conformist

เป็นความคล้อยตาม (conform) ที่โมเดล upstream มีทุกอย่างที่ downstream ต้องการ โดยที่ upstream ไม่ได้สนใจ downstream

Context Mapping – Anti-Corruption Layer

เป็นลักษณะที่ context ไม่สามารถปฏิบัติตามได้ จึงต้องมีส่วนสำหรับการแปลงการสื่อสารภายใน

Context Mapping – Open Host Service

เป็นการกำหนด protocal ในการสื่อสารไว้เพื่อให้ context อื่นสามารถใช้ integrate เข้ามาได้

Context Mapping – Published Language

เป็นการกำหนดภาษากลางไว้สำหรับการติดต่อ เช่น JSON, YAML, XML

Context Mapping – Big Ball of Mud

เป็นอีกประเภทของความสัมพันธ์แบบ ACL ที่ Bounded Context ได้ให้ส่วนของ model ต่างๆ มาใช้ มักจะพบเมื่อต้อง integrate กับระบบเก่ามากๆ (Lagacy)

Context Mapping – Separate ways

เป็นการยกเลิกความสัมพันธ์ที่มีอยู่ และสร้างขึ้นมาใหม่ใน context ทั้งนี้อาจจะง่ายกว่าที่ต้องใช้ความสัมพันธ์ในแบบเดิม

Tactical Design

เป็น design ที่มี scope ใน context ประกอบด้วยหลายส่วนดังนี้

  • Entity ส่วนใดๆ (things) ใน model ที่มีความจำเพาะ (unique identity)
  • Value Object ใช้ในการให้ความหมาย และจำนวนของ Entity เช่น สี และ จำนวน โดยจะไม่มีการเปลี่ยนรูป
  • Aggregates เป็นการรวมหรือเชื่อมข้อมูล เช่น Entity และ Value Object
  • Services การทำงาน หรือ Function
  • Factories สำหรับสร้างส่วนเสริมต่างๆ หรือส่วนสนับสนุน
    • Repositories ตัวแทนสำหรับการ access data ทำให้ model และ data แยกจากกันได้ ทั้งยังเป็นถังสำหรับ Entity และ Aggregates
    • Modules เป็นการ grouping ของสิ่งต่างๆ ใน Bounded context ที่อาจจะมีหลาย module โดยไม่สัมพันธ์กัน
    • Event เป็นตัวแทนของการเปลี่ยนแปลงใดๆ ใน domain จากสถานะหนึ่งไปเป็นอีกสถานะหนึ่ง ปกติเขียนในรูป Noun + past-tense verb เช่น ClaimCreated, ClaimSettled เป็นต้น

The Monolith

ลักษณะของ software architecture ที่รวมทุก modules ไว้ใน project หรือ package เดียว เพื่อความง่ายในการเรียกใช้ function หรือ service ใน project โดยไม่ต้องแยก deploy ที่ต้องเรียกใช้งานผ่าน interface อย่างเช่น API อีกทั้งการส่งมอบงาน และ deploy ก็ง่ายเพราะ deploy ทั้ง package และการ reuse ในส่วนของ code ก็ทำได้สะดวกสบาย ถือเป็นหลักนิยมของการพัฒนา software ในยุคที่ผ่านมา จนกระทั้ง software ได้ถูกนำมาใช้เป็นบริการหลักของธุรกิจ ความต้องการใหม่ๆ ที่เพิ่มและแก้ไขตลอดเวลา รวมถึงการรองรับจำนวนผู้ใช้จำนวนมาก ทำให้รูปแบบการพัฒนาแบบเดิมเริ่มจะส่งผลในทางลบมากกว่า กล่าวคือ การเพิ่มทีมพัฒนาเข้าไปจะทำได้ยาก เพราะการวาง code ภาษาที่ใช้ จะรู้จักดีในเฉพาะทีมเท่านั้น แต่ละ module ที่มีการเรียกใช้งานเริ่มมีความซับซ้อน และต้อง share หรือรับงานที่มากขึ้น (overloaded) ความต้องการเพิ่มจำนวน process (scalability) ที่ต้องขยาย resource ทั้ง server การที่ทำให้ระบบทำงานได้อย่างต่อเนื่อง (availability) ด้วยประสิทธิภาพของการให้บริการที่ดีตลอดเวลา (reliability) รวมถึงการให้บริการได้แม้ในขณะที่ระบบเกิดปัญหา (Resiliency) การส่งมอบ software อย่างต่อเนื่อง (Continuous Delivery) โดยไม่ทำให้การบริการหยุดชะงัก ทำให้เกิดอัตราเร่งให้ต้องเปลี่ยนแปลงไปสู่ microservice architect

Forces

  • Developer หลายคนทำงานใน project เดียว
  • Developer ใหม่ของทีมสามารถเริ่มต้นทำงานได้อย่างรวดเร็ว
  • Application จะต้องง่ายในการทำความเข้าใจ และแก้ไข
  • ต้องการ apply continuous deployment practices
  • ความต้องการเรื่อง Scale up – Scalability, Availability และ Resiliency
  • ต้องการใช้ประโยชน์จาก technology ใหม่ใน project เช่น framework และ programming language

Solutions

  • สร้างหลายๆ module แล้ว pack ไว้ใน package เดียว เช่น WAR หรือ EAR
    • Deploy ทุกอย่างอยู่ในรูปแบบของ directory เดียว
    • อาจจะแยกหน้าที่ออกเป็นหลายๆ Tier (N-Tier Architechy)
    • ออกแบบเป็นลักษณะลำดับชั้น (Layered Architecture)

Resulting Context

  • การพัฒนา application มีรูปแบบที่ซับซ้อน (Complexity)
  • Web Server ทำงานหนัก ด้วยการทำงานทุกอย่างใน Server เดียว
  • การ deploy ส่ิงใหม่ๆ (continuous deliver) จะทำยากเพราะเกี่ยวพันกับหลาย module
  • การ scale out ใช้เวลามากเพราะต้องการ resource และ scale ทั้ง server
  • การแก้ไข เพื่อให้ใช้งานได้ไปก่อน (Technical debt) ไม่ได้เป็นแนวทางระยะยาว
  • ทำงานได้ใน scope อย่างไดอย่างหนึ่ง มีความยากในการต่อยอด

PostgreSQL tuning recommendation

สรุปเกี่ยวกับค่า parameter ที่จำเป็นสำหรับการ tuning PostgreSQL database ก่อนที่จะ tuning มาทำความเข้าใจเกี่ยวกับ architecture ของ Posgresql ตามรูปข้างล่าง จะเห็นว่า Shared Memory เป็น resource สำคัญที่ทุก backgroud process และ data file ต้องการที่จะเข้าถึงและใช้งาน

Shared Memory คือ Memory ที่ reserve ไว้สำหรับ database caching และ transaction log caching ประกอบด้วย shared buffer และ WAL buffer

shared buffer ช่วยทำให้ไม่ต้องอ่านข้อมูลจาก Disk ตลอดเวลา จากการอ่านข้อมูลขึ้นมาพักไว้ที่ shared buffer และไม่ต้องอ่านจาก disk อีกครั้งเมื่อต้องการข้อมูลเดิม

WAL buffer เป็นที่เก็บข้อมูลที่มีการเปลี่ยนแปลงต่างๆ ใน database ใน memory ก่อนที่จะมีการเขียนลง WAL file เป็นรอบเวลา WAL file มีความจำเป็นมากในการทำ backup และ restore

PostgreSQL process type ประกอบด้วย 4 ประเภทดังนี้

  1. Postmaster (Daeomon) process
  2. Background process
  3. Backend process
  4. Client process

Postmaster process เป็น process ที่ start ขึ้นมาตอนที่ PostgreSQL เริ่มทำงาน โดยจะจัดการเรื่อง Recovery, initializes shared memory และสั่งให้ background process เริ่มทำงาน นอกจากนั้น Postmaster process ยังสร้าง backend process ขึ้นมาทุกครั้งที่ client เรียกใช้ PostgreSQL

Background Process ทำหลายหน้าที่ดังนี้

MethodRole
loggerเขียน error message ลง file
checkpointer writerตรวจสอบและเขียนข้อมูลลง file เมื่อเจอ dirty buffer
wal writerเขียน WAL buffer ลง WAL file
autovacuum launcherจะมีการ start autovacuum เพื่อ clean up space ที่ไม่ถูกใช้กลับมาใช้อีกครั้ง ถ้ามีการ set autovacuum=on
archiverarchive.log กรณีที่ setup WAL file ในแบบ direcoty copy
stats collectorเก็บข้อมูลของแต่ละ session (pg_stat_activty) และการทำงานของแต่ละ table (pg_stat_all_tables) และข้อมูล stat ของ database

Backend Process เป็น process ที่จัดการเกี่ยวกับ query ของ user process และส่ง result ที่ได้จาก query จำนวน process ที่จะรองรับ user request จะถูกกำหนดในค่า max_connection ซึ่งมีค่า default ที่ 100 connection ในการ query แต่ละครั้งจำเป็นต้องใช้ local memory โดยมี parameter หลักๆ คือ

  1. work_mem เนื้อที่ใช้สำหรับการ sorting, สร้าง bitmap, hash joins และ merge joins. ค่า default คือ 4 MB
  2. Maintenance_work_mem เนื้อที่สำหรับ Vacuum และ CREATE INDEX ค่า default คือ 64MB
  3. Temp_buffer เนื้อที่หรับสร้าง Temporary Table ค่า default คือ 8 MB

Client procces คือ background process ที่ assign ให้กับทุกๆ backend user connection โดย Postmaster process จะสร้าง process ลูกเพื่อให้บริการสำหรับแต่ละ user connection โดยเฉพาะ

Postgresql Tuning parameter

ในการสร้าง Postgrsql จะต้องตรวจสอบ spec ของแต่ละ version เช่น ขนาดของเครื่อง ที่ต้องมี resource ที่เพียงพอ เช่นจะต้องมี mininum resource ที่

  • CPU 1 core
  • 2 GB of RAM
  • 512 MB of Harddisk

Operating System

เลือกใช้ Linux distribution ที่เหมาะสมสำหรับ run Postgresql ส่วนใหญ่จะเป็น Redhat based เช่น RHEL หรือ CentOS และเลือกใช้ kernel ที่ up to date

CPU

Postgresql จะสร้าง threads (backend process) สำหรับแต่ละ connection เสมอ ซึ่งต้องการ cpu core พี่เพียงพอเพื่อจะทำให้สามารถสร้าง process ได้ ดังนั้นจำนวน cpu core จึงขึ้นกับจำนวน concurrent connection และ concurrent query

ค่าเริ่มต้นของ cpu ควรจะเริ่มที่ 4 cores เพื่อรองรับ application ขนาดเล็ก ที่มีจำนวน connection อยู่ที่ประมาณ 24 connections แต่ถ้าเกิดเหตุการณ์ overload ก็ต้องเพิ่มจำนวน core มากขึ้น บางกรณีอาจต้องมีจำนวน core มากกว่า 48 cores เพื่อรองรับจำนวน connection หลายร้อย connections

Tuning Tips: เทียบจำนวน transaction per second (TPS) กรณีที่ใช้ feature hyper-threading จะได้ TPS น้อยกว่าไม่ใช้ สำหรับ query ที่ไม่ซับซ้อนและมีการเรียกใช้เยอะ จำนวน core จะมีผลต่อ TPS มากกว่าความเร็วของ cpu

Memory

Memory สำคัญมากๆ สำหรับ Postgresql performance และค่าที่สำคัญคือ shared_buffers ซึ่งเป็นเนื้อที่สำหรับ postgresql ใช้เพื่อเป็น data caching การที่มี data ถูก load เข้าไปใน cache มากเท่าไหร่ ก็จะทำให้ query ทำงานเร็วขึ้นเท่านั้น นอกจากนั้นพื้นที่นี้ยังใช้สำหรับ sorting เพื่อ return ผลกลับไปยัง client กลับกันถ้าทุกครั้งต้องมีการอ่านจาก disk เนื่องจากไม่มีข้อมูลอยู่ใน cache หรือเนื่อที่สำหรับ cache น้อยก็จะทำให้การทำงานช้ากว่าจะได้ผลลัพธ์

Tuning Tips: ค่าเริ่มต้นสำหรับ shared_buffers คือ 25% ของ memory ที่เหลือทั้งหมด เพื่อให้มีพื้นที่สำหรับ OS ใช้ในการ caching data และ ​run process อื่นๆ ด้วยนอกเหนือจาก database การเพิ่ม work_mem สามารถทำให้ sorting ทำงานได้เร็วขึ้น แต่ต้องไม่มากจนเกินไป เพราะจะทำให้ memory ของทั้งเครื่องถูกใช้จนหมดได้ เพราะทุกครั้งที่มีการ query และ sorting พื้นที่ส่วนนี้จะถูกใช้ผันตามจำนวน query และ sort จึงต้องเริ่ม tuning ด้วยค่าที่น้อยๆ ก่อน แล้วค่อยๆ เพิ่มขึ้นจนได้ค่าที่เหมาะสม แล้วควรจะใช้ free command (free -h) เพือ set ค่า effective_cache_size ตามจำนวน memory ที่เหลืออยู่ รวมกับ cache ทั้งนี้ planner ใน postgresql ก็จะรู้ว่าควรจะใช้ memory ได้เท่าไหร่ตามที่ OS cache มีให้ใช้อยู่จริง

Disk

ความเร็วของการอ่านเขียน Disk มีผลอย่างมากต่อ performance ของ database เพราะต้องมีการ load ข้อมูลจาก disk ไปยัง shared_buffer ในทุกครั้งที่ query และการ sync จาก memory ไปยัง disk

Tuning Tips: กรณีของ SSD disk set ค่า random_page_cost ที่ 1.5 หรือ 2 (ค่า default คือ 4) จะส่งผลดีต่อ planner เพราะการดึงข้อมูลแบบสุ่มจะให้ผลลัพธ์ที่เร็วกว่าอ่านจาก disk แบบปกติ

Initial Configuration Settings

โดยพื้นฐานแล้ว tuning จะอิงกับ performance ของเครื่องเป็นหลัก เพราะปัจจัยเรื่อง application ที่การใช้งานเปลี่ยนแปลงตามเวลา ต้องพิจารณาเฉพาะในแต่ละ user case เพื่อให้ได้ค่าที่เหมาะสมด้วยการทำ benchmark

shared_buffers: ควร set ที่ 25% (1/4) ของ memory ที่เหลืออยู่ในขณะนั้นของเครื่อง ถ้าเครื่องเหลือน้อยกว่า 1GB ควร set ที่ 1/8

work_mem: ค่า default คือ 4 MB การปรับค่าขึ้นอยู่กับปัจจัยของ temp file ว่าถูกสร้างบ่อยครั้ง และ file มีขนาดเล็ก (10 mb) หรือไม่ ค่าที่แนะนำคือ 1/4 system memory / max_connection การ tuning ต้องพิจารณาความถี่ของการ query ด้วย ตัวอย่างถ้า work_mem 1024mb ถ้ามี 16 worker ก็จะต้อง request memory ถึง 16GB การ set มากไปจะทำให้ system memory เต็ม ส่งผลให้ host มีปัญหา out of memory ได้

effective_cache_size: set ตามจำนวน memory ที่เหลือของเครืองรวมกับ cache ข้อมูลได้จาก free -h command

Logging

configuration พื้นฐานคือ

log_checkpoints = on
log_connections = on
log_disconnections = on
log_temp_files = 0
log_min_duration_statement = -1

PostgreSQL Tuning Queries

enable pg_stat_statement สำหรับการทำ Profiling และ statistic

#add pg_stat_statements to postgresql.conf, require restart
shared_preload_libraries = 'pg_stat_statements

#create the pg_stat_statements extension
create extension pg_stat_statements;

# add the buffercache extension
create extension pg_buffercache;

Query เพื่อหาว่า table ไหนใช้ buffercache มากผิดปกติ

SELECT  c.relname,
 pg_size_pretty(count(*) * 8192) as buffered, round(100.0 * count(*) / (SELECT setting FROM pg_settings WHERE name='shared_buffers')::integer,1) AS buffers_percent,
 round(100.0 * count(*) * 8192 / pg_relation_size(c.oid),1) AS percent_of_relation,
 round(100.0 * count(*) * 8192 / pg_table_size(c.oid),1) AS percent_of_table
FROM    pg_class c
  INNER JOIN pg_buffercache b
  ON b.relfilenode = c.relfilenode
  INNER JOIN pg_database d
  ON (b.reldatabase = d.oid AND d.datname = current_database())
GROUP BY c.oid,c.relname
ORDER BY 3 DESC
LIMIT 10;

Query เพื่อหา waiting หรือ block

SELECT * FROM pg_stat_activity 
WHERE wait_event IS NOT NULL AND backend_type = 'client backend';

กรณีที่ query ถูก block จาก connection อื่น ใน Postgresql 9.6 ขึ้นไป ใช้ function pg_blocking_pids() เพื่อให้ได้ process ID ที่ถูก block แล้วค่อยหา statistic

SELECT * FROM pg_stat_activity 
WHERE pid IN (SELECT pg_blocking_pids())

Query statistic ของแต่ละ type

select query, calls, total_exec_time, min_exec_time, max_exec_time, mean_exec_time, stddev_exec_time, rows
from public.pg_stat_statements order by total_exec_time desc;

Query แสดง statistic ของ sequential scan

SELECT schemaname, relname, seq_scan, seq_tup_read, idx_scan, seq_tup_read / seq_scan AS avg
FROM  pg_stat_user_tables 
WHERE   seq_scan > 0 
ORDER BY seq_tup_read DESC;SELECT schemaname, relname, seq_scan, seq_tup_read, idx_scan, seq_tup_read / seq_scan AS avg
FROM  pg_stat_user_tables 
WHERE   seq_scan > 0 
ORDER BY seq_tup_read DESC;

Query แสดงเวลารวม และเวลาเฉลี่ย

SELECT query, total_exec_time, calls, mean_exec_time 
FROM   pg_stat_statements 
ORDER BY total_exec_time DESC;

การ reset statistic

SELECT pg_stat_statements_reset();
SELECT pg_stat_reset();

Query แสดงขนาดของ table

SELECT *, pg_size_pretty(total_bytes) AS total
    , pg_size_pretty(index_bytes) AS INDEX
    , pg_size_pretty(toast_bytes) AS toast
    , pg_size_pretty(table_bytes) AS TABLE
    , (toast_bytes * 100)/NULLIF(table_bytes,0) as toast_percent
  FROM (
  SELECT *, total_bytes-index_bytes-COALESCE(toast_bytes,0) AS table_bytes FROM (
      SELECT c.oid,nspname AS table_schema, relname AS TABLE_NAME
              , c.reltuples AS row_estimate
              , pg_total_relation_size(c.oid) AS total_bytes
              , pg_indexes_size(c.oid) AS index_bytes
              , pg_total_relation_size(reltoastrelid) AS toast_bytes
          FROM pg_class c
          LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
          WHERE relkind = 'r'
  ) a
) a
where table_schema = 'public'
order by table_bytes desc;

Query จำนวน live, dead rows และ last vacuum

SELECT schemaname, relname, n_live_tup, n_dead_tup, (n_dead_tup * 100)/(NULLIF(n_live_tup, 0)) as dead_tup_percent, last_autovacuum, last_vacuum FROM pg_stat_all_tables
	where schemaname = 'pg_toast' or schemaname = 'public'
	ORDER BY n_live_tup DESC
	LIMIT 20;
  • last_vacuum และ last_autovacuum ต้องภายใน 24 ชั่วโมง
  • ค่า dead_tup_percent ต้องไม่มากเกินไปสำหรับ config_str, config_blob, config_version การที่ค่ามากเกินไปเกิดจาก cleaner ทำงานช้าส่งผลให้รอบของ vacuum ช้ากว่าที่จะเป็น

Query ตรวจสอบการทำงานของ Vacuum

SELECT datname, usename, pid, current_timestamp - xact_start AS xact_runtime, state, query
FROM pg_stat_activity 
WHERE query LIKE '%autovacuum%' AND query NOT LIKE '%pg_stat_activity%'
ORDER BY xact_start;

ค่า xact_runtime สูง อาจจะเป็นเพราะ maintenance_work_mem มีค่าน้อยไป อาจจะต้องพิจารณาเพิ่มเป็น 1 GB

Query เพื่อหา query ที่ใช้เวลานาน

SELECT left(query, 100) AS short_query,
round(total_time::numeric, 2) AS "total_time (msecs)",
calls,
round(mean_time::numeric, 2) AS "mean_time (msecs)",
round(stddev_time::numeric, 2) AS "stddev_time (msecs)",
round((100 * total_time / sum(total_time::numeric) OVER ())::numeric, 2) AS percentage_cpu
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 20;

…end…

References

understanding-postgresql-architecture

postgresql document

Setting Up an Optimal Environment for PostgreSQL