Anda Mungkin Tidak Membutuhkan Redis Dengan Elixir

Informasi

Anda Mungkin Tidak Membutuhkan Redis Dengan Elixir – Jika Anda telah berpartisipasi dalam diskusi tentang Elixir, Anda mungkin pernah mendengar “Anda mungkin tidak membutuhkan Redis dengan Elixir”. Mengingat Redis memiliki banyak kasus penggunaan, kalimat ini mungkin membingungkan pengembang saat mereka mencoba mencocokkan fitur Elixir yang berbeda dengan kemampuan Redis. Artikel ini bertujuan untuk mengeksplorasi berbagai skenario di mana hal di atas benar, ketika tidak, dan trade off mana yang mungkin ingin Anda pertimbangkan. Kami akan membahas empat kasus. Sebelum kita mulai, saya ingin menekankan bahwa kami menemukan Redis sebagai bagian dari teknologi yang fantastis.

Anda Mungkin Tidak Membutuhkan Redis Dengan Elixir

Ini bukan kritik terhadap Redis melainkan diskusi tentang berbagai opsi yang mungkin tersedia oleh pengembang Elixir.

1. PubSub Terdistribusi

elixir-memory – Skenario pertama di mana Anda mungkin tidak memerlukan Redis dengan Elixir adalah Distributed PubSub . Sepanjang bagian ini, kami akan mempertimbangkan sistem PubSub untuk menyediakan pengiriman paling banyak satu kali : mereka menyiarkan acara ke pelanggan yang tersedia saat ini. Jika pelanggan tidak ada, mereka tidak akan menerima pesan nanti. Untuk alasan ini, sistem PubSub sering dipasangkan dengan database untuk menawarkan kegigihan. Misalnya, setiap kali seseorang mengirim pesan dalam aplikasi obrolan, sistem dapat menyimpan konten ke database dan kemudian menyiarkannya ke semua pengguna. Ini berarti semua orang yang terhubung pada saat tertentu segera melihat pembaruan, tetapi pengguna yang tidak terhubung dapat menyusul nanti.

Di 200LOC atau kurang , Anda dapat menerapkan sistem PubSub yang menyiarkan ke semua pelanggan dalam node yang sama atau di mana pun dalam kluster, tanpa membawa alat pihak ketiga apa pun. Paling-paling, Anda akan memerlukan libcluster perpustakaan Elixir untuk membuat koneksi antara node berdasarkan beberapa strategi (K8s, AWS, DNS, dll). Dengan kata lain, PubSub cukup banyak dikirimkan dengan Elixir. Teknologi tanpa distribusi harus bergantung pada Redis PubSub, PostgreSQL Notifications, atau sejenisnya untuk mencapai hal yang sama. Tentu saja, asumsi di atas bahwa infrastruktur Anda memungkinkan Anda untuk secara langsung membangun koneksi antar node, yang mungkin tidak dapat dilakukan di beberapa PaaS, seperti Heroku. Dalam kasus tersebut, Anda dapat menggunakan salah satu teknologi di atas (Phoenix memiliki adaptor Redis untuk PubSub-nya), atau sebagai alternatif, menggunakan platform, seperti Gigalixir yang memudahkan penyiapan kluster.

Baca Juga : 5 Alasan Elixir Bisa Menjadi Keunggulan Kompetitif Anda

2. Kehadiran

Kehadiran adalah kemampuan untuk melacak siapa yang terhubung dalam sebuah cluster sekarang siapa yang mungkin pengguna, telepon, perangkat IoT, dll. Misalnya, jika Alice terhubung ke node A, dia ingin melihat bahwa Bob juga tersedia, bahkan jika dia telah bergabung dengan simpul B. Kehadiran adalah salah satu masalah yang lebih rumit untuk diterapkan daripada kedengarannya. Sebagai contoh, mari kita pertimbangkan untuk mengimplementasikan Kehadiran dengan menyimpan entitas yang terhubung dalam database. Namun, apa yang terjadi jika sebuah node crash atau meninggalkan cluster? Karena node tersebut mogok, semua pengguna yang terhubung dengannya harus dihapus, tetapi node itu sendiri tidak dapat melakukannya. Oleh karena itu node lain perlu mendeteksi skenario kegagalan tersebut dan bertindak sesuai dengan itu. Tetapi mengamati kegagalan dalam sistem terdistribusi juga rumit, bagaimana Anda membedakan antara simpul sementara yang tidak responsif dari simpul yang gagal secara permanen?

