Pengantar Reliable Actor Service Fabric

Reliable Actor adalah kerangka kerja aplikasi Service Fabric berdasarkan pola Virtual Actor. Reliable Actor API menyediakan model pemrograman rangkaian tunggal yang dibangun berdasarkan jaminan skalabilitas dan keandalan yang disediakan oleh Service Fabric.

Apa itu Aktor?

Aktor adalah unit komputasi dan status independen dengan eksekusi rangkaian tunggal. Pola aktor adalah model komputasi untuk sistem bersamaan atau terdistribusi di mana sejumlah besar aktor ini dapat mengeksekusi secara bersamaan dan independen satu sama lain. Aktor dapat berkomunikasi satu sama lain dan mereka dapat menciptakan lebih banyak aktor.

Kapan menggunakan Reliable Actor

Reliable Actor Service Fabric adalah implementasi dari pola desain aktor. Seperti pola desain perangkat lunak apa pun, keputusan apakah akan menggunakan pola tertentu dibuat berdasarkan kecocokan antara masalah desain perangkat lunak dengan pola.

Meskipun pola desain aktor dapat cocok dengan sejumlah masalah dan skenario sistem terdistribusi, pertimbangan yang cermat tentang batasan pola dan kerangka kerja yang mengimplementasikannya dibuat. Sebagai panduan umum, pertimbangkan pola aktor untuk menjadi model masalah atau skenario Anda jika:

  • Ruang masalah Anda melibatkan sejumlah besar (ribuan atau lebih) unit status dan logika yang kecil, independen, dan terisolasi.
  • Anda ingin bekerja dengan objek rangkaian tunggal yang tidak memerlukan interaksi signifikan dari komponen eksternal, termasuk status kueri di seluruh set aktor.
  • Instans aktor Anda tidak akan memblokir pemanggil dengan penundaan yang tidak dapat diprediksi dengan mengeluarkan operasi I/O.

Aktor dalam Service Fabric

Dalam Service Fabric, aktor diimplementasikan dalam kerangka kerja Reliable Actor: Kerangka kerja aplikasi berbasis pola aktor yang dibangun di atas Reliable Service dalam Service Fabric. Setiap layanan Reliable Actor yang Anda tulis sebenarnya adalah Reliable Service yang dipartisi dan berstatus.

Setiap aktor didefinisikan sebagai instans jenis aktor, identik dengan cara objek .NET yang merupakan instans jenis .NET. Misalnya, mungkin ada jenis aktor yang mengimplementasikan fungsionalitas kalkulator dan mungkin ada banyak aktor jenis itu yang didistribusikan pada berbagai node di seluruh kluster. Setiap aktor diidentifikasi secara unik oleh ID aktor.

Aktor Seumur Hidup

Aktor Service Fabric adalah virtual, yang berarti masa hidupnya tidak terikat dengan representasi dalam memorinya. Akibatnya, aktor tidak perlu dibuat atau dihancurkan secara eksplisit. Runtime Reliable Actor secara otomatis mengaktifkan aktor saat pertama kali menerima permintaan untuk ID aktor tersebut. Jika seorang aktor tidak digunakan untuk jangka waktu tertentu, runtime Reliable Actor mengumpulkan sampah pada objek dalam memori. Ini juga akan menjaga pengetahuan tentang keberadaan aktor jika perlu diaktifkan kembali nantinya. Untuk detail selengkapnya, lihat siklus hidup Aktor dan pengumpulan sampah.

Abstraksi seumur hidup aktor virtual ini mengakibatkan beberapa peringatan sebagai hasil dari model aktor virtual, dan pada kenyataannya implementasi Reliable Actor terkadang menyimpang dari model ini.

  • Aktor diaktifkan secara otomatis (menyebabkan objek aktor dibangun) saat pertama kali pesan dikirim ke ID aktornya. Setelah beberapa periode waktu, objek aktor menjadi sampah yang dikumpulkan. Di masa mendatang, menggunakan ID aktor lagi, akan objek aktor baru dibangun. Kondisi aktor yang hidup lebih lama dari umur hidup objek saat disimpan dalam pengelola status.
  • Memanggil metode aktor mana pun untuk ID aktor mengaktifkan aktor tersebut. Untuk alasan ini, jenis aktor memiliki konstruktornya yang secara implisit disebut dengan runtime. Oleh karena itu, kode klien tidak dapat meneruskan parameter ke konstruktor jenis aktor, meskipun parameter dapat diteruskan ke konstruktor aktor oleh layanan itu sendiri. Hasilnya adalah bahwa pelaku dapat dibuat dalam status yang sebagian diinisialisasi pada saat metode lain dipanggil pada pelaku, jika pelaku memerlukan parameter inisialisasi dari klien. Tidak ada satu pun titik entri untuk aktivasi aktor dari klien.
  • Meskipun Reliable Actor secara implisit membuat objek aktor; Anda memiliki kemampuan untuk secara eksplisit menghapus aktor dan statusnya.

