কম্পিউটার টিউটোরিয়াল

সার্ভারহীন আর্কিটেকচার:AWS Lambda, Upstash Redis &Go for Scalable, খরচ-কার্যকর অ্যাপ

পরিচয়

সার্ভারহীন কম্পিউট প্ল্যাটফর্মগুলি দুর্দান্ত, কিন্তু সার্ভারহীন ডেটাবেস ছাড়া সেগুলি খুব সীমিত৷

আমি যখন আমার আসন্ন কোর্স, দ্য এলিমেন্টস অফ সিআই/সিডির জন্য প্ল্যাটফর্ম তৈরি করছিলাম, তখন আমি একটি সার্ভারহীন ডাটাবেস চেয়েছিলাম যেহেতু আমি কিছু জিনিসের জন্য আমার সার্ভার হিসাবে AWS Lambda ব্যবহার করার সিদ্ধান্ত নিয়েছিলাম। আমার প্রয়োজনীয়তা ছিল:

  1. মূল্য নির্ধারণের সাথে সাথে অর্থ প্রদান করুন . আমি প্রতি ঘন্টা বা নোড প্রতি অর্থ প্রদান করতে চাই না, তবে ব্যবহারের মাধ্যমে (অনুরোধ, স্টোরেজ, ইত্যাদি)। এটি ব্যবহার করা শুরু করা খুব সস্তা হওয়া উচিত এবং ব্যবহারের র‌্যাম্প বাড়লে খরচ আনুপাতিকভাবে বাড়বে।
  2. কম বিলম্ব৷ . কেউ ধীর প্রতিক্রিয়া পছন্দ করে না, তাই AWS অঞ্চলের ভিতর থেকে ডাটাবেস অনুসন্ধান করা দ্রুত হওয়া উচিত (যেমন eu-west-1 )।
  3. অসাধারণ ডেভেলপার অভিজ্ঞতা (DevX) . অন্য একটি বিশেষ DSL না শিখে ডাটাবেসের জন্য একটি সুন্দর ইন্টারফেস থাকা, অথবা কোনো ওয়েবসাইট নিয়ে ঘন্টার পর ঘন্টা নষ্ট করা পছন্দনীয়৷

Upstash Redis উপরের সমস্ত প্রয়োজনীয়তা পূরণ করে, এবং এটি একটি দুর্দান্ত কাজ করে।

  • যেমন যেতে হবে সেভাবে অর্থ প্রদান করবেন?
    • ✅ শুরু করা সত্যিই সাশ্রয়ী, এবং স্কেলেও!
  • কম লেটেন্সি?
    • < AWS Lambda!
    • এর ভিতর থেকে প্রশ্ন করার জন্য 1ms লেটেন্সি
  • গ্রেট DevX?
    • ✅ এটি স্ট্যান্ডার্ড রেডিস। তাই, হ্যাঁ।

এই প্রবন্ধে আমরা দেখতে যাচ্ছি কিভাবে AWS Lambda থেকে Upstash Redis ব্যবহার করতে হয়, নিশ্চিত করুন যে এটি আমাদের প্রয়োজনের জন্য যথেষ্ট দ্রুত, একই সাথে স্থানীয়ভাবে পরীক্ষা করতে বা প্রয়োজনে একটি ভিন্ন প্ল্যাটফর্মে স্থাপন করতে সক্ষম হওয়ার জন্য আমাদের কোড রক্ষণাবেক্ষণযোগ্য রাখতে হবে।

আমরা কি বাস্তবায়ন করছি?

সরলতার জন্য, আমরা মাত্র 3টি API এন্ডপয়েন্ট বাস্তবায়ন করতে যাচ্ছি:

  1. GET|POST /login এন্ডপয়েন্ট যা একটি userId গ্রহণ করে একটি GET-এ একটি ক্যোয়ারী প্যারামিটার হিসাবে , অথবা POST সহ জমা দেওয়া ফর্মের মানের ভিতরে অনুরোধ এই এন্ডপয়েন্টটি একটি সেশন আইডি তৈরি করবে, এটিকে Redis-এ সঞ্চয় করবে এবং পরবর্তী ভিজিটের জন্য একটি কুকিও সেট করবে। GET শুধু পরীক্ষা করা সহজ করে তোলে।🙃
  2. GET /lessons/completed এন্ডপয়েন্টের জন্য লগ ইন করা ব্যবহারকারীদের প্রয়োজন (অর্থাৎ সেশন আইডি সহ কুকি থাকা) এবং ব্যবহারকারীর সম্পূর্ণ করা সমস্ত পাঠ সহ একটি JSON প্রতিক্রিয়া প্রদান করে এবং কখন।
  3. POST /lessons/{lessonSlug}/mark-complete এন্ডপয়েন্ট ব্যবহারকারীদের লগ ইন করা প্রয়োজন (অর্থাৎ সেশন আইডি সহ কুকি থাকা) এবং lessonSlug দ্বারা চিহ্নিত পাঠটিকে চিহ্নিত করে বর্তমান সময়ের সাথে সম্পূর্ণ।