Pendekatan umum lainnya untuk mengatasi masalah ini adalah dengan sering menulis ke database saat pengguna terhubung. Jika Anda tidak melihat penulisan dalam jangka waktu tertentu, Anda menganggap pengguna tersebut terputus. Namun, solusi semacam itu harus memilih antara menulis intensif atau tidak akurat. Misalnya, pengguna menjadi terputus setelah 1 menit. Ini berarti Anda perlu menulis ke database setiap 1 menit untuk setiap pengguna. Jika Anda memiliki 10k pengguna, itu berarti 167 penulisan per detik, hanya untuk melacak bahwa pengguna terhubung. Sementara itu, jarak antara pengguna yang keluar dan status mereka tercermin di UI, dalam skenario terburuk, juga 1 menit. Upaya apa pun untuk mengurangi jumlah penulisan menyiratkan peningkatan kesenjangan.

Dengan dukungan pengelompokan Elixir, kami sekali lagi dapat mengimplementasikan Kehadiran tanpa perlu ketergantungan pihak ketiga. Kami menggunakan sistem PubSub untuk mengimplementasikan Kehadiran, karena kami perlu memberi tahu saat pengguna bergabung dan keluar. Alih-alih mengandalkan penyimpanan terpusat, node secara langsung berkomunikasi dan bertukar informasi tentang siapa yang ada di sekitarnya. Ini menghilangkan kebutuhan untuk sering menulis. Saat pengguna pergi, ini juga langsung terlihat. Jadi, meskipun Anda dapat menggunakan Redis atau penyimpanan lain untuk menyediakan Kehadiran, Elixir dapat memberikan solusi yang efisien dan tidak memerlukan alat pihak ketiga.

3. Caching

Solusi untuk kasus sebelumnya dibangun di atas kemampuan distribusi unik Erlang. Pada bagian berikut, faktor pembeda antara membutuhkan Redis atau tidak adalah multi core concurrency, sehingga diskusi ini lebih dapat diterapkan secara umum. Oleh karena itu, ketika kami mengatakan Elixir di bagian ini, itu juga akan berlaku untuk JVM, Go, dan lingkungan lainnya. Mereka akan kontras dengan Ruby, Python, dan Node.js, di mana runtime utama mereka tidak menyediakan konkurensi multi core yang memadai dalam satu proses Sistem Operasi. Mari kita mulai dengan skenario yang tidak bersamaan. Pertimbangkan Anda sedang membangun aplikasi web di Ruby, Python, dll. Untuk menyebarkannya, Anda mendapatkan dua mesin delapan inti. Dalam bahasa yang tidak memberikan konkurensi multi inti yang memuaskan, opsi umum untuk penerapan adalah memulai 8 instance aplikasi web Anda, satu per inti, pada setiap node. Secara keseluruhan, Anda akan memiliki instance CxN, di mana C adalah jumlah core, dan N adalah jumlah node.

Sekarang pertimbangkan operasi tertentu dalam aplikasi ini yang mahal, dan Anda ingin men-cache hasilnya. Solusi termudah, terlepas dari lingkungan pemrograman Anda, adalah menyimpannya di memori. Namun, mengingat kami memiliki 16 contoh aplikasi ini, menyimpannya di memori kurang optimal, kami harus melakukan operasi mahal ini setidaknya 16 kali, satu untuk setiap contoh. Untuk alasan ini, penggunaan Redis, Memcached, atau serupa untuk caching di lingkungan seperti Ruby, Python, dll. Dengan Redis, Anda akan men-cache hanya sekali, dan itu akan dibagikan di semua instance. Pertukarannya adalah kami mengganti akses memori dengan jaringan pulang pergi, dan yang terakhir adalah urutan besarnya lebih mahal.

Sekarang mari kita pertimbangkan lingkungan dengan konkurensi multi inti. Dalam bahasa seperti Elixir, Anda memulai satu instance per node, terlepas dari jumlah core, karena runtime akan berbagi memori dan secara efisien menyebarkan pekerjaan ke semua core. Dalam hal caching, menyimpan cache di memori adalah skenario yang jauh lebih terjangkau, karena Anda hanya perlu menghitung sekali per node. Oleh karena itu, Anda memiliki opsi untuk melewati Redis atau Memcached sama sekali dan menghindari jaringan bolak-balik. Tentu saja, ini tergantung pada berapa banyak node yang Anda jalankan secara efektif dalam produksi. Untungnya, banyak perusahaan melaporkan dapat menjalankan Elixir dengan urutan node yang lebih kecil daripada teknologi tempat mereka bermigrasi.

