Cloudflare D1 Database Sqlite3 Alpha 사용 후기

2022. 12. 10. 00:21Develop/Javascript

728x90

클라우드플레어 블로거에서 돚거한 이미지

 

Cloudflare 의 서버리스 제품에서 굉장히 오랫동안 기다려오고 D1의 예고가 등장하자마자 존버의 존버를 했던 바로 Serverless DB의 결정체 sqlite3 기반의 DB 제품입니다.

 

현재는 Alpha 버전으로만 제공하고 있지만, 현재까지 출시된 d1-ORM 이나 Prepare로 사용되는 better-sqlite3 를 사용하고 있다는 점을 보았을때는 문법의 변경은 크게 나타나지 않을 것 같습니다.

 

또한, 서버리스의 DB 이자 Sqlite3를 이용하여 Edge 단에서 동작하는 Cloudflare의 특징을 잘 살려낸 만큼 여타 서비스들과 마찬가지로 HTTP REST API를 통해 제공도 하는데, DB가 읽기 전용 토큰으로 사용해서 노출되도 괜찮다면 경우에 따라서는 클라이언트가 직접적으로 통신도 가능하다는 이야기가 됩니다. (요금 폭탄은 본인의 몫)

 

사실 위와 같은 HTTP 통신 DB가 필요로했던 가장 큰 이유는 Cloudflare Worker가 Node.js의 서버와 Web Worker의 중앙 지점의 느낌에서 동작하기 때문에, TCP 연결이 불가능 했었습니다. 이러한 상황에서 사용할 수 있는 DB로는 클라우드에서 제공해주는 HTTP DB인 Fauna, Dynamo, Arango 처럼 HTTP 를 제공해주는 DB 뿐이었죠.

 

많이 쳐줘야 Haskell로 포팅되서 만들어진 Postgresql REST API 서버가 같이 도는 것 정도 있었습니다.

 

 

 

 

D1의 Alpha 테스트는 공개적으로 진행되고 있고, D1이 먼저 공개된 서비스는

Worker보다는 Cloudflare가 주력해서 하나의 풀스택으로 묶어버리기 위해 밀고 있는 Cloudflare Pages 입니다.

Pages에서 Functions를 통해 DB와 직접적으로 통신해서 Hydration SSR 서버를 올리라고 마치 유도하는 것 같았죠.
(결국에는 Worker에도 보이기 시작했지만요)

 

 

 

 

단점

  • Sqlite3
    • sqlite3 안써본지가 5년이나 지났는데 postgresql, mysql, mariadb만 쓰다가 쓰면 Type에서 어어..? 싶은 순간이 옵니다.
    • datetime 미지원 -> Text로 선언하고, 쿼리시 datetime(created_at) 이런식으로 표현
  • 테이블 수정 불가능 
    • 웹 대시보드 상에서 아직 제공하지 않습니다.
    • cli 명령을 통해 원격 DB에 붙어서 ALTER TABLE 쿼리로 수정해야 합니다.
  • 유니크 제약사항 적용 불가
    • 위와 같은 내용입니다. 대시보드에서만 제공하지 않습니다.
    • 마찬가지로 cli 명령으로  ALTER TABLE이나 CREATE TABLE로 적용해야 합니다.
  • 데이터 확인 불가
    • 웹 대시보드 상에서 제공하지 않습니다.
    • 백업트리거가 주기적으로 동작하고 있지만, 수동으로도 가능합니다. 이를 통해 DB 덤프를 생성하여 로컬에서
      DB Browser for SQLite 같은 프로그램을 사용하여 확인할 수 있습니다.
  • d1-console 오픈소스의 불완전 함
    • 알파이니 그럴 수 있습니다...
    • 예를들면 SELECT * FROM posts 라는 쿼리를 통해 posts 테이블을 조회하는 경우 오류가 발생
    • SELECT title from posts 라는 쿼리를 날리면 한글의 경우 일부가 표기 안됨.
    • 대체방안으로 그냥 공식적으로 지원하는 wrangler d1 을 이용하는게 정신건강에 좋습니다.
  • HTTP 요청의 단점
    • 사실 http 요청은 공식 API에도 아직 게재가 안된건데 오픈소스 보고 뚫어서 사용중입니다.
    • http 요청의 경우 prepare가 없어서 직접 구현하던가 무시하고 작성해야 합니다.
    • prepare 없이 작성하는 경우 삽입하는 내용중에 ;(세미콜론) 이 포함되어 있을때 오류가 발생합니다.
    • 굳이 필요없다면 세미콜론을 잘 처리해주셔야 합니다.
    • 텍스트 삽입시 세미콜론과 마찬가지로 '(어퍼스트로피, 따옴표) 이슈가 있을 수 있습니다.
  • dev 실행시 로컬 모드 강제성
    • cloudflare pages / functions + Nuxt3 로 진행하는 중 삽질을 쥰내 했습니다.
    • dev 모드로 동작시 로컬 모드가 강제적으로 동작합니다.
    • dev 동작하기 전에 schema.sql 등을 이용하거나 exeucte 명령으로 로컬 db의 테이블을 생성해주어야 합니다.
  • Nuxt.js 연동의 부실한 설명
    • Next.js 연동 예제 오픈소스 보고 훔쳐서 발견했습니다.
    • 아래와 같이 실행해야 합니다. wrangler로 실행하는데 -- npm run dev 명령을 뒤에 붙여서
      package.json에 정의된 dev 스크립트를 실행시키게합니다.

      이렇게되면 wrangler가 실행하기전에 dev를 프록시로 먼저 실행시키고 wrangler 서버가 동작합니다.
      실행 이후 콘솔(터미널) 에서 b 를 누르면 브라우저를 띄워주는데 그 주소 및 포트가 앞으로 개발하실때 보셔야하는 주소이고 거기서만 functions에 정의한 API가 정상적으로 동작합니다.

      ex) Nuxt 기본 포트가 3000이라면, wrangler 실행시 대체로 8788포트로 실행됨.