দ্রষ্টব্য:নীচের কোডটিতে কিছু জিনিস অনুপস্থিত রয়েছে, এইভাবে এটি উত্পাদন-প্রস্তুত কপি-পেস্টযোগ্য কোড নয়। উদাহরণস্বরূপ, আমাদের দেওয়া lessonSlug চেক করা উচিত এটি আপডেট করার আগে বিদ্যমান। লগইন এন্ডপয়েন্টের একটি পাসওয়ার্ডও গ্রহণ করা উচিত এবং সেশন আইডি ইত্যাদি তৈরি করার আগে সঠিক সল্টেড/হ্যাশড যাচাইকরণ করা উচিত।

1. সেটআপ

  • নিচে বিস্তারিত সম্পূর্ণ কোডটি আমার aws-playground-এও বিদ্যমান রিপোজিটরি যদি আপনি দেখতে চান কিভাবে সবকিছু একসাথে ফিট করে।

আপনি নীচে দেখতে পাবেন, আমরা দুটি এন্ট্রিপয়েন্ট তৈরি করছি, অর্থাৎ দুটি এক্সিকিউটেবল কমান্ড। একটি হবে একটি সাধারণ স্থানীয় সার্ভারের জন্য, এবং একটি হবে AWS Lambda-এর জন্য৷ এইভাবে, আমরা স্থানীয়ভাবে আমাদের সম্পূর্ণ যুক্তি পরীক্ষা করতে সক্ষম হব, এবং আমরা চাইলে মানক ইউনিট/ইন্টিগ্রেশন পরীক্ষার মাধ্যমে।

তাদের মধ্যে পার্থক্যগুলি নীচের 1.2 এবং 1.3 বিভাগে দেখানো হয়েছে৷

1.1 ওয়ার্কস্পেস

আমরা কোডে ডুব দেওয়ার আগে, আসুন Go এর জন্য আমাদের কাজের ডিরেক্টরি সেটআপ করি৷

  1. গো ডাউনলোড করুন।
  2. আপনার পছন্দের একটি অঞ্চলে একটি Upstash Redis অ্যাকাউন্ট এবং ডাটাবেস তৈরি করুন। আদর্শভাবে এটি একই AWS অঞ্চল হওয়া উচিত যা আপনি আপনার Lambda স্থাপন করবেন। আমি eu-west-1 ব্যবহার করব (ইউরোপ, আয়ারল্যান্ড) এই নিবন্ধে।

সার্ভারহীন আর্কিটেকচার:AWS Lambda, Upstash Redis &Go for Scalable, খরচ-কার্যকর অ্যাপ

উপরেরটি সম্পূর্ণ করার পর, আমরা এখন আমাদের ওয়ার্কস্পেস তৈরি করতে পারি। বাকি নিবন্ধের জন্য, ধরে নিন আমাদের কোডটি ~/dev/aws-lambda-upstash-redis এর অধীনে .

mkdir -p ~/dev/aws-lambda-upstash-redis
cd ~/dev/aws-lambda-upstash-redis

তারপর, একটি গো প্যাকেজ তৈরি করুন:

go mod init com.upstash/example/aws-lambda-upstash-redis

1.2 স্থানীয় সার্ভার এন্ট্রিপয়েন্ট

  • নিম্নলিখিত কোডটি ~/dev/aws-lambda-upstash-redis/cmd/server/main.go এ পেস্ট করুন .
package main
 
import (
 "log"
 "net/http"
 "os"
 
 "com.upstash/example/aws-lambda-upstash-redis/core"
)
 
func main() {
 mux := core.NewMux()
 port := os.Getenv("PORT")
 if len(port) == 0 {
 port = "5000"
 }
 if err := http.ListenAndServe(":"+port, mux); err != nil {
 log.Fatal(err)
 }
}

1.3 AWS Lambda এন্ট্রিপয়েন্ট

  • নিম্নলিখিত কোডটি ~/dev/aws-lambda-upstash-redis/cmd/lambda/main.go এ পেস্ট করুন .
