如何遷移到PlanetScale的無服務器數據庫?
譯文【51CTO.com快譯】作為一名開發者,我一直嘗試通過試驗和構建來學習新技術。我最近對無服務器數據庫頗感興趣,該技術有望加快部署、增強可擴展性及改善開發者體驗。我在測試多個產品后,決定將個人網站由使用Firebase和Redis改用PlanetScale,這是建立在MySQL和Vitess上的新的無服務器數據庫平臺,是為YouTube 提供支持而開發的開源平臺。
我選擇PlanetScale的原因如下:
- 數據庫分支:我可以使用心智模型與Git相同的數據庫。每次更改我的數據庫模式,我都打開部署請求。然后,我可以將這些更改合并回到主數據庫分支中。
- Prisma支持:與Prisma結合使用,可以很輕松地處理數據庫遷移。
- 無連接:由于PlanetScale是無服務器,因此可以承受數千個同時連接。幾乎可以把這認為是無連接,因為我不需要擔心池化或其他常見的反對意見。
- 10秒內部署:我在測試13個數據庫后,發現PlanetScale部署速度最快。使用它幾周并監控性能后,我看到API平均在大約150ms內解析(見下面的結果)。
Firebase和Redis
我的網站以前使用Google Firebase和Redis用于實時博文閱讀量和留言簿。決定選擇這些技術主要是想學習一下。Firebase和Redis(借助Upstash)都很易于上手,無需思考即可擴展,在無服務器環境下運行順暢。但是我想轉而使用基于SQL的數據庫(MySQL或PostgreSQL),以獲得新的學習體驗。
重建SQL
我發現自己在SQL有內置功能的地方編寫JavaScript。比如說,我使用Firebase獲取 JSON對象閱讀量,然后將這些值相加以找到總的閱讀量。
- const snapshot = await db.ref('views').once('value');
- const views = snapshot.val();
- const allViews = Object.values(views).reduce((total, value) => total + value);
- With SQL, you can use SUM() instead.
- SELECT SUM(count) as total
- FROM views;
排序同樣如此。以前我使用JavaScript sort,現在使用ORDER BY。雖然Firebase確實有類似功能,但我并不使用它。
- SELECT * FROM guestbook
- ORDER BY updated_at DESC;
SQL是成熟的技術。它已存在多年,會繼續存在多年。我在以前的工作中用過它,但仍覺得可以更深入地理解它。我也喜歡使用PostgreSQL(推薦Supabase),強烈推薦考慮該解決方案。
我還堅信使用自己推薦的工具。如果我沒有實際動手編寫代碼、在生產環境中運行應用程序,就很難有把握地向別人推薦產品。我使用PlanetScale Vercel Integration后,大為驚喜。只需點擊幾下鼠標,我就可以部署整個全棧應用程序。正如開頭提到的,數據庫遷移與我的心智模型相一致。
遷移現有數據
可能有更好的方法來遷移,但我將數據遷移到PlanetScale的自創解決方案如下:
- 從我的Firebase實時數據庫導出JSON數據
- 使用HVALS和TablePlus,從我的Redis集群導出JSON數據
- 在PlanetScale中創建新的數據庫分支,用于添加表的模式遷移
- 創建兩個新的API路由,負責加載JSON數據和INSERT INTO(插入到)MySQL
- 在數據庫分支上驗證API正確處理和遷移數據
- 創建擁有新模式更改的部署請求,并將其合并到main中
- 最后,點擊API,將JSON數據遷移到main
- 完畢!
下面是我使用的兩個腳本,供參考。
- import db from 'lib/planetscale';
- import guestbookData from 'data/guestbook';
- export default async function handler(req, res) {
- const toISOString = (unixTimestampInMs) =>
- new Date(unixTimestampInMs).toJSON().slice(0, 19).replace('T', ' ');
- let query = `INSERT INTO guestbook (email, updated_at, body, created_by)
- VALUES `;
- const escapeStr = (str) =>
- str
- .replace(/\\/g, '\\\\')
- .replace(/\$/g, '\\$')
- .replace(/'/g, "\\'")
- .replace(/"/g, '\\"');
- guestbookData.forEach((item, key) => {
- var value = JSON.parse(item['value']);
- query += `("${
- value.email ? `${value.email}` : 'not@provided.com'
- }", "${toISOString(value.updated_at)}", "${escapeStr(value.body)}", "${
- value.created_by
- }")`;
- if (key === guestbookData.length - 1) {
- query += ';';
- } else {
- query += ', ';
- }
- });
- const [rows] = await db.query(query);
- return res.status(201).json(rows[0]);
- }
- import db from 'lib/planetscale';
- import viewsData from 'data/views';
- export default async function handler(req, res) {
- let query = `INSERT INTO views (slug, count)
- VALUES `;
- const slugs = Object.keys(viewsData['views']);
- slugs.forEach((slug, key) => {
- const count = viewsData['views'][slug];
- query += `("${slug}", ${count})`;
- if (key === slugs.length - 1) {
- query += ';';
- } else {
- query += ', ';
- }
- });
- const [rows] = await db.query(query);
- return res.status(201).json(rows[0]);
- }
以下是我的PlanetScale模式,用于跟蹤博文閱讀量和留言簿留言。
- CREATE TABLE `views` (
- `slug` varchar(128) NOT NULL,
- `count` bigint NOT NULL DEFAULT '1',
- PRIMARY KEY (`slug`)
- )
- CREATE TABLE `guestbook` (
- `id` bigint NOT NULL AUTO_INCREMENT,
- `email` varchar(256) NOT NULL,
- `body` varchar(500) NOT NULL,
- `created_by` varchar(256) NOT NULL,
- `created_at` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
- `updated_at` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
- PRIMARY KEY (`id`)
- )
結果
我一直使用Checkly來監控連接到PlanetScale的生產級API的性能。Checkly讓我可以設置警報,那樣出現停運或性能降到接受的閾值以下時發出警報。迄今為止,我發現我的Next.js API Routes在us-east的Vercel上部署為無服務器函數時延遲約150ms。
PlanetScale性能小結
如下圖所示,與我之前的Firebase實現相比,響應時間顯著加快(請注意我何時進行切換)。 此外,擁有一項而不是兩項服務可以清理代碼,需要較少的環境變量即可連接到每項服務。
原文標題:How to Migrate to PlanetScale’s Serverless Database,作者:Lee Robinson
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】