Distribusi dan failover

Untuk memberikan skalabilitas dan keandalan, Service Fabric mendistribusikan aktor ke seluruh kluster dan secara otomatis melakukan migrasi dari node yang gagal ke yang sehat sesuai kebutuhan. Ini adalah abstraksi terhadap Reliable Service yang dipartisi dan berstatus. Distribusi, skalabilitas, keandalan, dan failover otomatis semuanya disediakan berdasarkan fakta bahwa aktor berjalan di dalam Reliable Service berstatus yang disebut Layanan Aktor.

Aktor didistribusikan di seluruh partisi Layanan Aktor, dan partisi tersebut didistribusikan di seluruh node dalam kluster Service Fabric. Setiap partisi layanan berisi satu set aktor. Service Fabric mengelola distribusi dan failover partisi layanan.

Misalnya, layanan aktor dengan sembilan partisi yang disebarkan ke tiga node menggunakan penempatan partisi aktor default akan didistribusikan dengan demikian:

Distribusi Reliable Actor

Kerangka Kerja Aktor mengelola skema partisi dan pengaturan rentang kunci untuk Anda. Ini menyederhanakan beberapa pilihan tetapi juga memunculkan beberapa pertimbangan:

  • Reliable Service memungkinkan Anda memilih skema partisi, rentang kunci (saat menggunakan skema partisi rentang), dan jumlah partisi. Reliable Actor dibatasi untuk skema partisi rentang (skema Int64 seragam) dan mengharuskan Anda menggunakan rentang kunci Int64 lengkap.
  • Secara default, aktor ditempatkan secara acak ke dalam partisi yang menghasilkan distribusi seragam.
  • Karena aktor ditempatkan secara acak, diharapkan operasi aktor akan selalu memerlukan komunikasi jaringan, termasuk serialisasi dan deserialisasi data panggilan metode, menimbulkan latensi dan overhead.
  • Dalam skenario lanjutan, mengontrol penempatan partisi aktor dengan menggunakan INT64 ID aktor yang memetakan ke partisi tertentu mungkin dilakukan. Namun, melakukannya dapat mengakibatkan distribusi aktor yang tidak seimbang di seluruh partisi.

Untuk informasi selengkapnya tentang cara layanan aktor yang dipartisi, lihat konsep partisi untuk aktor.

Komunikasi aktor

Interaksi aktor didefinisikan dalam antarmuka yang dibagikan oleh aktor yang mengimplementasikan antarmuka, dan klien yang mendapatkan proksi ke aktor melalui antarmuka yang sama. Karena antarmuka ini digunakan untuk memanggil metode aktor secara tidak sinkron, setiap metode pada antarmuka harus mengembalikan Tugas.

Pemanggilan metode dan respons pada akhirnya menghasilkan permintaan jaringan di seluruh kluster, sehingga argumen dan jenis hasil tugas yang dikembalikan harus dapat diserialisasi oleh platform. Secara khusus, harus berupa kontak data yang bisa diserialisasi.

Proksi aktor

API klien Reliable Actor menyediakan komunikasi antara instans aktor dan klien aktor. Untuk berkomunikasi dengan aktor, klien membuat objek proksi aktor yang mengimplementasikan antarmuka aktor. Klien berinteraksi dengan aktor dengan memanggil metode pada objek proksi. Proksi aktor dapat digunakan untuk komunikasi klien-ke-aktor dan aktor-ke-aktor.

// Create a randomly distributed actor ID
ActorId actorId = ActorId.CreateRandom();