package main
 
import (
 "com.upstash/example/aws-lambda-upstash-redis/core"
 "github.com/aws/aws-lambda-go/lambda"
 "github.com/awslabs/aws-lambda-go-api-proxy/httpadapter"
)
 
func main() {
 mux := core.NewMux()
 lambda.Start(httpadapter.NewV2(mux).ProxyWithContext)
}

1.4 মূল যুক্তি

আমাদের মূল মূল যুক্তি core-এ যাবে উপরের উভয় এন্ট্রি পয়েন্ট দ্বারা ভাগ করা প্যাকেজ৷

  • নিম্নলিখিত কোডটি ~/dev/aws-lambda-upstash-redis/core/lib.go-এ পেস্ট করুন .
package core
 
import (
 "github.com/go-chi/chi/v5"
)
 
func NewMux() *chi.Mux {
 r := chi.NewRouter()
 return r
}

1.5 বিল্ডিং / কম্পাইলিং

আমি সাধারণত একটি ছোট makefile লিখি আমি যখনই কম্পাইল করতে চাই তখন লম্বা কমান্ড টাইপ করা এড়াতে তাই নিচেরটি ~/dev/aws-lambda-upstash-redis/makefile এ কপি করুন :

default: build
 
clean:
 rm -rf build/
 
build: build-lambda build-server
 
build-lambda: clean
 GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o build/handler cmd/lambda/main.go
 cd build/ && zip handler.zip ./handler
 
build-server: clean
 CGO_ENABLED=0 go build -o build/server cmd/server/main.go

বিস্তারিত সম্পর্কে আপাতত খুব বেশি চিন্তা করবেন না তবে এটি আমাদের করতে দেয়:

  • make build-server :স্থানীয়ভাবে সার্ভার চালানোর জন্য বাইনারি তৈরি করে (নির্বাহযোগ্য ./build/server )।
  • make build-lambda :AWS Lambda তে সার্ভার চালানোর জন্য বাইনারি তৈরি করে (এক্সিকিউটেবল ./build/handler এবং ./build/handler.zip )।
  • make অথবা make build উভয়ই করে।

CGO_ENABLED=0 বিকল্পটি নিশ্চিত করে যে আমাদের এক্সিকিউটেবল বাইনারিগুলি স্বয়ংসম্পূর্ণ (অর্থাৎ স্ট্যাটিকালি কম্পাইল করা)। GOOS=linux GOARCH=amd64 আপনি স্থানীয়ভাবে ম্যাক বা উইন্ডোজ সিস্টেম ব্যবহার করার ক্ষেত্রে AWS Lambda-এর লিনাক্স এনভায়রনমেন্ট ক্রস-কম্পাইল এবং মেলানোর জন্য বিকল্পগুলির প্রয়োজন৷

এরপর, go mod tidy চালান সমস্ত কোড নির্ভরতা আনতে। প্রতিবার আপনি Go নির্ভরতা যোগ বা সরানোর সময় এটি চালানোর কথা মনে রাখবেন।

অবশেষে, make চালান একবার, সবকিছু তৈরি করতে এবং কোডের গভীরে যাওয়ার আগে আপনার ওয়ার্কস্পেস সেটআপ করা হয়েছে তা নিশ্চিত করতে৷

2. API বাস্তবায়ন

এই বিভাগের জন্য আমরা সবসময় ~/dev/aws-lambda-upstash-redis/core/lib.go এর ভিতরে কাজ করব ফাইল।

নিম্নলিখিত কয়েকটি লাইন আশ্চর্যজনক go-chi ব্যবহার করে আমরা আগে আলোচনা করা API শেষ পয়েন্টগুলিকে সংজ্ঞায়িত করে লাইব্রেরি।

import (
 //...
 "github.com/go-chi/chi/v5"
 "github.com/go-chi/chi/v5/middleware"
)
 
func NewMux() *chi.Mux {
 r := chi.NewRouter()
 
 r.Use(middleware.RequestID)
 r.Use(middleware.Logger)
 r.Use(middleware.Recoverer)
 
 r.Get("/login", login)
 r.Post("/login", login)
 r.Group(func(r chi.Router) {
 r.Use(UsersWithSessionOnly)
 r.Get("/lessons/completed", listLessonsCompleted)
 r.Post("/lessons/{lessonSlug}/mark-complete", markLessonComplete)
 })
 
 return r
}

