Blog AWS Indonesia

Memindahkan aplikasi web ke AWS Serverless: Bagian 2

Pada bagian 1, Anda telah mempelajari bahwa melakukan migrasi sebuah aplikasi web non-serverless ke lingkungan serverless dapat dilakukan tanpa mengubah banyak kode. Anda mempelajari alat-alat berbeda yang dapat digunakan untuk membantu dalam proses migrasi ini, seperti AWS Lambda Web Adapter dan AWS Amplify.

Akan tetapi, jika Anda tes aplikasi yang telah dimigrasi ini, Anda akan menemukan dua masalah. Masalah pertama adalah sesi dari user tidak melekat. Setiap Anda login, maka Anda akan otomatis logout secara tidak terduga dari aplikasi. Masalah kedua adalah ketika Anda membuat sebuah produk baru, Anda tidak bisa mengupload gambar dari produk tersebut.

Artikel kedua ini akan menganalisa setiap masalah ini dengan detil dan menunjukkan solusinya. Sebagai tambahan, artikel ini akan menjelaskan bagaimana menyelesaikan masalah-masalah ini, juga menganalisa biaya dan performa dari solusi ini.

Migrasi autentikasi dan otorisasi

Aplikasi asli menangani autentikasi dan otorisasi secara mandiri. Terdapat daftar pengguna di dalam database, dengan password dan email dari setiap pengguna. Terdapat API dan middleware yang melakukan validasi bahwa pengguna telah terautentikasi sebelum menampilkan aplikasi. Semua bagian itu dikembangkan didalam aplikasi Node.js/Express.

Tetapi, dengan aplikasi yang baru dimigrasi, setiap kali Anda mencoba login, Anda akan terlogout secara tidak terduga dari aplikasi. Hal ini karena kode di server yang bertanggung jawab untuk menangani auentikasi dan otorisasi pengguna, dan sekarang kode tersebut berjalan di dalam sebuah fungsi AWS Lambda dan fungsi di Lambda adalah stateless. Ini artinya ada sebuah fungsi yang berjalan per request — sebuah request yang menampilkan semua produk di halaman depan, mendapatkan detil dari sebuah produk, atau masuk ke website — dan ketika Anda melakukan sesuatu dalam salah satu fungsi ini, status kondisinya tidak terbagi dengan request lain.

Untuk menyelesaikan ini, Anda harus menghapus mekanisme autentikasi dan otorisasi dari fungsi tersebut dan menggantinya dengan layanan yang dapat mempertahankan sesi di beberapa pemanggilan lintas fungsi.

Ada banyak cara menyelesaikan tantangan ini. Anda dapat menambahkan bagian autentikasi dan manajemen sesi dengan sebuah database seperti Redis, membangun microservice baru yang bertugas untuk autentikasi dan otorisasi yang dapat menangani status kondisi dari request, atau menggunakan layanan terkelola yang sudah ada untuk ini.

Karena kebutuhan dari migrasi, kita ingin biayanya serendah mungkin, dan dengan sesedikit mungkin perubahan pada aplikasi. Solusi yang lebih baik adalah dengan menggunakan layanan terkelola yang sudah ada untuk menangani autentikasi dan otorisasi.

Demo ini menggunakan Amazon Cognito, yang menyediakan layanan terkelola untuk autentikasi dan otorisasi ke sumber daya AWS dengan model harga bayar sesuai pemakaian. Cara tercepat adalah dengan mengganti semua kode di server yang berhubungan dengan autentikasi dan otorisasi ke Amazon Cognito menggunakan AWS SDK. Akan tetapi, hal ini akan menambah kompleksitas yang sebenarnya dapat digantikan sepenuhnya dengan memanggil API Amazon Cognito langsung dari aplikasi React.

Menggunakan Amazon Cognito

Sebagai contoh, ketika pengguna baru mendaftar, aplikasi akan membuat pengguna di direktori Amazon Cognito user pool, dan juga di database dari aplikasi. Tapi ketika pengguna ingin masuk ke aplikasi, maka aplikasi akan memanggil API Amazon Cognito secara langsung dari aplikasi yang ditempatkan di AWS Amplify. Cara ini meminimalkan jumlah kode yang dibutuhkan.

Pada aplikasi asli, semua API di server yang membutuhkan autentikasi diamankan menggunakan middleware yang memvalidasi apakah pengguna terautentikasi dengan cara menyediakan access token. Dengan cara baru ini hal tersebut tidak berubah, tapi bedanya token akan dihasilkan oleh Amazon Cognito, kemudian token tersebut dapat divalidasi di sisi backend.

