สร้าง Microservice + Redis ด้วย Spring Boot + Spring Data
ฐานข้อมูลแบบ NoSQL ที่ได้รับความนิยมอย่างมากอีกตัวหนึ่งคือ Redis ซึ่งเก็ฐข้อมูลแบบ key-value ไว้ในหน่วยความจำชั่วคราว ซึ่งสามารถใช้เป็นฐานข้อมูลชั่วคราวได้ ดังนั้นในบทความนี้จะทำ CRUD Microservice ที่ใช้ Redis เป็นฐานข้อมูลด้วย Spring Boot และ Spring Data Redis
Redis คืออะไร
ย่อมาจาก Remote Directory Server (RE-dis) เป็นฐานข้อมูลแบบ NoSQL ที่ได้รับความนิยมอย่างมากตัวหนึ่ง โดยเก็บข้อมูลแบบ key-value ในหน่วยความจำชั่วคราว (in-memory — RAM) มีความทนทานของข้อมูล (durability) รองรับความแตกต่างของชนิดข้อมูลได้อย่างหลากหลาย ตัวอย่างเช่น string, list, set, hash, sorted set, bitmap, hyperloglogs และ special indexes พัฒนาโดย Salvatore Sanfilippo และปัจจุบันดูแลโดย Redis Labs
Data types ที่รองรับ
Redis จะ map key กับ data type ซึ่งเป็นจุดที่แตกต่างจากฐานข้อมูล key-value ตัวอื่นที่ ไม่รองรับ key แบบ string อย่างเดียว แต่จะรองรับ key ต่างๆ ได้ดังนี้
- String — เป็นชนิดข้อมูลพื้นฐาน
- List —เป็น list ของ String จัดเรียงโดย insertion order
- Set — เป็น set ของ String ที่ไม่จัดเรียง
- Hash table — เป็นตารางที่เก็บ key และ value
- Sorted set — เป็น set ของ String ที่จัดเรียงและไม่ซำ้กัน
- Bitmap — ใช้สำหรับคำสั่งพิเศษที่จัดการค่าของ String เหมือน array ของ bits
- HyperLogLogs — เป็นโครงสร้างข้อมูลความน่าจะเป็นใช้สำหรับการประมาณ cardinality ของ set
Spring Data Redis
เป็น Spring Data สำหรับฐานข้อมูล Redis ซึ่งเป็นส่วนหนึ่งของโครงการ Spring Data ที่ทำให้ตั้งค่าและเข้าถึงฐานข้อมูล Redis จาก Spring applicatoin โดยใช้ key-value store ของ Redis โดยลดงานที่ซ้ำกันและ boilerplate code ที่จำเป็นสำหรับติดต่อกับ stroe ผ่านทาง Spring infrastructure
โดยสามารถเพิ่ม dependency ของ Spring Data Redis ใน maven ด้วย
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
แต่ถ้าเป็น Spring Boot สามารถเพิ่มด้วย
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</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 ทำให้บางหัวข้อจะละการอธิบายในลายละเอียดเพราะเหมือนกัน
ติดตั้งและรัน Redis
เนื่องจากเราจะใช้งาน Redis เราจะต้องติดตั้งในเครื่องก่อน ถ้าเป็น MacOS สามารถติดตั้งได้จาก brew ได้เลยด้วยคำสั่งนี้
$ brew install redis
ถ้าเป็น OS อื่นดูได้ ที่นี่ แต่ถ้าเป็น Windows อาจจะใช้ Redis ยากหน่อยจะต้องติดตั้งบน VM หรือ Docker เพื่อใช้งาน
หลังจากติดตั้งแล้ว สามารถรัน Redis server ได้ด้วยคำสั่ง
$ redis-server
สร้าง Spring Boot Project
สามารถใช้ Spring Initializr ในการสร้างโปรเจ็คโดยเลือก dependency เป็น Web
Redis
และ Lombok
สร้าง Customer Data (POJO)
เป็น POJO ที่แทนข้อมูล Customer โดยใช้ @Data เพื่อสร้าง Getter/Setter ให้ และใช้ @RedisHash เพื่อระบุว่าจะใช้ data type เป็น hash ชื่อว่า customer
src/main/java/com/example/demo/customer/Customer.java
โดยกำหนดให้แต่ละ field ของ Customer ใน hash table มีลักษณะดังนี้
- id — ตัวแปรค่า id ชนิดข้อมูล String ซึ่งเป็นค่าที่กำหนดให้อัตโนมัติ
- firstName — ตัวแปร String ที่จะต้องมีค่า
- lastName — ตัวแปร String ที่จะต้องมีค่า
- age — ตัวแปร Integer ที่จะต้องมีค่า
- email — ตัวแปร String ที่จะต้องมีรูปแบบเป็น email
สร้าง Customer Controller
เป็น controller ที่ mapping กับ request ต่างๆ ด้วย @ResController ใน presentation layer ดังนี้
src/main/java/com/example/demo/customer/CustomerController.java
สร้าง Customer Service
เป็น Service ที่รองรับการ invoke จาก Controller เพื่อทำ Business Logic ต่างๆ โดยเรียกไปยัง Redis เพื่อใช้ CRUD operation ด้วย CustomerRepository ดังนี้
src/main/java/com/example/demo/customer/CustomerService.java
สร้าง Customer Repository (สำคัญ)
เป็นส่วนของ Persistence layer แต่สำหรับ Redis แล้วจะเป็นข้อมูลไว้ในหน่วยความจำชั่วคราวดังนั้นมันจะไม่เชิง Persistence เท่าไหร่ ที่ติดต่อโดยตรงกับ Redis โดยสร้าง interface ที่ extend จาก CrudRepository เพื่อใช้ CRUD operation ในการดำเนินการกับ Redis ที่เป็นฐานข้อมูล โดยใช้ @EnableRedisRepositories เพื่อใช้ Redis Repository
src/main/java/com/example/demo/customer/CustomerRepository.java
การใช้ @EnableRedisRepository annotation เป็นการให้ config ต่างๆ ที่จำเป็นสำหรับการใช้งาน Redis ในเชิง Repository patter สำหรับให้ Redis เป็นฐานข้อมูลและใช้งาน CRUD operation ทำให้การเปลี่ยนฐานข้อมูล NoSQL ได้อย่างไร้รอยต่อ เพราะเราเพียงเปลียน Customer Repository ให้ตรงกับฐานข้อมูล NoSQL ที่ใช้งาน
ง่ายใช่ไหม!!!
สร้าง Application Config
กำหนด config ของ application อีกนิดหน่อย ไม่เกี่ยวกับฐานข้อมูลแต่เกี่ยวกับกำหนด port และ prefix ของ URI
ทดลองรับ Application
หลังจากที่ได้ implement ทุกอย่างเรียบร้อยแล้ว ก็รัน Application (Microservice) ด้วยคำส่ัง mvn spring-boot:run
ถ้าสำเร็จจะเห็น message Started
และต้องแน่ใจว่า mongo deamon รันอยู่
ลองสร้าง Customer ด้วย POST method และ body เป็นข้อมูลของ Customer โดย request ไปที่ endpoint http://localhost:9000/api/customers
ด้วย Postman จะเห็นได้ว่า Service response กลับมาเป็นข้อมูลของ Customer โดยที่ id ถูกกำหนดให้เองอัตโนมัตโดย Redis เป็น hash key ในรูปแบบของ String ดังนี้
ใช้ id ที่ได้มาจากตอนสร้าง Customer มา request ด้วย GET เพื่อตรวจสอบว่าข้อมูลได้ถูกสร้างจริง จะเห็นได้ว่าจะได้ข้อมูลของ Customer ที่เราสร้างไป และสามารถแก้ไขข้อมูลด้วย method PUT และ ลบข้อมูลด้วย method DELETE
ใช้ Redis-CLI
หลังจากที่เราได้สร้าง Microservice เพื่อทำ CRUD operation กับฐานข้อมูล Redis แล้ว สามารถใช้ Redis-CLI เพื่อตรวจสอบข้อมูลในฐานข้อมูลดูได้
โดยเข้าสูง Redis-CLI ด้วยคำสั่ง redis-cli
ก็จะแสดง prompt ให้ใส่คำสั่งของ Redis ได้
$ redis-cli
127.0.0.1:6379>
คำสั่ง KEYS *
แสดง key ทั้งหมดใน Redis Server
> KEYS *
1) "customer"
2) "customer:678f6b3f-f388-42bc-9e21-fce76232cf8d"
คำสั่ง TYPES key
แสดง data type ของ key นั้นๆ
> TYPE customer
set
> TYPE customer:678f6b3f-f388-42bc-9e21-fce76232cf8d
hash
คำสั่ง HGETALL key
แสดง field และ value ทั้งหมดของ hash ที่เก็บค่า key นั้นๆ
> HGETALL customer:678f6b3f-f388-42bc-9e21-fce76232cf8d
1) "_class"
2) "com.iphayao.demo.customer.Customer"
3) "id"
4) "678f6b3f-f388-42bc-9e21-fce76232cf8d"
5) "firstName"
6) "John"
7) "lastName"
8) "Doe"
9) "age"
10) "20"
11) "email"
12) "john.doe@gmail.com"
คำสั่ง HGET key field
แสดง value ของ key และ field นั้นๆ
> HGET customer:678f6b3f-f388-42bc-9e21-fce76232cf8d id
"678f6b3f-f388-42bc-9e21-fce76232cf8d"
> HGET customer:678f6b3f-f388-42bc-9e21-fce76232cf8d firstName
"John"
> HGET customer:678f6b3f-f388-42bc-9e21-fce76232cf8d lastName
"Doe"
> HGET customer:678f6b3f-f388-42bc-9e21-fce76232cf8d age
"20"
> HGET customer:678f6b3f-f388-42bc-9e21-fce76232cf8d email
"john.doe@gmail.com"
> HGET customer:678f6b3f-f388-42bc-9e21-fce76232cf8d _class
"com.iphayao.demo.customer.Customer"
สรุป
จากการสร้าง CRUD Microservice ติดต่อกับฐานข้อมูล Redis ซึ่งเป็น NoSQL ที่เก็บข้อมูลไว้ในหน่วยความจำชั่วคราว ด้วย Spring Boot และ Spring Data Redis นั้น ทำได้ง่ายมากเพียงแค่เปลี่ยน Persistence layer ให้เป็น Redis Repository ด้วยการใช้ @EnableRedisRepositories annotation ใน Customer Repository interface ที่ extends CrudRepository มาซึ่ง Spring Data จะจัดการ Dependency Injection ให้เองโดยอัตโนมัติ แต่ในบทความนี้จะเป็นการใช้ Redis ในเครื่องเอง แต่ถ้าเป็นการเชื่อมต่อ กับ Redis ที่อยู่ภายนอกอาจจะต้องตั้งค่าเพิ่มเติม แต่ด้วยที่ว่า Redis นั้นเก็บข้อมูลในหน่วยความจำชั่วคราวดังนั้นจึงไม่เหมาะกับการใช้เก็บข้อมูลถาวร โดยเมื่อ Redis Server shutdown หรือ restart ข้อมูลที่มีอยู่ก็จะหายไปหมด ดังนั้น Use Case ที่ใช้ Redis อาจจะใช้สำหรับ Caching ข้อมูลจะดีกว่า แต่ก็มีวิธีที่ทำให้ Redis เก็บข้อมูลถาวรได้เช่นกันแต่อาจจะต้องตั้งค่าเพิ่มเติมอีก