উপরের স্নিপেটে, r.Group(...) একটি ভাগ করা স্তর তৈরি করে যেখানে আমরা এর ভিতরে সংজ্ঞায়িত যেকোনো রুটের জন্য সাধারণ মিডলওয়্যার প্রয়োগ করতে পারি। এই ক্ষেত্রে, আমরা আমাদের নিজস্ব মিডলওয়্যার UsersWithSessionOnly যোগ করি , যা আমরা পরে দেখব গ্যারান্টি দেয় যে অনুরোধটিতে একটি সক্রিয় সেশন আইডি সহ কুকি রয়েছে৷

2.1 UsersWithSessionOnly Middleware

এই মিডলওয়্যারে আমরা নিম্নলিখিতগুলি বাস্তবায়ন করতে চাই:

  1. সেশন আইডি ধারণ করে কুকি বের করুন এবং অন্যথায় ব্যর্থ হন।
  2. সেশন আইডির উপর ভিত্তি করে ব্যবহারকারীর বিশদ সংগ্রহ করতে পুনরায় কোয়েরি করুন এবং প্রদত্ত সেশন আইডি সক্রিয় না থাকলে ব্যর্থ হয়৷
  3. অনুরোধের context.Context-এ ব্যবহারকারী আইডি সংরক্ষণ করুন ডাউনস্ট্রিম মিডলওয়্যার বা হ্যান্ডলারদের কাছে এটি উপলব্ধ করার জন্য।

প্রথমত, আমাদের কিছু আমদানি এবং সংজ্ঞার জন্য কিছু বয়লারপ্লেট কোড প্রয়োজন যা সর্বত্র ব্যবহৃত হয়।

import (
 //...
 "log"
 "os"
 "strings"
 
 "github.com/go-redis/redis/v8"
)
 
type contextKey struct {
 name string
}
const (
 COOKIE_AUTH_NAME = "xxx_session_id"
)
var (
 CTX_USER_ID = &contextKey{"LoggedInUserId"}
 redisDb = NewClient()
)
 
func NewClient() *redis.Client {
 redisUrl := strings.TrimSpace(os.Getenv("UPSTASH_REDIS_URL"))
 if redisUrl == "" {
 log.Fatalln("Required env UPSTASH_REDIS_URL not set!")
 }
 opt, _ := redis.ParseURL(redisUrl)
 redisDb := redis.NewClient(opt)
 
 return redisDb
}

এবং এখন প্রমাণীকরণ মিডলওয়্যারের প্রধান যুক্তি।

// UsersWithSessionOnly middleware restricts access to just logged-in users.
// If validation passes, then the context will contain the user id (CTX_USER_ID).
func UsersWithSessionOnly(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 c, err := r.Cookie(COOKIE_AUTH_NAME)
 if err != nil {
 render.Status(r, http.StatusForbidden)
 render.JSON(w, r, struct{}{})
 return
 }
 
 ctx := r.Context()
 userId, err := redisDb.Get(ctx, "session:"+c.Value).Result()
 if err == redis.Nil {
 // If session is not found then user is forbidden from accessing the API!
 render.Status(r, http.StatusForbidden)
 render.JSON(w, r, struct{}{})
 return
 } else if err != nil {
 // Something went wrong querying Redis!
 render.Status(r, http.StatusInternalServerError)
 render.JSON(w, r, struct{ Message string }{Message: "We could not validate the provided session ID"})
 return
 }
 // Set it for downstream middleware and handlers.
 next.ServeHTTP(w, r.WithContext(context.WithValue(ctx, CTX_USER_ID, userId)))
 })
}

2.2 মার্ক পাঠ সম্পূর্ণ(...)

এটি একটি সহজবোধ্য অপারেশন যেখানে আমরা Redis-এ সঞ্চয় করতে চাই যে পাঠটি lessonSlug দ্বারা নির্দেশিত পাথ প্যারামিটারটি অনুরোধের বর্তমান সময়ে সম্পন্ন হয়েছে।

Redis-এ আমরা প্রতিটি ব্যবহারকারীর জন্য একটি মানচিত্র রাখতে চাই যেখানে মানচিত্রের প্রতিটি কী-মূল্যের জোড়া হবে কী হিসেবে পাঠ এবং মান হিসেবে সমাপ্তির তারিখ। অতএব, আমরা HSET ব্যবহার করি রেডিস কমান্ড। আমরা প্রতি পাঠের জন্য একটি পৃথক কী সংরক্ষণ করতে পারি তবে এটি পরবর্তীতে একজন ব্যবহারকারীর জন্য সমস্ত পাঠ একবারে আনা সহজ করে তোলে।