let auth = (req, res, next) => {
    const token = req.headers.authorization;
    const jwtToken = token.replace('Bearer ', '');

    verifyToken(jwtToken)
        .then((valid) => {
            if (valid) {
                getCognitoUser(jwtToken).then((email) => {
                    User.findByEmail(email, (err, user) => {
                        if (err) throw err;
                        if (!user)
                            return res.json({
                                isAuth: false,
                                error: true,
                            });

                        req.user = user;
                        next();
                    });
                });
            } else {
                throw Error('Not valid Token');
            }
        })
        .catch((error) => {
            return res.json({
                isAuth: false,
                error: true,
            });
        });
};

Anda dapat melihat langkah demi langkah bagaimana implementasi ini dilakukan dalam video ini.

Migrasi storage

Pada aplikasi asli, ketika sebuah produk dibuat, gambar akan diupload ke server Node.js/Express. Namun, sekarang aplikasi berada disebuah fungsi Lambda. Kode (dan file-file) yang menjadi bagian dari fungsi tersebut tidak dapat berubah, kecuali fungsinya di-deploy ulang. Konsekuensinya, Anda harus memisahkan penyimpanan data user dari server.

Untuk melakukan ini, ada beberapa solusi: menggunakan Amazon Elastic System (EFS) atau Amazon S3. EFS adalah sebuah penyimpanan file, dan dapat Anda gunakan untuk penyimpanan data secara dinamis ketika Anda mengupload gambar baru. Penggunaan EFS tidak memerlukan banyak perubahan kode, karena implementasi asli menggunakan direktori di dalam server seperti yang disediakan EFS. Tetapi, menggunakan EFS menambah kompleksitas ke aplikasi, karena fungsi yang menggunakan EFS harus berada didalam sebuah Amazon Virtual Private Cloud (Amazon VPC).

Menggunakan S3 untuk mengupload gambar ke aplikasi lebih sederhana, karena hanya butuh sebuah S3 bucket. Untuk melakukan ini, Anda harus melakukan refactor aplikasi, dari sebelumnya gambar diupload ke API aplikasi diganti menjadi menggunakan library dari AWS Amplify yang mengupload dan mengambil gambar dari S3.

export function uploadImage(file) {
    const fileName = `uploads/${file.name}`;

    const request = Storage.put(fileName, file).then((result) => {
        return {
            image: fileName,
            success: true,
        };
    });

    return {
        type: IMAGE_UPLOAD,
        payload: request,
    };
}

Keuntungan utama ketika menggunakan S3 adalah Anda dapat juga menggunakan Amazon CloudFront untuk mempercepat proses pengambilan gambar dari cloud. Dengan cara ini, Anda dapat mempercepat waktu loading dari halaman web Anda. Anda dapat melihat bagaimana ini diimplementasikan langkah demi langkah dalam video ini.

Berapa biaya untuk aplikasi ini?

Jika Anda deploy aplikasi ini pada sebuah akun AWS yang masih kosong, kebanyakan penggunaan dari aplikasi ini tertutupi oleh AWS Free Tier. Layanan-layanan serverles, seperti AWS Lambda dan Amazon Cognito, memiliki free tier selamanya yang memberikan Anda keuntungan selama masa hosting aplikasi.

  • AWS Lambda — dengan 100 request per jam, rata-rata 10ms invokasi, dan konfigurasi memori 1 GB, biaya yang diperlukan 0 USD per bulan.
  • Amazon S3 — menggunakan S3 Standard, hosting 1 GB per bulan dan 10k PUT dan GET request per bulan akan memakan biaya 0.07 USD per bulan. Ini bisa dioptimalkan dengan menggunakan S3 Intelligent-Tiering.
  • Amazon Cognito — Menyediakan 50.000 monthly active users (MAU) secara gratis.
  • AWS Amplify — Jika Anda deploy aplikasi seminggu sekali, 3 GB data transfer out, dan menyimpan 1 GB data per bulan, akan memakan biaya 0.87 USD.
  • AWS Secret Manager — Ada dua secret yang disimpan di Secret Manager dengan biaya 1.16 USD per bulan. Ini dapat dioptimasi dengan menggunakan AWS System Manager Parameter Store dan AWS Key Management Service (AWS KMS).
  • MongoDB AtlasSelamanya gratis untuk shared cluster.

Total biaya bulanan untuk aplikasi ini sekitar 2.11 USD.