Anda juga dapat memilih pendekatan campuran dan menyimpan cache baik di dalam memori maupun di Redis. Pertama, Anda mencari di memori dan, jika hilang, Anda mundur ke Redis. Jika tidak tersedia di keduanya, maka Anda menjalankan operasi dan menyimpannya di masing-masing. Bagian penting untuk disorot di sini adalah bahwa lingkungan multi-inti memberi Anda lebih banyak fleksibilitas untuk mengatasi masalah ini sekaligus mengurangi pemanfaatan sumber daya. Di Elixir/Erlang, Anda juga dapat menyimpan cache di memori dan menggunakan PubSub untuk mendistribusikannya ke seluruh node. Anda dapat melihat pendekatan terakhir ini beraksi di perpustakaan FunWithFlags yang luar biasa. Pertukaran lain yang perlu dipertimbangkan adalah bahwa semua cache dalam memori akan hilang setelah Anda menerapkan node baru. Oleh karena itu, jika Anda memerlukan data untuk bertahan di seluruh penerapan, Anda akan ingin menggunakan Redis sebagai lapisan cache, seperti yang dijelaskan di atas, atau membuang cache di penyimpanan, seperti database, S3, atau Redis, sebelum setiap penerapan.

4. Pemrosesan Asinkron

Skenario lain yang mungkin tidak Anda perlukan Redis di Elixir adalah melakukan pemrosesan asinkron. Mari kita lanjutkan pembahasan dari kasus sebelumnya. Dalam lingkungan tanpa atau dengan konkurensi multi inti terbatas, mengingat setiap instans ditugaskan ke satu inti, mereka terbatas dalam kemampuannya untuk menangani permintaan secara bersamaan. Ini mengarah pada pepatah umum bahwa Anda harus menghindari pemblokiran utas utama. Misalnya, bayangkan aplikasi Anda harus mengirimkan email saat mendaftar atau menghasilkan beberapa laporan yang mahal secara komputasi. Saat salah satu dari 16 instans web Anda melakukan ini, itu tidak dapat menangani permintaan masuk lainnya secara efisien. Untuk alasan ini, pilihan umum di sini adalah memindahkan pekerjaan ke tempat lain, biasanya antrian pemrosesan pekerjaan latar belakang. Pertama, Anda menyimpan pekerjaan yang harus dilakukan di Redis atau serupa. Kemudian salah satu dari 16 contoh web (atau lebih umum satu set pekerja yang sama sekali berbeda) mengambilnya dari antrian.

Dalam lingkungan konkuren multi inti, permintaan dapat ditangani secara bersamaan terlepas dari apakah mereka melakukan pekerjaan CPU atau IO. Mengirim email dari permintaan itu sendiri tidak akan memblokir permintaan lain. Membuat laporan tidak menjadi masalah, karena permintaan dapat dilayani oleh CPU lain. Platform ini biasanya mendapatkan permintaan sebanyak yang dapat mereka tangani dan mereka mendistribusikan pekerjaan melalui sumber daya mesin. Bahkan jika Anda lebih suka mengirim email di luar permintaan, untuk mengirim respons lebih awal kepada pengguna, Anda dapat memunculkan pekerja asinkron tanpa perlu memindahkan pengiriman ke antrean eksternal atau ke komputer lain. Sekali lagi, konkurensi memberi kita opsi yang lebih mudah untuk menangani skenario ini. Perhatikan bahwa Erlang VM menangani pekerjaan CPU dan IO multiplexing tanpa perlu pengembang menandai fungsi sebagai asinkron atau serupa. Pekerja di Erlang/Elixir juga bersifat preemptive, jadi tidak mungkin sekelompok pekerja membuat semua sumber daya mesin kelaparan dan menghalangi pekerja lain untuk melanjutkan tugas mereka. Sangat mirip dengan bagaimana Sistem Operasi mengelola proses mereka sendiri, meskipun jauh lebih ringan.

Ada satu peringatan besar di sini yaitu antrian pemrosesan pekerjaan latar belakang sering datang dengan beberapa fitur, seperti percobaan ulang, visibilitas pekerjaan, dll. Jika Anda memerlukan salah satu dari fitur ini, maka saya sangat menyarankan menggunakan alat yang bergantung pada penyimpanan dan menyediakan semua lonceng dan peluit. Perhatikan bahwa alat pekerjaan latar belakang dapat menggunakan Redis, seperti Elixir’s exq, tetapi tidak perlu. Mereka dapat menggunakan database, seperti yang terlihat di Oban, atau sistem pesan konvensional, seperti RabbitMQ atau Amazon SQS. Bagaimanapun, untuk sesuatu yang sepele seperti mengirim email di Elixir, saya akan mengirim email dalam permintaan, terutama jika pengguna perlu membuka email sebelum melanjutkan. Peringatan ini telah menyebabkan beberapa kebingungan, di mana beberapa orang akan mengklaim bahwa Anda tidak memerlukan pekerjaan latar belakang di Elixir, yang dapat menyesatkan. Di Elixir, itu adalah pilihan yang Anda buat ketika kebutuhan Anda menuntut demikian, tetapi itu bukan keharusan sejak hari pertama.