func markLessonComplete(w http.ResponseWriter, r *http.Request) {
 ctx := r.Context()
 lessonSlug := chi.URLParam(r, "lessonSlug")
 userId := r.Context().Value(CTX_USER_ID).(string)
 timeNow := time.Now().Format(time.RFC3339)
 
 err := redisDb.HSet(ctx, "lessons:"+userId, lessonSlug, timeNow).Err()
 if err != nil {
 render.Status(r, http.StatusInternalServerError)
 render.JSON(w, r, struct{ Message string }{Message: "We could not save your progression..."})
 return
 }
 
 render.JSON(w, r, struct {
 LessonSlug string
 LastCompleted string
 }{
 lessonSlug,
 timeNow,
 })
}

2.3 তালিকা পাঠ সমাপ্ত(...)

পূর্ববর্তী বিভাগের মত অনুরূপ ফ্যাশনে, এখানে আমরা শুধু পাঠ সমাপ্তির পুরো মানচিত্রটি ফেরত দিতে চাই এবং একটি JSON প্রতিক্রিয়াতে ব্যবহারকারীকে ফেরত দিতে চাই। আমরা HGETALL ব্যবহার করি এর জন্য কমান্ড।

func listLessonsCompleted(w http.ResponseWriter, r *http.Request) {
 ctx := r.Context()
 userId := r.Context().Value(CTX_USER_ID).(string)
 
 lessons, err := redisDb.HGetAll(ctx, "lessons:"+userId).Result()
 if err == redis.Nil {
 lessons = map[string]string{}
 } else if err != nil {
 render.Status(r, http.StatusInternalServerError)
 render.JSON(w, r, struct{ Message string }{Message: "We could not load your lessons..."})
 return
 }
 
 render.JSON(w, r, struct {
 Lessons map[string]string
 }{
 lessons,
 })
}

2.4 লগইন(...)

অবশেষে, লগইন শেষ পয়েন্ট. আবারও, অনুগ্রহ করে নিম্নলিখিত কোডটি উৎপাদনে অনুলিপি করবেন না, যেহেতু এটি কোনো ধরনের বৈধতা করছে না। এই নিবন্ধটির উদ্দেশ্যে আমরা শুধুমাত্র আগ্রহী যে এটি কীভাবে রেডিসকে জিজ্ঞাসা করে এবং কীভাবে এটি সেশন আইডির জন্য কুকি সেট করে।

সেশন আইডি ksuid দ্বারা তৈরি হয় লাইব্রেরি, যার সাধারণ UUID-এর তুলনায় কিছু সুবিধা রয়েছে এবং আমরা এটিকে শুধুমাত্র 1 ঘন্টার জন্য সক্রিয় বিবেচনা করি। আমরা Redis SET-এর টাইম-টু-লাইভ কার্যকারিতা ব্যবহার করি এক ঘন্টা পরে ডাটাবেস থেকে স্বয়ংক্রিয় অপসারণের জন্য আদেশ।

import (
 // ...
 "github.com/segmentio/ksuid"
)
 
func login(w http.ResponseWriter, r *http.Request) {
 // Check credentials and update redis session and return Set-Cookie
 // WARNING: You should do an actual validation in production for credentials!
 // ...
 // For now we always assume correctness and automatically create a session token
 // by saving it to Redis, and also setting it as a cookie.
 userId := strings.TrimSpace(r.FormValue("userId"))
 if userId == "" {
 render.Status(r, http.StatusBadRequest)
 render.JSON(w, r, struct{ Message string }{Message: "Missing required userId"})
 return
 }
 
 sessionId := ksuid.New()
 redisDb.Set(r.Context(), "session:"+sessionId.String(), userId, time.Hour*1)
 http.SetCookie(w, &http.Cookie{
 Name: COOKIE_AUTH_NAME, Value: sessionId.String(),
 Path: "/", MaxAge: int((time.Hour * 1).Seconds()),
 // This should be true when deploying in production (https), but locally we need it false (http).
 Secure: false,
 })
 
 http.Redirect(w, r, "/lessons/completed", http.StatusTemporaryRedirect)
}

3. ডেমো - স্থানীয়ভাবে

উফ, এটা অনেক কোড ছিল।😅

