ปัจจุบันยากที่จะจินตนาการโลก IT โดยไม่มีฐานข้อมูล Redis ใน แบบสำรวจนักพัฒนา Stackoverflow ปี 2021 ฐานข้อมูลในหน่วยความจำนี้ได้รับความนิยมมาก และถูกเลือกเป็นฐานข้อมูลที่นักพัฒนาชื่นชอบมากที่สุดโดยนักพัฒนากว่า 70,000 คน เนื่องจากเป็นฐานข้อมูลในหน่วยความจำ Redis ให้ประสิทธิภาพสูง เหมาะสำหรับสถานการณ์ที่ต้องการเวลาตอบสนองสั้นและความหน่วงน้อยที่สุด อย่างไรก็ตาม กรณีการใช้งานของ Redis มักถูกเข้าใจผิดว่าจำกัดแค่ caching และ message-brokering วันนี้เราจะดูว่าทำไมมันผิดและใช้ Redis ในบทบาทฐานข้อมูลหลัก
แนวคิด
เราจะสร้างแอปเล็กๆ ที่ให้ผู้ใช้ทิ้งความคิดเห็นในรูปแบบแบบสำรวจออนไลน์ ในกรณีนี้ สมมติว่าอยากเก็บความคิดเห็นสำหรับบริษัท เพื่อให้ง่าย เราจะโฟกัสที่ฟังก์ชันหลักของแอป ดังนี้:
- ผู้ใช้ตอบคำถาม 3 ข้อ:
- คุณรู้สึกอย่างไรกับผลิตภัณฑ์/บริการของเรา? 1 - 10 คะแนน
- คุณจะแนะนำเราให้เพื่อนร่วมงานไหม? ใช่/ไม่ (true/false)
- แบ่งปันความคิดเห็น... ข้อความอิสระ
- ผู้ใช้ส่งฟอร์มได้
- แต่ละผลลัพธ์แบบสำรวจจัดเก็บเป็นระเบียนเดียวในฐานข้อมูล (hash)
- ผู้ใช้ดูผลลัพธ์แบบสำรวจได้
ดู แอป демо ได้ที่นี่
เทคโนโลยีที่ใช้
แอปสำรวจเล็กๆ นี้เป็นตัวอย่างที่ดีสำหรับการใช้ประโยชน์สูงสุดจากสถาปัตยกรรม serverless Serverless ให้ความสามารถในการขยายได้สูงสุดพร้อมลดต้นทุนต่ำสุด สามารถทำได้ด้วยเทคโนโลยีเหล่านี้:
Next.js
Next.js เป็นเฟรมเวิร์กพัฒนาโอเพนซอร์สที่เพิ่มความสามารถให้แอป React แบบดั้งเดิม เช่น server-side rendering, static page generation และสำคัญที่สุดคือ API routes เราจะใช้ Next.js สร้างทั้ง frontend และ API ของแอป
Upstash Redis
Upstash ให้ฐานข้อมูล Redis serverless แบบเต็มรูปแบบ คงทน ได้ง่ายมาก และราคาต่อคำขอล่าสุด สร้างบน Redis แบบดั้งเดิม Upstash รวมประสิทธิภาพที่นำของ Redis เข้ากับความทนทานของที่เก็บข้อมูลดิสก์ ทำให้เหมาะกับกรณีใช้งานของเราเป็นอย่างยิ่ง
การตั้งค่าโปรเจกต์
- สร้างแอป Next.js:
npx create-next-app survey-app. - สร้างฐานข้อมูล Upstash Redis ใน คอนโซล Upstash และคัดลอก UPSTASH_REDIS_REST_URL และ UPSTASH_REDIS_REST_TOKEN ทั้งคู่
โปรเจกต์จะเป็น single page application พร้อม 2 API endpoints:
pages/api/submit.jsจัดเก็บรายการแบบสำรวจpages/api/results.jsดึงรายการแบบสำรวจทั้งหมด
เพื่อสื่อสารกับ Upstash ได้ง่ายขึ้น ติดตั้ง @upstash/redis npm package ผ่าน npm install @upstash/redis.
โค้ด
สร้างไฟล์ใหม่ pages/api/submit.js ดังนี้:
// pages/api/submit.js
import { Redis } from "@upstash/redis";
const redis = new Redis({
url: "INSERT_YOUR_URL_HERE",
token: "INSERT_YOUR_TOKEN_HERE",
});
const submitHandler = async (req, res) => {
const body = req.body;
// เตรียมข้อมูลเพื่อใส่เข้า DB
const data = {
rating: String(body.rating) || "0",
recommendation: String(body.recommendation) || "false",
comment: String(body.comment) || "",
};
// สร้าง id แบบสุ่มเพื่อจัดเก็บรายการสำรวจ
const id =
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
// ใส่ข้อมูลลง Upstash redis
try {
// จัดเก็บข้อมูลสำรวจ
await redis.hset(`entries:${id}`, data);
// จัดเก็บ id ของสำรวจเพื่อดึงคืนมาได้ภายหลัง
await redis.sadd("entries", `entries:${id}`);
} catch (error) {
console.error("Failed to insert data into redis", error);
return res.status(500).json({
success: false,
message: "Failed to insert data into redis",
});
}
return res.status(200).json({
success: true,
message: "Data inserted successfully",
});
};
export default submitHandler;
เราทำ 3 อย่างที่นี่:
- รับข้อมูลสำรวจจาก request body และเตรียมสำหรับ Redis
- ใส่รายการสำรวจลง Redis เป็น hash
- เพิ่ม id ของรายการสำรวจเข้าไปใน set
อาจสงสัยว่าทำไมต้องสร้าง hash สำหรับรายการสำรวจแล้วค่อย put id ลง set อีกครั้ง ขั้นตอนนี้สำคัญเมื่อต้องการดึง event จาก Redis อีกครั้ง Redis ทำงานเป็น key-value store หมายความว่าไม่เหมือน SQL databases ที่คุ้นเคย Redis ไม่ได้ทำให้ค้นหาข้อมูลได้ เว้นแต่จะระบุ key ที่แน่นอนที่จัดเก็บไว้ คำสั่งแบบ SELECT * FROM SurveyResults; รองรับใน SQL แต่ Redis ต้องใช้วิธีอื่น เราสร้าง set และเพิ่ม Redis keys ทั้งหมดของรายการผลลัพธ์สำรวจเข้าไป ตอนต้องการดึงรายการสำรวจทั้งหมด ให้ค้นหา keys ใน set แทน กลับไปเขียนโค้ดต่อดีกว่า
สร้างไฟล์ใหม่ pages/api/results.js ดังนี้:
// pages/api/results.js
import { Redis } from "@upstash/redis";
const resultsHandler = async (req, res) => {
// ดึงข้อมูลจาก redis
const redis = new Redis({
url: "INSERT_YOUR_URL_HERE",
token: "INSERT_YOUR_TOKEN_HERE",
});
try {
// หา entries ทั้งหมดใน set
const entries = await redis.smembers("entries");
// ดึงรายการสำรวจทั้งหมดด้วย id/key
// เพื่อรันหลายคำสั่งพร้อมกัน Upstash รองรับ pipeline command ทำให้รันหลายคำสั่งพร้อมกันและได้ผลลัพธ์ในครั้งเดียว
const p = redis.pipeline();
entries.forEach((id) => {
p.hgetall(id);
});
const results = await p.exec();
return res.status(200).json({
success: true,
message: "Data retrieved successfully",
data: results,
});
} catch (error) {
console.error("Failed to retrieve data from redis", error);
return res.status(500).json({
success: false,
message: "Failed to retrieve data from redis",
});
}
};
export default resultsHandler;
Backend ทำงานแล้ว ทำ frontend ให้เสร็จสิ้น
สร้างไฟล์ใหม่ pages/index.js ดังนี้:
// pages/index.js
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
export default function Home() {
const handleSubmit = async (e) => {
e.preventDefault();
const form = e.target;
const data = {
rating: form.rating.value,
recommendation: form.recommendation.value,
comment: form.comment.value,
};
// ส่งข้อมูลไป backend
await fetch("/api/submit", {
body: JSON.stringify(data),
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
method: "POST",
});
alert("Thank you for your feedback!");
};
const RatingOption = ({ value }) => (
{" "}
);
return (
);
}
เพื่อให้ styles ทำงาน แทนที่เนื้อหา styles/Home.styles.css ด้วยโค้ดต่อไปนี้:
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.container form > div {
padding: 20px;
display: flex;
flex-direction: column;
align-items: stretch;
}
.container form > div > label {
margin-bottom: 10px;
}
พร้อมรับรายการสำรวจแล้ว! แต่ยังมีอีก เรายังต้อง implement ผลลัพธ์สำรวจใน frontend
สร้างไฟล์ใหม่ pages/results.js ดังนี้:
import { useEffect, useState } from "react";
import styles from "../styles/Results.module.css";
export default function Results() {
const [surveyData, setSurveyData] = useState([]);
useEffect(() => {
fetch("/api/results")
.then((res) => res.json())
.then((response) => setSurveyData(response.data));
}, []);
return (
{" "}
{surveyData.map((data) => (
Rating: {data.rating} {" "}
{" "}
Recommendation: {data.recommendation} {" "}
{" "}
Comment: {data.comment} {" "}
{" "}
))}
{" "}
);
}
และสุดท้ายสร้างไฟล์ styles/Results.module.css ด้วยเนื้อหาต่อไปนี้:
.container {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
min-height: 100vh;
margin: 50px 0;
}
.container > div {
background: rgba(0, 0, 0, 0.05);
border-radius: 10px;
padding: 15px;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.container p {
margin: 0;
}
ตอนนี้ดูภาพรวมรายการสำรวจทั้งหมดได้ที่ localhost:3000/results.
โค้ดต้นฉบับครบถ้วนของแอปพลิเคชันมีที่ GitHub repository upstash-survey-app.
สรุป
ในโพสต์นี้เราพัฒนาแอปเว็บ fullstack Next.js ที่จัดการการส่งฟอร์มและจัดเก็บฟอร์มที่กรอกแล้วใน Upstash serverless Redis เราเห็นว่า Redis ใช้เป็นฐานข้อมูลหลักได้ และการเปลี่ยนแปลงการออกแบบเมื่อสลับจากฐานข้อมูลอื่น (เช่น SQL) ไป Redis
ด้วยฐานข้อมูล Redis serverless ที่ตั้งค่าง่ายของ Upstash ทำให้การจัดเก็บข้อมูลฟอร์มบนคลาวด์ง่ายขึ้นอย่างลافت
หวังว่าโพสต์นี้ช่วยให้เข้าใจ Redis ได้เรียนรู้ Upstash Redis และเริ่มสร้างแอปพลิเคชันด้วยวิธีใหม่ๆ ในการจัดเก็บข้อมูล