Saya ingin menyelesaikan bagian ini dengan kisah salah satu pertunjukan konsultasi terakhir saya sebagai pengembang Ruby karena ini adalah contoh yang tepat ketika pekerjaan latar belakang bukanlah jawaban dan bahkan bisa berbahaya. Pertunjukan itu dengan perusahaan yang memiliki masalah skalabilitas dengan Ruby. Secara khusus, masalah mereka terkait dengan pemrosesan pembayaran. Mereka harus berintegrasi dengan pemroses pembayaran tertentu, yang seringkali membutuhkan waktu 3 detik untuk menangani permintaan. Sesuai di atas, sementara server Ruby mereka sedang menunggu prosesor pembayaran, mereka tidak dapat melakukan pekerjaan lain, yang memperlambat layanan mereka. Tindakan pertama mereka adalah meningkatkan jumlah server. Namun, karena aplikasi memperoleh pengguna, latensi masih tidak dapat diprediksi, operasi menjadi lebih rumit, sering kali membebani bagian lain dari arsitektur mereka, yang menyebabkan banyak waktu pengembangan yang terhenti.

Mereka mencoba menggunakan server web berulir tetapi tidak mengatasi masalah dengan memuaskan. Mereka juga mengeksplorasi pindah ke JRuby, yang akan memecahkan masalah pada tingkat runtime, tetapi mereka memiliki sedikit pengalaman mengoperasikan VM Java, yang menghalangi mereka untuk bermigrasi. Solusi cepat (dan praktik umum) adalah memindahkan pemrosesan pembayaran ke pekerjaan latar belakang. Namun, jika pemrosesan gagal, mereka tidak bisa hanya mencoba kembali pekerjaan itu. Karena persyaratan pemrosesan pembayaran, input pengguna diperlukan pada setiap upaya. Jadi ketika gagal, mereka memilih untuk mengirim email ke pengguna dengan tautan untuk mencoba lagi, yang pada akhirnya memengaruhi tingkat konversi mereka. Ketika kami dibawa untuk mengerjakan sistem, kami mengembangkan aplikasi terpisah untuk berkomunikasi dengan pemroses pembayaran, sehingga kami dapat menskalakannya secara terpisah dan mencoba opsi penerapan yang berbeda dengan dampak minimal. Kemudian kami menambahkan polling sisi klien untuk melihat status pembayaran saat diproses. Masalahnya telah diatasi, tetapi menghabiskan ratusan jam waktu pengembangan dan kehilangan pendapatan sampai mereka menemukan solusi. Kesulitan yang tidak akan ada di platform dengan alat yang kaya dan kuat untuk pemrosesan asinkron dan konkurensi.

Ringkasan

Dalam artikel ini, kami membahas kasus di mana Anda dapat mengurangi kompleksitas operasional Anda dengan menggunakan fitur yang dikirimkan sebagai bagian dari Elixir. Tujuannya adalah untuk memberikan referensi mendalam yang dapat ditautkan oleh pengembang ketika seseorang mengatakan bahwa Anda mungkin tidak memerlukan Redis di Elixir. Jika saya harus meringkas kesamaan dari semua kasus, jawabannya adalah keadaan fana. PubSub, caching, dll. semuanya bersifat sementara. PubSub mengirimkan pesan kepada siapa yang tersedia saat ini. Kehadiran membuat siapa yang terhubung sekarang. Apa pun yang di-cache bisa hilang dan dihitung ulang. Oleh karena itu, jika Anda memiliki data sementara di Elixir, kemungkinan besar Anda mungkin tidak memerlukan Redis. Namun, jika Anda perlu mempertahankan atau mencadangkan status ini, Redis atau basis data lainnya akan berguna. Perlu juga dikatakan bahwa, jika Anda lebih suka hanya menggunakan Redis, untuk alasan apa pun, lanjutkan dan gunakan Redis! Anda tentu tidak akan sendirian saat Anda bergabung dengan perusahaan lain yang menggunakan perpustakaan seperti Redix untuk menjalankan Elixir dan Redis bersama-sama dalam produksi.

Leave a Reply