সবকিছু আশানুরূপ কাজ করে তা নিশ্চিত করতে একটি দ্রুত ডেমো করি।

  • প্রথমে UPSTASH_REDIS_URL সেট করুন উপরের বিভাগ 1-এ আপনার তৈরি করা ডাটাবেসের URL-এর পরিবেশ পরিবর্তনশীল। আপনি এটি বিশদ বিবরণে খুঁজে পেতে পারেন৷ আপনার ডাটাবেসের পৃষ্ঠার ট্যাব (উপরে বিভাগ 1.1 দেখুন)।
export UPSTASH_REDIS_URL="<your-url-here>"
  • তারপর, স্থানীয় সার্ভার তৈরি করুন এবং চালান:
make build-server && ./build/server

ব্রাউজার টেস্টিং

এখন http://localhost:5000/lessons/completed-এ গিয়ে ব্রাউজারে কিছু পরীক্ষা করা যাক।

সার্ভারহীন আর্কিটেকচার:AWS Lambda, Upstash Redis &Go for Scalable, খরচ-কার্যকর অ্যাপ

আমরা 403 - Forbidden পাই , তাহলে আসুন, http://localhost:5000/login?userId=lambros এ গিয়ে লগইন করি।

সার্ভারহীন আর্কিটেকচার:AWS Lambda, Upstash Redis &Go for Scalable, খরচ-কার্যকর অ্যাপ

আমরা এখন লগ ইন করেছি, এবং আমরা স্বয়ংক্রিয়ভাবে /lessons/completed এ পুনঃনির্দেশিত হয়েছি , কিন্তু তারা খালি। সুতরাং, আসুন একটি পাঠকে সমাপ্ত হিসাবে চিহ্নিত করি। console-এ আপনার ব্রাউজারের devtools ভিতরে ট্যাব নিম্নলিখিত চালান:

await (
 await fetch("http://localhost:5000/lessons/123/mark-complete", {
 method: "POST",
 credentials: "same-origin",
 })
).json();
 
// Should output something like:
// {LessonSlug: '123', LastCompleted: '2022-10-12T02:01:14+03:00'}

http://localhost:5000/lessons/completed ভিজিট করা এই পাঠটিকে এখন চিহ্নিত হিসাবে দেখানো উচিত:

{ "Lessons": { "123": "2022-10-12T02:01:14+03:00" } }

এবং ভয়েলা. সবকিছু ঠিকঠাক কাজ করে!

সম্প্রতি চালু হওয়া অনলাইন ডেটা ব্রাউজার ব্যবহার করে নিজেই Redis ডাটাবেসের দিকে তাকানোও প্রমাণ করে যে প্রত্যাশিত ডেটা রয়েছে৷

সার্ভারহীন আর্কিটেকচার:AWS Lambda, Upstash Redis &Go for Scalable, খরচ-কার্যকর অ্যাপ

4. AWS Lambda

AWS Lambda তে পরীক্ষা এবং স্থাপন করার জন্য আমরা sam ব্যবহার করতে যাচ্ছি cli.

  • প্রথমে, SAM cli সেটআপ করুন এবং নিশ্চিত করুন যে আপনার ব্যবহারকারী/ ভূমিকার সঠিক অনুমতি আছে।

  • sam cli-এর কাজ করার জন্য একটি ক্লাউডফর্মেশন টেমপ্লেট প্রয়োজন, তাই aws-iac/sam-template.yml-এ নিম্নলিখিতটি অনুলিপি করুন :

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Defines all the AWS resources we need for our Upstash Redis API.
 
Resources:
 # https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html
 GoUpstashRedis:
 Type: AWS::Serverless::Function
 Properties:
 CodeUri: ../build/handler.zip
 Handler: handler
 Runtime: go1.x
 MemorySize: 512
 FunctionUrlConfig:
 AuthType: NONE
 Cors:
 AllowCredentials: false
 AllowMethods: ["*"]
 AllowOrigins: ["*"]
 
Outputs:
 GoUpstashRedisApi:
 Description: "Endpoint URL"
 Value: !GetAtt GoUpstashRedisUrl.FunctionUrl
 GoUpstashRedis:
 Description: "Lambda Function ARN"
 Value: !GetAtt GoUpstashRedis.Arn
 GoUpstashRedisIamRole:
 Description: "Implicit IAM Role created for GoUpstashRedis"
 Value: !GetAtt GoUpstashRedisRole.Arn
  • AWS Lambda-এর জন্য হ্যান্ডলার বান্ডিল তৈরি করুন:
make build-lambda
  • নিম্নলিখিতটি makefile-এ যোগ করুন আমরা কোড পরিবর্তন করার পরে এটি স্থাপন করা সহজ করতে:
