สร้าง Microservice + Cassandra ด้วย Spring Boot + Spring Data
ถ้าพูดถึงฐานข้อมูลแบบ NoSQL ที่สามารถขยายได้และประสิทธิภาพสูงโดยไม่ต้องกังวลเรื่องว่าจะล่มและมี avalibility สูงมาก โดยที่ไม่มี single point of failure เลยก็คือ Cassandra เก็บข้อมูลแบบ column ในบทความนี้จะทำ CRUD Microservice ที่ใช้ Cassandra เป็นฐานข้อมูลด้วย Spring Boot และ Spring Data Cassandra
Cassandra คืออะไร
มาเริ่มต้นเหมือนเดิมคือมาทำความรู้จักกับ Cassandra กันก่อน ก็คือเป็นฐานข้อมูล NoSQL ตัวหนึ่งที่มีคุณสมบัติเด่นคือสามารถขยายได้ (Hight Scalability) เป็นฐานข้อมูลกระจายประสิทธิภาพสูง (High Performance) ออกแบบมาให้จัดการกับข้อมูลจำนวนมากกับหลายๆ เซิร์ฟเวอร์ที่เชื่อมต่อกัน ซึ่งมี avalibility สูงมาก โดยที่ระบบจะไม่ล้มเหลวเลย (no single point of failure) โดยที่เก็บข้อมูลแบบ column (wide column store) และมีภาษาในการ query ของตัวเองคือ CQL ซึ่งคล้ายกับ SQL
Cassandra เริ่มพัฒนาที่ Facebook โดย Avinash Lakshman และ Prashant Malik เพื่อทำฟีเจอร์ Facebook inbox search และปล่อยให้เป็น Open Source ในปี 2008 และกลายเป็นโครงการหลักของ Apache ในปี 2010
Spring Data for Apache Cassandra
เป็น Spring Data สำหรับ Apache Cassandra ที่ทำให้ลดระยะเวลาการเรียนรู้สำหรับ การใช้งาน Cassandra โดยใช้วิธีเดียวกันกับ Spring Data อื่นๆ เพื่อเชื่อมต่อกับฐานข้อมูล
โดยสามาถเพิ่ม dependency ของ Spring Data Cassandra ดังนี้
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
แต่ถ้าเป็น Spring Boot สามารถเพิ่มด้วย
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
วางแผนกันก่อน (เหมือนเดิม)
CRUD Microservice ที่จะสร้างขึ้นเป็น Microservice ที่เก็บข้อมูลของ Customer ด้วย Redis ดังนั้น จะมี endpoint ที่ดำเนินการกับ customers resource ภายใต้ prefix path เป็น /api ดังนี้
- GET /api/customers — เรียกดูรายการ Customer ทั้งหมด
- GET /api/customers/{id} — เรียกดู Customer โดย user id
- GET /api/customers?name=xxxx — เรียกดูรายการ Customer ด้วยการค้นหาด้วย name
- POST /api/customers — สร้าง Customer ใหม่
- PUT /api/customers/{id} — แก้ไข Customer โดย user id
- DELETE /api/customers/{id} — ลบ Customer โดย user id
โดยแบบออกเป็น 3 Layer คือ Presentation Layer, Service Layer และ Persistence Layer
Use Case เดียวกับ สร้าง CRUD Microservice ด้วย Spring Boot ทำให้บางหัวข้อจะละการอธิบายในลายละเอียดเพราะเหมือนกัน
ติดตั้งและรัน Cassandra
ในบทความนี้จะใช้ Cassandra บน Docker ดังนั้นเราสามารถใช้ Official Image ของ Cassandra ได้เลย ใช้คำสั่งนี้ รัน docker container และ expose port 9042 ซึ่งเป็น default port ของ Cassandra และใช้ docker ps
เพื่อตรวจสอบว่า Cassandra รันอยู่หรือไม่
$ docker run --name cassandra-node -p 9042:9042 -d cassandra
ใช้คำสั่ง docker exec
เพื่อ remote เข้าไปใน Cassandra และใช้คำส่ัง cqlsh
เพื่อใช้ CQL shell ในการ execute คำสั่ง CQL
$ docker exec -it cassandra-node bash
root@81d55a6c1a61:/# cqlsh
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.3 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
สร้าง Key Space ด้วยคำสั่ง CREATE KEYSPACE
ดังนี้
cqlsh> CREATE KEYSPACE mykeyspace WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };
และสร้าง Table ด้วยคำสั่ง CREATE TABLE
ดังนี้
cqlsh> CREATE TABLE mykeyspace.customer (id UUID PRIMARY KEY, firstname text, lastname text, age double, email text);
เพราะเราต้องสร้าง Key Space และ Table ก่อนที่จะ insert ข้อมูลเข้ามาใน Table ซึ่ง Spring Data Cassandra ไม่ได้สร้างให้
สร้าง Spring Boot Project
สามารถใช้ Spring Initializr ในการสร้างโปรเจ็คโดยเลือก dependency เป็น Web
, Cassandra
และ Lombok
สร้าง Customer Data (POJO)
เป็น POJO ที่แทนข้อมูล Customer โดยใช้ @Data เพื่อสร้าง Getter/Setter ให้ และใช้ @Table เพื่อระบุว่าจะให้เป็น table ชื่อว่า customer
src/main/java/com/example/demo/customer/Customer.java
โดยกำหนดให้แต่ละ field ของ Customer ใน table มีลักษณะดังนี้ ซึ่งจะต้องสอดคล้องกับ table ที่เราสร้างด้งย CQL shell
- id — ตัวแปรค่า id ชนิดข้อมูล UUID และให้เป็น @PrimaryKey
- firstName — ตัวแปร String ที่จะต้องมีค่า
- lastName — ตัวแปร String ที่จะต้องมีค่า
- age — ตัวแปร Integer ที่จะต้องมีค่า
- email — ตัวแปร String ที่จะต้องมีรูปแบบเป็น email
โดยที่มี constructor เพื่อกำหนดค่า id ซึ่งเป็น UUID ที่ได้จาก UUIDs.timeBased()
สร้าง Customer Controller
เป็น controller ที่ mapping กับ request ต่างๆ ด้วย @ResController ใน presentation layer ดังนี้
src/main/java/com/example/demo/customer/CustomerController.java
จะเห็นได้ว่าค่า id จะเป็น UUID ทั้งหมดเพื่อให้สอดคล้องกับ model และ table ที่สร้างขึ้น
สร้าง Customer Service
เป็น Service ที่รองรับการ invoke จาก Controller เพื่อทำ Business Logic ต่างๆ โดยเรียกไปยัง Cassandra เพื่อใช้ CRUD operation ด้วย CustomerRepository ดังนี้
src/main/java/com/example/demo/customer/CustomerService.java
สร้าง Customer Repository
เป็นส่วนของ Persistence layer แต่สำหรับ Cassandra จะเก็บข้อมูลเป็น colume-base และเก็บใน table ดังนั้น CustomerRepository
จะเป็น interface ที่ extends จาก CassandraRepository
ซึ่งจะ inject SimpleCassandraRepository
ในตอน runtime เพื่อใช้ CRUD operation ในการดำเนินการกับฐานข้อมูล Cassandra
src/main/java/com/example/demo/customer/CustomerRepository.java
ใช้ @Repository เพื่อใช้ Repository configuration
ง่ายอีกแล้ว
สร้าง Application Config
กำหนด config ของ application อีกนิดหน่อย ไม่เกี่ยวกับฐานข้อมูลแต่เกี่ยวกับกำหนด port และ prefix ของ URI และ config ค่าต่างๆให้ cassandra
src/main/resources/application.yml
ค่าที่ config ให้กับ Spring Data Cassandra ดังนี้
- contactpoints — ค่า host ของ Cassandra ซึ่งในที่นี้ใช้ localhost เพราะว่าใช้ local docker container ซึ่งเข้าถึงได้ด้วย localhost
- port — ค่า port ของ Cassandra ซึ่งเป็นค่าตั้งต้น 9042 ที่เราได้ expose ตอนที่รัน docker container
- keyspace-name — ชื่อของ keyspace เป็น mykeyspace ที่เราสร้างขึ้นด้วย CQL shell
ทดลองรับ Application
หลังจากที่ได้ implement ทุกอย่างเรียบร้อยแล้ว ก็รัน Application (Microservice) ด้วยคำส่ัง mvn spring-boot:run
ถ้าสำเร็จจะเห็น message Started
แสดงว่า connect ได้กับ Cassandra
ลองสร้าง Customer ด้วย POST method และ body เป็นข้อมูลของ Customer โดย request ไปที่ endpoint http://localhost:9000/api/customers
ด้วย Postman จะเห็นได้ว่า Service response กลับมาเป็นข้อมูลของ Customer โดยที่ id ถูกกำหนดให้เป็น UUID ดังนี้
ใช้ id ที่ได้มาจากตอนสร้าง Customer มา request ด้วย GET เพื่อตรวจสอบว่าข้อมูลได้ถูกสร้างจริง จะเห็นได้ว่าจะได้ข้อมูลของ Customer ที่เราสร้างไป และสามารถแก้ไขข้อมูลด้วย method PUT และ ลบข้อมูลด้วย method DELETE
ซึ่งเราก็สามารถใช้ CQL shell ในการ query ข้อมูลใน Cassandra ได้เหมือน SQL
สรุป
จากการสร้าง CRUD Microservice ติดต่อกับฐานข้อมูล Cassandra ซึ่งเป็น NoSQL ที่เก็บข้อมูลในรูปแบบ column ด้วย Spring Boot และ Spring Data for Apache Cassandra โดยรัน Cassandra ใว้ใน docker container นั้น อาจจะยุ่งยากนิดหน่อยเพราะว่าเราต้องสร้าง keyspace และ table เองถ้าไม่สร้างจะฟ้อง error ว่าหาไม่เจอ และเปลียน Persistence lay ให้เป็น Cassandra Repository ซึ่ง Spring จะ inject SimpleCassandraRepository มาให้เอง และ id จะเป็น UUID ซึ่งจะต้อง generate เองใน constracture ของ Customer model แต่โดยรวมแล้วก็ไม่ยากที่ใช้งาน Cassandra กับ Spring framework