Analisis performa

Setelah Anda memigrasikan aplikasi, Anda dapat menjalankan page speed insight untuk mengukur performa dari aplikasi ini. Alat ini menyediakan hasil tentang frontend dan bagaimana pengalaman yang dialami pengguna. Hasilnya seperti yang ditampilkan pada gambar berikut. Performa website ini bagus, berdasarkan performa skor yang dinilai oleh alat ini — website merespon secara cepat dan pengalaman pengguna juga bagus.

Hasil tes dari page speed insight

Setelah aplikasi dimigrasi ke lingkungan serverless, Anda dapat melakukan refactoring untuk lebih meningkatkan keseluruhan performa. Satu contoh adalah ketika sebuah gambar diupload, gambar tersebut otomatis diubah ukuran dan formatnya ke dalam format baru secara otomatis menggunakan kapabilitas event drivent yang disediakan oleh S3. Contoh lainnya adalah menggunakan Lambda@Edge untuk memformat gambar secara on-the-fly menjadi ukuran yang optimal sesuai perangkat pengguna.

Anda juga bisa menjalankan uji beban untuk mengetahui seberapa bagus performa dari backend dan database. Untuk ini, Anda dapat menggunakan Artillery, sebuah library open source yang memungkinkan Anda melakukan uji beban. Anda dapat menjalankan tes uji beban dengan perkiraan beban maksimum yang dapat ditangani dan memastikan website mampu mengatasinya.

Sebagai contoh, Anda dapat mengkonfigurasi sebuah tes yang mengirim 30 request per detik untuk melihat bagaimana aplikasi merespon:

config:
  target: 'https://xxx.lambda-url.eu-west-1.on.aws'
  phases:
    - duration: 240
      arrivalRate: 30
      name: Testing
scenarios:
  - name: 'Test main page'
    flow:
      - post:
          url: '/api/product/getProducts/'

Tes ini dilakukan untuk sisi API backend, ini tidak hanya melakukan tes pada backend tapi juga integrasinya dengan MongoDB. Setelah menjalankannya, Anda dapat melihat bagaimana performa dari fungsi Lambda di dashboard Amazon CloudWatch.

Menjalankan uji beban membantu Anda untuk memahami batasan dari sistem Anda. Sebagai contoh, jika Anda menjalankan tes dengan terlalu banyak pengguna bersamaan, Anda akan melihat throttling pada fungsi Anda meningkat. Ini berarti Anda perlu meningkatkan batasan pemanggilan dari fungsi yang bisa berjalan secara bersamaan.

Atau ketika meningkatkan request per detik, Anda mungkin menemukan bahwa kluster MongoDB mulai membatasi request Anda. Ini karena Anda menggunakan free tier yang memiliki batasan jumlah koneksi. Anda mungkin butuh kluster yang lebih besar atau migrasi database ke layanan lain yang menyediakan free tier yang lebih besar, seperti Amazon DynamoDB.

Kesimpulan

Pada bagian dua artikel ini, Anda telah mempelajari jika migrasi aplikasi non-serverless ke lingkungan serverlesss dapat dilakukan tanpa mengubah banyak kode. Anda mempelajari alat-alat berbeda yang dapat digunakan untuk membantu dalam proses migrasi ini, seperti AWS Lambda Web Adapter dan AWS Amplify, dan bagaimana menyelesaikan tantangan-tantangan yang ada, seperti storage dan autentikasi.

Setelah aplikasi ditempatkan di lingkungan serverless secara penuh, aplikasi dapat melakukan scaling secara otomatis sesuai kebutuhan. Aplikasi ini juga memiliki performa yang bagus ketika backend ditempatkan di sebuah fungsi Lambda.

Jika dibutuhkan, dari sini Anda dapat mulai migrasi dengan menggunakan pola strangler untuk me-refactor aplikasi dan mendapatkan keuntungan dari arsitektur event-driven.

Untuk melihat semua langkah dari migrasi, terdapat playlist yang berisi semua panduan yang dapat Anda ikuti.

Untuk sumber belajar lain tentang serverless, kunjungi Serverless Land.

Artikel ini diterjemahkan dari artikel dengan judul Lifting and shifting a web application to AWS Serverless: Part 2 yang ditulis oleh Marcia Villalba, Principal Developer Advocate, AWS.

TAGS:
Rio Astamal

Rio Astamal

Rio Astamal is a Developer Advocate at AWS and a passionate web developer since 2003. In his spare time he loves writing small open source projects to solve problem in his daily activity.