sam-deploy: build-lambda
 sam deploy -t aws-iac/sam-template.yml --stack-name "UpstashRedisGoArticleStackDemo" --region eu-west-1 --resolve-s3 --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND
  • নির্দিষ্ট অঞ্চলে স্থাপন করুন (আগের কমান্ড দেখুন)।
make sam-deploy
  • আপনার নিচের মত কিছু আউটপুট পাওয়া উচিত:
CloudFormation outputs from deployed stack
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Key GoUpstashRedis
Description Lambda Function ARN
Value arn:aws:lambda:eu-west-1:<redacted>:function:UpstashRedisGoArticleStackDem-GoUpstashRedis-baB8dQPkTfg0
 
Key GoUpstashRedisIamRole
Description Implicit IAM Role created for GoUpstashRedis
Value arn:aws:iam::<redacted>:role/UpstashRedisGoArticleStac-GoUpstashRedisRole-16UWC7HR6KII8
 
Key GoUpstashRedisApi
Description Endpoint URL
Value https://6pmmwqmg5vec3bcsldabckaf5i0nlgje.lambda-url.eu-west-1.on.aws/
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 
Successfully created/updated stack - UpstashRedisGoArticleStackDemo in eu-west-1
  • নিয়োজিত AWS Lambda-এর URL প্রিন্ট করা আউটপুটে দেখানো হয়েছে, এই ক্ষেত্রে https://6pmmwqmg5vec3bcsldabckaf5i0nlgje.lambda-url.eu-west-1.on.aws/ . সুতরাং, localhost ব্যবহার করার আগে আমরা আমাদের ব্রাউজারে যে ডেমো পদক্ষেপগুলি করেছি তা নির্দ্বিধায় পুনরাবৃত্তি করুন এখন প্রকৃত ডোমেনের সাথে।
    • বিকল্পভাবে, আপনি ক্লাউডফরমেশন স্ট্যাকের আউটপুট UpstashRedisGoArticleStackDemo নতুন তৈরি ফাংশনের URL খুঁজে পেতে পারেন ক্লাউডফর্মেশন কনসোলে।
    • দ্রষ্টব্য: UPSTASH_REDIS_URL সেট করা নিশ্চিত করুন আপনার AWS Lambda কনফিগারেশনেও পরিবেশ পরিবর্তনশীল, অন্যথায় এটি ক্র্যাশ হবে। AWS Lambda কনসোলে যান, তারপরে আপনার নতুন স্থাপন করা Lambda-এ ক্লিক করুন, কনফিগারেশন-এ ক্লিক করুন ট্যাব, এবং তারপরে বাম পাশের মেনুতে পরিবেশ ভেরিয়েবল ক্লিক করুন . UPSTASH_REDIS_URL টাইপ করুন কী হিসাবে, এবং মান হিসাবে আপনার Upstash Redis URL। সংরক্ষণ করুন ক্লিক করুন৷ , এবং এখন আপনার ল্যাম্বডা প্রস্তুত।

4.1 SAM স্থানীয় পরীক্ষা

আমরা একটি sample-event.json প্রদান করে স্থানীয়ভাবে আমাদের Lambda পরীক্ষা করতে পারি সঠিক পথ/কুকি/কোয়েরি প্যারামিটার/ইত্যাদি সহ। এই ধরনের JSON-এর উদাহরণ aws-lambda-upstash-redis-article/sample-event.json-এ পাওয়া যাবে .

  • তারপর, একবার আপনার কাছে একটি বৈধ JSON ইভেন্ট ফাইল হয়ে গেলে, সার্ভার লজিক চালু করতে নিম্নলিখিতটি চালান কারণ এটি AWS Lambda-তে চলবে:
sam local invoke -t aws-iac/sam-template.yml -e sample-event.json

4.2 Upstash Redis URL এর নিরাপত্তা

এই নিবন্ধে, সরলতার জন্য আমরা পরিবেশ ভেরিয়েবলের মাধ্যমে পাসওয়ার্ড সহ Upstash Redis URL প্রদান করেছি। আমরা এটিকে SAM ক্লাউডফর্মেশন টেমপ্লেটে হার্ডকোড করতে চাই না যা আমাদের কোডের সাথে সংস্করণ করা হয়েছে, তাই কেন আমাদের এটিকে AWS Lambda কনসোলের মাধ্যমে ম্যানুয়ালি কনফিগার করতে হয়েছিল।