npx wrangler@pages pages dev --local --persist -- npm run dev

 

 

 

장점

  • HTTP 로 쿼리 수행 가능
    • 일부 제한적인 환경 Cloudflare Worker 또는 다른 언어들을 사용해서 분리 개발하는데 DB는 같은 곳을 바라볼때, HTTP라는 공통된 규격이 있다는 것은 별다른 의존성없이도 가능하다는 것을 의미합니다.
  • 서버리스
    • 가장 강력한 장점입니다. 하다못해 AWS RDS 같은 것을 사용하면, 결국 수직/수평 확장에 대해서 언젠가는 고민을 해야합니다. 돈을 쳐발라서 오토스케일링을 걸던가 하는 방법이죠. 하지만 클라우드 제공사들은 DB서버는 유독 비싸게 요금을 받습니다. RDS 프리티어가 끝나면 젤 꾸진거 써도 월 75,000원 이상이 찍히는 것을 확인하실 수 있습니다.
    • Cloudflare가 관리하니 샤딩이나 성능에 대한 고려가 없습니다.
  • 전 세계 동기화
    • Cloudflare의 유일 무이한 장점입니다. AWS/Google/Oracle/IBM/Naver 를 예시로들면 해당 국가의 그것도 특정 리전내에서만 서버가 돌고 백업이되고 하기 때문에, 사용자가 결국 글로벌 서비스 진출시 타 리전까지 등록하지 않으면 클라우드 제공사들은 이를 제공해주지 않습니다.
      (극단적인 예시로, 서울/경기에 핵이떨어져서 IDC가 모두 공중분해되면 서비스가 마비되지만 Cloudflare는 가장 가까운 CDN으로 알아서 잡아줍니다. [클플은 한국 버린지 오래라 어차피 오사카/도쿄가 젤 가깝습니다.])
    • 현재는 Alpha 테스트 단계라 사용하는 국가 리전만 이용 가능합니다.
      (별다른 리전 설정은 없습니다. 가까운 리전 자동 적용)

 

아무리 쥐어짜도 장점이 더 없습니다. 그냥 DB인데 사실 가격 정책이 어떻게 정해지느냐에 따라 갈리겠지만,

서버리스 DB이니 만큼 쿼리 요청의 따른 지불 비용이 예상됩니다.

 

 

 

 

HTTP 쿼리 요청 방법

 

access token 발급 방법

https://dash.cloudflare.com/profile/api-tokens

 

 

* DB ID 발급은 그냥 DB 생성하고 해당 db 상세페이지 들어가면 보입니다.

* Account ID 확인은 Workers 탭 -> 개요 -> 우측 탭 중앙쯤에 계정 ID라고 표기되어 있습니다.

 

 

// Base URL
https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{db_id}/query

 

필수 항목

// Authorization 쓰기 싫으면 X-Auth-Key, X-Auth-Email 사용 하셔야합니다.
{
	"header": {
		"Authroization": "Bearer <access_token>"
	}
}

 

 

 

 

사용 방법

Javascript - Axios 사용

const uri = "https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{db_id}/query"
const options = {header: {Authroization: "Bearer <access_token>"}}
const payload = {sql: "SELECT * FROM <table_name>"}
axios.post(uri, payload, options)

JS로 작성하였으나, 타 언어도 동일합니다.

 

 

 

Python3 - requests 사용

import requests

uri = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{db_id}/query"
headers = {"Authroization": f"Bearer {access_token}"}

const payload = {"sql": "SELECT * FROM <table_name>"}
requests.post(uri, json=payload, headers=headers)

 

 

Go 1.19

// 필요한것만 추출한거라 직접 결과 보고 뽑으시는게 좋습니다.
type QueryResponse struct {
	Result []struct {
		Results []struct {
			// 여기 컬럼 정의 필요
		} `json:"results"`
		Success bool `json:"success"`
		Meta    struct {
			Duration      float64     `json:"duration"`
			LastRowID     interface{} `json:"last_row_id"`
			Changes       interface{} `json:"changes"`
			ServedBy      string      `json:"served_by"`
			InternalStats interface{} `json:"internal_stats"`
		} `json:"meta"`
	} `json:"result"`
}


// 알잘딱 ㅇㅈ? 솔직히 이거보고 이해못하면 go언어 삭제해야됨.
var AccountID string 
var DatabaseID string

func main() {
	target := new(QueryResponse)
	client := &http.Client{}
    
    	uri := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%s/d1/database/%s/query", AccountID, DatabaseID)
	payload, _ := json.Marshal(query)

	req, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(payload))
	req.Header.Set("content-type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", AccessToken))
    	resp, err := client.Do(req)
	if err != nil {
		log.Fatalln(err)
	}

	defer resp.Body.Close()
	_ = json.NewDecoder(resp.Body).Decode(target)
}
728x90