Dağıtık Sistemler CS5001 Th. Letschert Çeviri: Turgay Akbaş TH Mittelhessen Gießen University of Applied Sciences Dağıtık Programlar ve Uygulamalar II - - 2 Katman / 3 Adım Yaklaşımı
Dağıtık Programlar Dağıtık Programlar 2.0 Senkronizasyon yerine iletişim Dağıtıklık ortak durumlar(state) için klasik yapılar, eş zamanlı programlar için program yapısı olarak görülmektedir(senkronizasyon). lokal uygulamalarda dağıtıklık : Küçük uygulamalarda da dağıtıklık gereklidir. Bu nedenle Programlama Dilleri daha kompleks bir yapı yerine dağıtık uygulamalar için gereklidirler. Dağıtık uygulamalar için programlama dilleri yeni/tekrar gündeme gelmiş yaklaşım: Diller (!) yapı tanımlamalarında iletişim kuran süreçler Süreç topolojisi bulunan açık sözdizim ve semantik barındıran. Dağıtık sistemler için programlama dilleri uzun bir geçmişe sahiptir ancak hiçbir zaman gerçekleştirilememişlerdir. Seite 2
Senkronizasyon Yerine İletişşm Ortak kaynak yasaktır(mümkün değil yerine) Birden fazla süreç(thread) tarafından paylaşılan bir durum, kompleks problemleri beraberinde getirir kompleks yapılara ihtiyaç duyar (Semafor, Muteks, Şart değişkenleri, ) test edilmeleri zordur kötü ölçeklenmiştir. Senkronizasyon yerine iletişim Ortak bir duruma sahip olmayan bir programda Mesajlar üzerinden bilgi transferinde bulunan aktif elementler (Süreçler / Threads) Ortak bir kaynak bulunmadığından dolayı senkronizasyon talimatları önemli değildir. Ortak Durum(State): kötü! Yerel durum(state): iyi! Seite 3
Aktif Monitör Olarak Buffer: Mesaj işleme süreci passiv => aktiv geçiş stratejisi Senkron çağrı => Mesaj tipi, bir yanıt gönderme, alma wait => Mesajın kaydedilmesi notify => Kayıt edilmiş mesajın işlenmesi Mesajları işle: Put-Mesajı gönder OK-Yanıt Get-Mesajı gönder Daten-Yanıt public class Buffer<TokenType> { TokenType place; boolean empty = true; synchronized void put(tokentype t) throws InterruptedException { while (! empty ) wait(); place = t; empty = false; notify(); synchronized TokenType get() throws InterruptedException { while ( empty ) wait(); empty = true; notify(); return place; Put-Mesaj göndericisiyle birlikte kaydedildi gecikmiş Get-Mesajının işlenmesi Get-Mesajı göndericisiyle birlikte kaydedildi gecikmiş Put-Mesajı işlenmesi Seite 4
Aktif monitör olarak Buffer : Mesajları işleyen süreç (Pseudocode) process Buffer { Queue<PutMsg> pendingputs; Queue<GetMsg> pendinggets; Token place; boolean empty = true; void processpendingget() { if (! pendinggets.empty) { getmsg, sender = pendinggets.remove() send DataMsg(place) to sender empty = true; processpendingput(); void process(msg msg, sender) { case msg { PutMsg(item) => if (!empty) { pendingputs.enqueue(msg, sender) else { place = msg.item; send OK to sender; empty = false; processpendingget(); void processpendingput() { if (! pendingputs.empty) { putmsg, sender = pendinggets.remove() send OKMsg to sender place = putmsg.item empty = false; processpendingget(); GetMsg(item) => if (empty) { pendinggets.enqueue(msg, sender) else { send Data(place) to sender; empty = true; processpendingput(); do (forever) { reveive msg from sender process(msg, sender) Seite 5
Senronizasyon Yerine İletişim Aktif Monitör Olarak Buffer: Ağ Programı Olarak Gerçekleştirim (1) public class ActiveBuffer<TokenType extends Serializable> extends Thread { private final DatagramSocket dtgrmsocket; private class Pkt { Pkt(InetAddress senderadr, int senderport, Msg msg) { this.senderadr = senderadr; this.senderport = senderport; this.msg = msg; InetAddress senderadr; int senderport; Msg msg; public enum Token { Ping, Pong public class BufferServer { private TokenType place; private boolean empty = true; private List<Pkt> pendingputs = new LinkedList<>(); private List<Pkt> pendinggets = new LinkedList<>(); public ActiveBuffer(int bufferport) throws SocketException { this.dtgrmsocket = new DatagramSocket(bufferPort); /** * @param args: arg[0]: port * @throws SocketException */ public static void main(string[] args) throws SocketException { if (args.length!= 1) { System.out.println("Aufruf: BufferServer <port>"); System.exit(0); int port = Integer.valueOf(args[0]).intValue(); ActiveBuffer<Token> activebuffer = new ActiveBuffer<>(port); @Override public void run() { activebuffer.start(); while (true) { Pkt pkt = receive(); process(pkt.msg, pkt.senderadr, pkt.senderport); private void process(msg msg, InetAddress address, int port) {... private void processpendingget() {... private void processpendingput() {... private void send(msg msg, InetAddress adr, int port) {... Seite 6?
Aktif Monitör Olarak Buffer : Ağ Programı Olarak Gerçekleştirim (2) private void process(msg msg, InetAddress address, int port) { if (msg instanceof PutMsg<?>) { PutMsg<TokenType> putmsg = (PutMsg<TokenType>) msg; if (!empty) { pendingputs.add(new Pkt(address, port, putmsg)); else { place = putmsg.getcontent(); empty = false; send(new OKMsg(), address, port); processpendingget(); else if (msg instanceof GetMsg) { GetMsg getmsg = (GetMsg) msg; if (empty) { pendinggets.add(new Pkt(address, port, getmsg)); else { empty = true; send(new AnswerMsg<TokenType>(place), address, port); processpendingput(); else { private void processpendingput() { throw new IllegalArgumentException(); if (! pendingputs.isempty()) { Pkt pkt = pendingputs.remove(0); send(new OKMsg(), pkt.senderadr, pkt.senderport); place = ((PutMsg<TokenType>)pkt.msg).getContent(); empty = false; processpendingget(); private void processpendingget() { if (!pendinggets.isempty()) { Pkt pkt = pendinggets.remove(0); send(new AnswerMsg<TokenType>(place), pkt.senderadr, pkt.senderport); empty = true; processpendingput();? Seite 7
Aktif Monitörden Pasif Monitöre: Özet İyi Fikir Senkronizasyonu iletişim ile değiştirmek prensipte iyi bir fikir. Bu büyük senkronizasyon problemlerini beraberinde getirir. Değişik bir yoldan çözülmeleri gerekmektedir. Destek Eksikliği Klasik shared state senkronizasyonu birden fazla yapıyla desteklenir. Muteksler, Koşul değişkenleri, Semafor, Uygun olan destek iletişim yoluyla gerçekleştirilen senkronizasyonda eksik kalır. put get producer buffer consumer producer Seite 8 buffer consumer
İletişim Paradigması İçin Destek Eksikliği Mesajların Koşullu Alınması ~ Wait'e karşılık gelir belirli mesajlar sadece belirli şartlar altında işlenebilirler(boş bir buffera yazmak), aksi takdirde mesajlar kayıt edilmelidir. Mesajların gecikmeli işlenmesi ~ Notify'a karşılık gelir Kaydedilmiş mesajlara kesin işlemlerin uygulanması (Put'tan sonra gecikmeli bir Get işleme alınabilir.) İletişim partnerlerinin yönetimi Gerçekte bir mesajın göndericisi mesaj alımının onayını ve/veya mesajının işlenmesini ve/veya bir yanıt elde etmelidir. Bundan dolayı mesajın göndericisi kolay tespit edilebilir olmalıdır. Serileştirme / Yönetim Biçimi Mesajlar taşıma esnasında serileştirilmeli ve deserileştirilebilmelidir. Bu rahat ve güvenli olarak gerçekleştirilebilmelidir. Seite 9
ve Dağıtık Programlar Dağıtık programlar dağıtık algoritmaları gerçekleştirirler. Bilgisayar bilimi dağıtık algoritmalara uygun bir yapı üzerinde 40 yıldan fazla bir süredir çalışmaktadır ne yazıkki çalışmalar tamamlanamamıştır. Genel çözümler dağıtıklık problemini soyutlaştırmayı (Middleware) ya da kolaylaştırılmış standartlara indirgemeyi (Web-Teknolojileri) denemektedirler. Bu probleme birçok çözüm üretilmiştir. Evrensel olarak kabul edilmiş semantik olarak tutarlı sistemler(dağıtık Programlama Dilleri) (henüz) yoktur. Durum değişmeye başlamıştır Şeffaflık arayışının bir hata olduğu kanıtlanmıştır Senkronizasyon yerine iletişim popülerdir Daha karmaşık uygulamalar: Dağıtıklık problemi isimlendirme ve serileştirmeden kaynaklanmamaktadır, kompleks algoritmalardan kaynaklanmaktadır. Uygun 'Dağıtık Programlama' arayışı yeni başlamıştır. Seite 10
Örnek : Scala'da Dağıtık Buffer (Akka-Aktörleri ile) 1 import akka.actor.actor import akka.actor.stash sealed abstract class Msg abstract class DataMsg[T](d : T) extends Msg case object GetMsg extends Msg case object OKMsg extends Msg case class PutMsg[T](data: T) extends DataMsg[T](data) case class AnswerMsg[T](data: T) extends DataMsg[T] (data) put get OK value producer buffer consumer class ActiveBuffer[T] extends Actor with Stash { var empty : Boolean = true; var place : Option[T] = None; Reaktif Gösterim def receive = { case PutMsg(data:T) => { if (!empty) { stash else { place = Some(data) sender! OKMsg empty = false unstashall() case GetMsg => { if (empty) { stash else { sender! AnswerMsg(place.get) place = None empty = true unstashall() Bir mesaj ulaştığında Eğer mesaj bir Put-mesajı ise Eğer yer boş ise: koy ve OK gönder ve başka işlenmemiş mesaj var mı diye bak Eğer boş değilse: mesajı geriye gönder Eğer mesaj bir Get-mesajı ise Eğer yer dolu ise: al ve geri gönder Ve başka işlenmemiş mesaj var mı diye bak Eğer boş ise: mesajı geri gönder Akka-Aktörleri ile Scala'da Aktif Monitör Seite 11
Örnek : Scala'da Dağıtık Buffer (Akka-Aktörleri ile) 2 class Consumer(buffer: ActorRef) extends Actor { import context._ import akka.actor.actorref import akka.actor.actor def accepter: Receive = { case AnswerMsg(data: Token) => println(data) buffer! GetMsg object Token extends Enumeration { type Token = Value val Ping, Pong = Value def receive = { case Start => { buffer! GetMsg become(accepter) object Start import Token._ class Producer(buffer: ActorRef) extends Actor { import context._ def pinger: Receive = { case OKMsg => buffer! PutMsg[Token](Ping) become(ponger) def ponger: Receive = { case OKMsg => buffer! PutMsg[Token](Pong) become(pinger) def receive = { case Start => { buffer! PutMsg[Token](Ping) become(pinger) Consumer-Actor import akka.actor._ import Token._ object Main extends App { val system = ActorSystem("BufferSystem") val buffer = system.actorof( Props[ActiveBuffer[Token]].withDispatcher("DequeBasedMailboxDispatcher"), name = "buffer") val producer = system.actorof( Props(new Producer(buffer)), name = "producer") val consumer = system.actorof( Props(new Consumer(buffer)), name = "consumer") producer! Start consumer! Start Producer-Aktor Tüm-Sistem DequeBasedMailboxDispatcher { mailbox-type = "akka.dispatch.unboundeddequebasedmailbox" Seite 12 Application.conf
Scala / Akka: Temel Unsurlar (Senkronizasyon yerine iletişim açısından) Aktif unsurların basit tanımları Mesajların kolay yönetimi ve işlenmesi işlenmemiş mesajların olduğu bir mesaj kutusu Pattern-Match ile arama yapılabilir. Uygun olmayan mesajlar geri gönderilebilir (stash) geri gönderilen mesajlar yeniden aktive edilebilir (unstash) Bir mesajın adres bilgilerinin kolay yönetimi: kimden, kime Kolay gönderim ve alma: serializasyon ve deserializasyon problem yaratmaz. Seite 13
Dağıtık Programlar ve Uygulamalar İki-Katmanlı Yaklaşım Katman 1: Ağ ve Taşıma Bu katman veri aktarımı ile tüm Klasik orta katman kurallarıyla serileştirme, isimlendirme vb. düzenler. Bu katman dağıtıklığı şeffaflaştırmaz. Bu katman burada daha fazla ilginç değil. İlet i dağ şim v e ı soy tıklık utla ştır ı lm az! Katman 2: Dağıtık Geçiş Sistemleri Bu katman uygulamanın (dağıtık) algoritmasını tamamlar. Üç-Adım-Prosedürü Adım 1: Uygulama mantığı İlk olarak uygulamanın mantığı, ancak gerçekte dağıtık olmayanı, bir sistemde gerçekleştirilir. Bu örnek olarak thread'lerin ortak bir kaynak olmadan gerçekleştirimleri demektir. Adım 2: Gerçek Dağıtıklık Mantıksal süreçler, gerçek iletişim kanallarını kullanarak mesaj değişimi yapan gerçek süreçler olarak gerçekleştirilir. Uygulama ağ problemi ve işlemci hatası olmadan mükemmel çalışmalıdır. Adım 3: Sorun Giderme Ağ problemleri ve işlemci hataları için sorun giderme özelliği eklenir. Seite 14
Dağıtık Programlar ve Uygulamalar Dağıtık Uygulamaların Gerçekleştirimi Konsept süreçlerin tanımlanabileceği mesaj gönderim ve alımının yapılabileceği ve herhangi bir yapıyla( Ağlar / Grafikler ) düzenlenebileceği Herhangi bir dil / herhangi bir yapı Gerçekleştirim Gerçek durumlara uygun diller/yapı Ne yazık ki her zaman bir konsept mi yoksa bir gerçekleştirim mi olması gerektiği, ve konsepte veya gerçeğe uygun bir altyapıyla gerçekleştirilip gerçekleştirilmediği açık değildir Seite 15
Dağıtık Programlar ve Uygulamalar Eşzamanlı ve Dağıtık Diller çok miktarda vardır farklı iddaaları vardır Oyuncak ya da gerçek uygulamalar için Gerçek dağıtıklığı ya da eşzamanlılığı desteklerler,... değişik modelleri temel alırlar RPC RMI Senkron iletişim Çalıştırıcılar(Actuators). see: http://en.wikipedia.org/wiki/list_of_concurrent_and_parallel_programming_languages#distributed Seite 16