4Developers 2015: Orleans - aplikacje, które skalują i dystrybuują się same - Krzysztof Suszka

25
Krzysztof Suszka ORLEANS APLIKACJE, KTÓRE SKALUJĄ I DYSTRYBUUJĄ SIĘ SAME

Transcript of 4Developers 2015: Orleans - aplikacje, które skalują i dystrybuują się same - Krzysztof Suszka

Krzysztof Suszka

ORLEANSAPLIKACJE, KTÓRE SKALUJĄ I DYSTRYBUUJĄ SIĘ SAME

• 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 – gra społecznościowa

• Przykład – koncepcja rozwiązania

• Przykład - architektura

Azu

reLo

ad-B

alancer

Front DoorOrleans cluster

• 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

o Na własną rękę

o Ze wsparciem 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/

FUTURE PROCESSING SP. Z O.O.

44-100 Gliwice,

Bojkowska 37 A

Tel: +48 32 461 23 00

www.future-processing.com