// This only creates a proxy object, it does not activate an actor or invoke any methods yet.
IMyActor myActor = ActorProxy.Create<IMyActor>(actorId, new Uri("fabric:/MyApp/MyActorService"));

// This will invoke a method on the actor. If an actor with the given ID does not exist, it will be activated by this method call.
await myActor.DoWorkAsync();
// Create actor ID with some name
ActorId actorId = new ActorId("Actor1");

// This only creates a proxy object, it does not activate an actor or invoke any methods yet.
MyActor myActor = ActorProxyBase.create(actorId, new URI("fabric:/MyApp/MyActorService"), MyActor.class);

// This will invoke a method on the actor. If an actor with the given ID does not exist, it will be activated by this method call.
myActor.DoWorkAsync().get();

Perhatikan bahwa dua bagian informasi yang digunakan untuk membuat objek proksi aktor adalah ID aktor dan nama aplikasi. ID aktor secara unik mengidentifikasi aktor, sementara nama mengidentifikasi aplikasi Service Fabric tempat aktor disebarkan.

Kelas ActorProxy(C#) / ActorProxyBase(Java) pada sisi klien melakukan resolusi yang diperlukan untuk menemukan aktor berdasarkan ID dan membuka saluran komunikasi dengannya. Ini juga mencoba kembali menemukan aktor dalam kasus kegagalan komunikasi dan failover. Akibatnya, pengiriman pesan memiliki karakteristik berikut:

  • Pengiriman pesan merupakan upaya terbaik.
  • Aktor mungkin menerima pesan duplikat dari klien yang sama.

Konkurensi

Runtime Reliable Actor menyediakan model akses berbasis giliran sederhana untuk mengakses metode aktor. Ini berarti tidak lebih dari satu rangkaian yang dapat aktif di dalam kode objek aktor kapan saja. Akses berbasis giliran sangat menyederhanakan sistem bersamaan karena tidak perlu mekanisme sinkronisasi untuk akses data. Artinya, sistem harus dirancang dengan pertimbangan khusus untuk sifat akses rangkaian tunggal dari setiap instans aktor.

  • Satu instans aktor tidak dapat memproses lebih dari satu permintaan sekaligus. Instance aktor dapat menyebabkan penyempitan throughput jika diharapkan untuk menangani permintaan bersamaan.
  • Aktor dapat mengalami kebuntuan satu sama lain jika ada permintaan tidak langsung antara dua pelaku, sementara permintaan eksternal dibuat untuk salah satu pelaku secara bersamaan. Waktu runtime aktor akan habis secara otomatis saat panggilan aktor dan melemparkan pengecualian kepada pemanggil untuk menginterupsi kemungkinan situasi kebuntuan.

Komunikasi Reliable Actor

Akses berbasis giliran

Giliran terdiri dari eksekusi lengkap metode aktor sebagai tanggapan atas permintaan dari aktor atau klien lain, atau eksekusi lengkap panggilan balik timer/pengingat. Meskipun metode dan panggilan balik ini asinkron, runtime Aktor tidak mencampurnya. Giliran harus sepenuhnya selesai sebelum giliran baru diizinkan. Dengan kata lain, metode aktor atau panggilan balik timer/pengingat yang saat ini sedang dijalankan harus sepenuhnya selesai sebelum panggilan baru ke metode atau panggilan balik diizinkan. Metode atau panggilan balik dianggap telah selesai jika eksekusi telah kembali dari metode atau panggilan balik dan tugas yang dikembalikan oleh metode atau panggilan balik telah selesai. Perlu ditekankan bahwa konkurensi berbasis giliran dipatuhi bahkan di berbagai metode, timer, dan panggilan balik.

Runtime Aktor memberlakukan konkurensi berbasis giliran dengan memperoleh kunci per-aktor di awal giliran dan melepaskan kunci di akhir giliran. Dengan demikian, konkurensi berbasis giliran diberlakukan berbasis per-aktor dan tidak di seluruh aktor. Metode aktor dan panggilan balik timer/pengingat bisa dieksekusi secara bersamaan atas nama aktor yang berbeda.

Contoh berikut mengilustrasikan konsep di atas. Anggap satu jenis aktor mengimplementasikan dua metode asinkron (misalnya, Method1 dan Method2), timer, dan pengingat. Diagram di bawah ini menunjukkan contoh garis waktu untuk eksekusi metode dan panggilan balik ini atas nama dua aktor (ActorId1 dan ActorId2) yang termasuk dalam jenis aktor ini.

Reliable Actor menjalankan konkurensi dan akses berbasis giliran

Diagram ini mengikuti konvensi berikut:

  • Setiap garis vertikal menunjukkan aliran logis eksekusi metode atau panggilan balik atas nama aktor tertentu.
  • Peristiwa yang ditandai pada setiap garis vertikal terjadi dalam urutan kronologis, dengan peristiwa yang lebih baru di bawah yang lama.
  • Warna yang berbeda digunakan untuk garis waktu yang cocok dengan aktor yang berbeda.
  • Penyorotan digunakan untuk mengindikasikan durasi untuk kunci per aktor ditahan atas nama metode atau panggilan balik.

Beberapa poin penting yang harus dipertimbangkan:

  • Sementara Method1 dijalankan atas nama ActorId2 sedang merespons permintaan klien xyz789, permintaan klien lainnya (abc123) tiba yang juga meminta Method1 dieksekusi oleh ActorId2. Namun, eksekusi kedua Method1 tidak dimulai sampai eksekusi sebelumnya selesai. Demikian pula pengingat yang terdaftar ActorId2 menyala saat Method1 dijalankan sebagai respons terhadap permintaan klien xyz789. Panggilan balik pengingat jalankan hanya setelah kedua eksekusi Method1 selesai. Semua ini karena konkurensi berbasis giliran yang diberlakukan untuk ActorId2.
  • Sama halnya konkurensi berbasis giliran yang juga diberlakukan untuk ActorId1, yang ditunjukkan sebagai eksekusi Method1, Method2, dan pemanggilan balik timer atas nama ActorId1 yang terjadi secara berulang.
  • Eksekusi Method1 atas nama ActorId1 tumpang tindih dengan eksekusi atas nama ActorId2. Ini karena konkurensi berbasis giliran hanya diberlakukan dalam satu aktor dan tidak di seluruh aktor.
  • Dalam beberapa metode/eksekusi panggilan balik Task(C#) / CompletableFuture(Java) dikembalikan oleh metode/panggilan balik yang selesai setelah metode kembali. Di beberapa yang lain, operasi asinkron telah selesai pada saat metode/panggilan balik kembali. Dalam kedua kasus, kunci per-aktor dirilis hanya setelah metode/panggilan balik kembali dan operasi asinkron selesai.

Masuknya kembali

Runtime Aktor memungkinkan masuknya kembali secara default. Ini berarti bahwa jika metode aktor Aktor A memanggil metode pada Aktor B, yang pada gilirannya memanggil metode lain pada Aktor A, metode itu diizinkan untuk dijalankan. Ini karena ini adalah bagian dari konteks rantai panggilan logis yang sama. Semua timer dan panggilan pengingat dimulai dengan konteks panggilan logis baru. Lihat masuknya kembali Reliable Actor untuk detail selengkapnya.

Cakupan jaminan konkurensi

Runtime Aktor memberikan jaminan konkurensi ini dalam situasi di mana ia mengontrol pemanggilan metode ini. Misalnya, ini memberikan jaminan untuk pemanggilan metode yang dilakukan sebagai respons terhadap permintaan klien, serta untuk timer dan panggilan balik pengingat. Namun, jika kode aktor secara langsung memanggil metode ini di luar mekanisme yang disediakan oleh runtime Aktor, maka runtime tidak dapat memberikan jaminan konkurensi. Misalnya, jika metode dipanggil dalam konteks beberapa tugas yang tidak terkait dengan tugas yang dikembalikan oleh metode aktor, runtime tidak dapat memberikan jaminan konkurensi. Jika metode ini dipanggil dari alur yang dibuat aktor sendiri, maka runtime juga tidak dapat memberikan jaminan konkurensi. Oleh karena itu, untuk melakukan operasi latar belakang, aktor harus menggunakantimer aktor dan pengingat aktor yang mematuhi konkurensi berbasis giliran.

Langkah berikutnya

Mulailah dengan membangun layanan Reliable Actor pertama Anda: