4Developers: Jak nie zasnąć na telekonferencjach? - Paweł Wrzeszcz
4Developers 2015: Orleans - aplikacje, które skalują i dystrybuują się same - Krzysztof Suszka
Transcript of 4Developers 2015: Orleans - aplikacje, które skalują i dystrybuują się same - Krzysztof Suszka
• Agendao Trochę teorii na początek
• Skalowanie aplikacji
• Actor model
• Orleans
o Podstawy implementacji
o Przykład
o Pozostałe możliwości
o Podsumowanie
source: http://pim.cpcache.com/product/228301273/funny_irish_agenda_mug.jpg
• Skalowanie
o Skalowanie wertykalne (scale up)
• Szybszy procesor, więcej pamięci
• Dobrze działa z klasycznym,
synchronicznym modelem
programistycznym
• Ograniczone technologią
o Skalowanie horyzontalne (scale out)
• Więcej rdzeni, procesorów, maszyn
• Wymaga specjalnego podejścia ze strony
programisty(wątki, synchronizacja, zakleszczenia, spójność
danych, awaryjność węzłów, opóźnienia, itd.)
• Nadal technologicznie możliwe(np. w chmurze)
Thread
Actor
behavior
state
mailbox• Actor model
o Wszystko jest aktorem
o Aktor hermetyzuje zachowanie i stan
o Aktor działa jednowątkowo
o Aktorzy nie współdzielą stanu
o Aktorzy działają współbieżnie
o Aktorzy komunikują się za pomocą
asynchronicznych wiadomości
o Użycie w praktyce: Erlang i Akka
Thread
Actor
behavior
state
mailbox
Thread
Actor
behavior
state
mailbox
Thread
Actor
behavior
state
mailbox
Thread
Actor
behavior
state
mailbox
• Orleans
o Rozproszone środowisko uruchomieniowe
• Model wirtualnych aktorów (ziarna – Grains)
• Stworzony do działania w chmurze
o Stworzony dla .Net
• Ziarna to obiekty .Net
• Komunikacja przy użyciu interfejsów .Net
• Asynchroniczność przy użyciu async/await
• Automatyczna propagacja wyjątków
o Ziarna działają w silosach (Silo)
• Automatyczne zarządzanie życiem ziaren
• Automatyczna dystrybucja ziaren
• Transparentność lokalizacyjna
Grain
Silo
source: http://video.ch9.ms/sessions/build/2014/3-641.pptx
• Wirtualne ziarnao Wszystkie ziarna zawsze istnieją
o Ziarna są automatycznie aktywowane
w momencie gdy są potrzebne
o Ziarna są automatycznie
dezaktywowane gdy przestają być
używane
o Automatyczna obsługa awarii
serwera
o Ziarna bezstanowe mogą istnieć
w wielu kopiach dla poprawy
wydajności
o Referencja do ziarna może być
przekazana na inny serwer lub
zapisana do bazy danych
#2,548,308 #1,432,717
Activation #[email protected] Activation #[email protected]
source: http://video.ch9.ms/sessions/build/2014/3-641.pptx
• Interfejs ziarna
Znacznik interfejsu ziarna
Wszystkie metody muszą być asynchroniczne
public interface IPlayerGrain : IGrain{
Task<string> GetName();Task<IGameGrain> GetCurrentGame();Task JoinGame(IGameGrain game);Task LeaveGame(IGameGrain game);
}
public class PlayerGrain : Grain, IPlayerGrain{
public async Task JoinGame(IGameGrain game){
bool canJoin = await game.CanJoin(this);if (canJoin) await gameManager.JoinGame(this, game);
}
public Task<string> GetName(){
return Task.FromResult(name);}
//...
public override Task OnActivateAsync() { … }public override Task OnDeactivateAsync() { … }
}
• Implementacja ziarna
Funkcja pomocnicza opakowująca wynik
Wywołania asynchroniczne
Metody wołane w momencie aktywacji/dezaktywacji ziarna
Klasa bazowa ziarna
• Użycie ziarna
Fabryka wygenerowana automatycznie z interfejsu IPlayerGrain
Identyfikator ziarna(long, guid lub string)
private async static Task PrintPlayerName(long grainId){
IPlayerGrain player = PlayerGrainFactory.GetGrain(grainId);string name = await player.GetName();Console.WriteLine("Player name: {0}", name);
}
• Przykład – interfejsy ziaren
public interface IDeviceGrain : IGrainWithGuidKey{
Task UpdatePosition(double latitude, double longitude);Task<IEnumerable<DeviceInfo>> GetSurroundingDevices();
}
public interface IBeaconGrain : IGrainWithGuidKey{
Task UpdateDevicePosition(Guid deviceId, double latitude, double longitude);Task Leave(Guid deviceId);Task<IList<DeviceInfo>> GetDevices();
}
Ustaw pozycję urządzenia
Pobierz urządzania w okolicy
Zarejestruj pozycję urządzenia w nadajniku
Opuść zasięg nadajnika
Pobierz listę urządzeń w zasięgu nadajnika
• Przykład – ziarno nadajnika
public class BeaconGrain : Grain, IBeaconGrain{
private Dictionary<Guid, DeviceInfo> _devices;
public async Task UpdateDevicePosition(Guid deviceId, double latitude, double longitude)
{_devices[deviceId] = new DeviceInfo(deviceId, latitude, longitude);
}
public async Task Leave(Guid deviceId)
{_devices.Remove(deviceId);
}
public async Task<IList<DeviceInfo>> GetDevices()
{return _devices.Values.ToList();
}
public override Task OnActivateAsync()
{_devices = new Dictionary<Guid, DeviceInfo>();return base.OnActivateAsync();
}}
Słownik z urządzeniami w zasięgu
Aktualizuj urządzenie w słowniku
Usuń urządzenie ze słownika
Pobierz zawartość słownika
• Przykład – ziarno urządzenia - cz. 1
public class DeviceGrain : Grain, IDeviceGrain{
private IBeaconGrain _currentBeacon;private HashSet<IBeaconGrain> _beacons;
public override Task OnActivateAsync(){
_beacons = new HashSet<IBeaconGrain>();return base.OnActivateAsync();
}
public override async Task OnDeactivateAsync(){
if (_currentBeacon != null) await _currentBeacon.Leave(this.GetPrimaryKey());await base.OnDeactivateAsync();
}
static private Guid GetBeaconId(double latitude, double longitude) { … }
public async Task<IEnumerable<DeviceInfo>> GetSurroundingDevices(){
var infos = await Task.WhenAll(_beacons.Select(b => b.GetDevices()));return infos.SelectMany(x => x).ToList();
}
// ...
Nadajnik, w którego zasięgu jest urządzenie
Lista sąsiednich nadajników, które nasłuchujemy
Dla każdego nadajnika, pobierz równolegle listę urządzeń w jego zasięguZłącz listy urządzeń w jedną
• Przykład – ziarno urządzenia - cz. 2
// ...
public async Task UpdatePosition(double latitude, double longitude)
{var beacon = BeaconGrainFactory.GetGrain(GetBeaconId(latitude, longitude));
if (!beacon.Equals(_currentBeacon))
{// different beacon - do a full initialization
if (_currentBeacon != null) await _currentBeacon.Leave(this.GetPrimaryKey());
_currentBeacon = beacon;
_beacons.Clear();for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {_beacons.Add(
BeaconGrainFactory.GetGrain(
GetBeaconId(latitude + i*latitudeBeaconOffset,longitude + j*longitudeBeaconOffset)));
}}
}
await _currentBeacon.UpdateDevicePosition(this.GetPrimaryKey(), latitude, longitude);}
}
Na podstawie pozycji pobieramy ziarno właściwego nadajnika
Czy to ten sam nadajnik co ostatnio?
Opuszczamy stary nadajnik
Zapamiętujemy nowy nadajnik
Aktualizujemy listę nadajników, które będziemy nasłuchiwać
Informujemy właściwy nadajnik o nowej pozycji
• Przykład – podsumowanie
o Prosty model przy użyciu aktorów i asynchronicznej komunikacji
o Prosta implementacja dzięki wykorzystaniu Orleans
o Skalowanie i odporność na awarie zapewnione przez Orleans
• Persystencja
<OrleansConfiguration xmlns="urn:orleans"><Globals>
<StorageProviders><Provider Type="Orleans.Storage.AzureTableStorage"
Name="StateStore"
DataConnectionString="…" />
public interface ICounterGrain : IGrain {Task<int> Increase();
}
public interface ICounterState : IGrainState {int Value { get; set; }
}
[StorageProvider(ProviderName = "StateStore")]public class CounterGrain : Grain<ICounterState>, ICounterGrain {
public async Task<int> Increase() {State.Value++;await State.WriteStateAsync();return State.Value;
}}
Konfiguracja magazynu do przechowywania stanu
Interfejs bez zmian
Definicja stanu
Wybór magazynu
Wybór definicji stanu
Odczyt stanu automatycznie podczas aktywacji ziarna
Zapis stanu
• Co jeszcze?
o Timers and Reminders
• Timers – działają gdy ziarno jest aktywne
• Reminders – działają niezależnie od aktywacji ziarna
o IGrainObserver
• Observer pattern
o Orleans Streams
• Rozszerzenie podobne do Reactive Extensions (Rx)
• Co jeszcze?
o Monitoring
• Tabele z metrykami i statystykami
• Logger
• Windows performance counters
o Activation Garbage Collection
• Konfigurowalne per klaster lub per grain
o OrleansSDK vs NuGet
o Orleans Design Patterns
• https://github.com/OrleansContrib/DesignPatterns
• Deployment
o Azure
• Azure Cloud Services Worker Role – Orleans silos
Web Role – front-end - Orleans client
• Azure Table jako magazyn danych
• Automatyczna konfiguracja
o On-premises
• Self-hosted w dowolnym procesie .Net
• SQL Server zamiast Azure
• Dostępne gotowe skrypty deployujące
Azure Cloud Service
Worker RoleWorker RoleWorker Role
silos
Web RoleWeb RoleWeb Role
WebAPI
• Orleans został stworzony do:
Scenarios• Social graphs• Mobile backend• Internet of things• Real-time analytics• ‘Intelligent’ cache• Interactive entertainment
Common characteristics• Large numbers of independent actors• Free-form relations• High throughput/low latency
• These generally dictate stateful compute
• Fine-Grained partitioning is natural• Cloud-based scale-out & elasticity• Much broader developer audience
source: http://video.ch9.ms/sessions/build/2014/3-641.pptx
• Kilka informacji na konieco Orleans jest wykorzystywany produkcyjnie w grze Halo 4
o Open Source dostępny na GitHub’ie
o Jeszcze „szorstki”, ale ciągle rozwijany i poprawiany
o Inne implementacje modelu aktorów: Akka.Net, Dotsero
• Linkio http://en.wikipedia.org/wiki/Actor_model
o https://channel9.msdn.com/Events/Build/2014/3-641
o https://github.com/dotnet/orleans
o https://dotnet.github.io/orleans/
o http://getakka.net/