প্রতিবার ল্যাম্বডা কনফিগারেশন পরিবর্তন না করে স্বয়ংক্রিয়ভাবে এটি করার একটি ভাল উপায় রয়েছে এবং কনসোল অ্যাক্সেস সহ যে কারো জন্য রেডিস শংসাপত্র/URL সরল দৃষ্টিতে থাকা এড়াতে।

আমরা AWS সিস্টেম ম্যানেজার প্যারামিটার স্টোর এবং সংশ্লিষ্ট ক্লাউডফর্মেশন রিসোর্স AWS::SSM::Parameter ব্যবহার করতে পারি URL ধরে রাখতে (আমরা এটি একবার সেট করতে পারি এবং স্থাপনার সময় ধরে রাখতে পারি), এবং রানটাইমে প্যারামিটারের মান আনতে আমাদের Lambda কোড পরিবর্তন করুন। আমরা স্বয়ংক্রিয়ভাবে এটিকে sam-template.yml-এর ভিতরে একটি env ভেরিয়েবল হিসাবে ইনজেক্ট করতে পারি , যদিও এটি এখনও কনসোলে প্লেইন টেক্সটে থাকবে।

এসএসএম প্যারামিটার স্টোর থেকে কোড আনার জন্য এটিকে পরিবর্তন করা আমাদের এন্ট্রিপয়েন্টগুলির পৃথকীকরণের কারণে সহজ, তাই আমরা শুধুমাত্র AWS Lambda (~/dev/aws-lambda-upstash-redis/cmd/lambda/main.go) এর ভিতরে চলাকালীন প্যারামিটারটি আনতে পারি ) এবং এটিকে NewClient()-এ পাস করা ফাংশন যা Redis ক্লায়েন্ট তৈরি করে।

5. এটা কত দ্রুত?

প্রথম কোল্ড স্টার্ট ইনভোকেশন ছাড়াও যা মোটামুটি 100-120 ms লাগে , তার পরের প্রতিটি আমন্ত্রণ বিদ্যুত দ্রুত এবং সর্বদা 4 ms এর অধীনে .

নীচে /login?userId=lambros-এর জন্য একটি উত্তপ্ত আহ্বানের একটি উদাহরণ শেষবিন্দু উপরে প্রয়োগ করা হয়েছে:

সার্ভারহীন আর্কিটেকচার:AWS Lambda, Upstash Redis &Go for Scalable, খরচ-কার্যকর অ্যাপ

আপনি দেখতে পাচ্ছেন যে আমাদের অনুরোধের মোট সময়কাল ছিল 2.06 ms . হ্যাঁ, সেটা হল দুই মিলিসেকেন্ড , একটি সেশন আইডি তৈরি করতে, এটিকে দূরবর্তীভাবে Upstash Redis-এ লিখুন এবং পুনঃনির্দেশ প্রতিক্রিয়া ফেরত দিন৷

লগ আউটপুট-এ আরও যত্ন সহকারে দেখছেন৷ বিভাগে, আমরা দেখতে পাচ্ছি যে অনুরোধটি স্থায়ী হয়েছে 789.435μs , অন্তত আমাদের কোডের দৃষ্টিকোণ থেকে। এর মানে হল আমাদের যুক্তি 1 ms এর অধীনে ভালভাবে সম্পন্ন হয়েছে (মোটামুটি 0.790 ms ) আমরা একটি দূরবর্তী ডাটাবেস ব্যবহার করছি বিবেচনা করে মন ফুঁসে যায়।🤯

উপসংহার

Upstash Redis কতটা ভালো পারফর্ম করে তাতে আমি সত্যিই অবাক হয়েছি, বিশেষ করে যেহেতু AWS Lambda-এর মতো প্ল্যাটফর্মের জন্য উপযুক্ত সার্ভারহীন ডাটাবেসের জন্য এই ধরনের পারফরম্যান্স খুঁজে পাওয়া কঠিন।

Redis API সত্যিই সুবিধাজনক, Upstash Redis-এর রয়েছে শীর্ষস্থানীয় মূল্যের মডেল এবং দুর্দান্ত বিকাশকারী অভিজ্ঞতা, এবং এটি দ্রুত। আমি কম্বিনেশন পছন্দ করি!

AWS Lambda + Upstash Redis + Go =🚀❤️


  1. জাভাস্ক্রিপ্টে ফাংশন প্রোটোটাইপ

  2. সিএসএস অপাসিটি/স্বচ্ছতা

  3. CSS ওভারফ্লো:লুকানো

  4. ডেটাবেসলেস (ডিবিলেস) আর্কিটেকচার কী—এবং কেন এটি ভবিষ্যত