paint-brush
Bu Web IDE, Dizüstü Bilgisayarınızı Eritmeden Kodunuzu Bulutta Çalıştırırile@oleksiijko
Yeni tarih

Bu Web IDE, Dizüstü Bilgisayarınızı Eritmeden Kodunuzu Bulutta Çalıştırır

ile Oleksii Bondar12m2025/02/21
Read on Terminal Reader

Çok uzun; Okumak

Proje, işlevselliği bağımsız hizmetlere bölmenize olanak tanıyan mikro hizmet mimarisi ilkesi üzerine inşa edilmiştir. Her bileşen, sistemin esnekliğini, ölçeklenebilirliğini ve hata toleransını sağlayan oldukça uzmanlaşmış bir görevden sorumludur. Proje, Go programlama diline dayanmaktadır.
featured image - Bu Web IDE, Dizüstü Bilgisayarınızı Eritmeden Kodunuzu Bulutta Çalıştırır
Oleksii Bondar HackerNoon profile picture
0-item
1-item

Bulut bilişim ve mikro hizmet mimarisinin hızla gelişmesi bağlamında, çeşitli programlama dilleri için güvenlik, ölçeklenebilirlik ve yüksek performans garantisiyle kodu dinamik olarak yürütme olanağı sağlama ihtiyacı artmaktadır. Bu makale, izole bir ortamda kod yürütmeyi uygulayan bir projeyi açıklar ve modern bir WEB IDE için seçilen mimari çözümün avantajlarını tartışır. Sistem şu şekilde oluşturulmuştur: Gitmek , kullanır gRPC etkili hizmet içi etkileşim için, Redis bir mesaj aracısı olarak ve Liman işçisi yürütme ortamını izole etmek için. WebSoketi sunucu sonuçları gerçek zamanlı olarak göstermek için kullanılır.

Sistemin ana bileşenlerinin nasıl yapılandırıldığını, alternatif çözümlerden nasıl farklılaştığını ve bu teknolojilerin seçiminin neden yüksek performans ve güvenlik elde etmeyi sağladığını detaylı olarak açıklayacağız.


1. Mimari genel bakış ve ana bileşenler

Proje, işlevselliği bağımsız hizmetlere bölmenize olanak tanıyan mikro hizmet mimarisi ilkesi üzerine inşa edilmiştir. Her bileşen, sistemin esnekliğini, ölçeklenebilirliğini ve hata toleransını sağlayan oldukça uzmanlaşmış bir görevden sorumludur.


Ana bileşenler:


  • gRPC, servisler arası iletişim için kullanılır. Mikroservisler arasında veri aktarımı için idealdir çünkü:
    • İkili protokol (Protokol Arabellekleri): Hızlı ve kompakt veri aktarımını sağlar.
    • Sıkı yazım: Veri aktarımı ve işlenmesinde hataların önlenmesine yardımcı olur.
    • Düşük gecikme: Hizmetler arasındaki dahili çağrılar için kritik öneme sahiptir (örneğin, bir gRPC sunucusu ile bir Redis kuyruğu arasında).
  • WebSocket Server: İstemciyle iki yönlü iletişim sağlayarak yürütme sonuçlarını gerçek zamanlı olarak iletir. Sonuçları olan bir kuyruğa abone olur ve verileri istemciye ileterek derleme ve yürütme günlüklerinin anında görüntülenmesini sağlar.
  • Çalışan: Görevleri bir kuyruktan çeken, geçici bir çalışma ortamı oluşturan, izole edilmiş bir Docker konteynerinde kodu doğrulayan ve yürüten ve ardından yürütme sonuçlarını kuyruğa geri yayınlayan bağımsız bir hizmet.
  • Redis: Görevleri gRPC sunucusundan Worker'a ve sonuçları Worker'dan WebSocket sunucusuna aktarmak için bir mesaj aracısı olarak kullanılır. Redis'in avantajları yüksek hız, Pub/Sub desteği ve kolay ölçeklenebilirliktir.
  • Dahili modüller:
    • Derleyici ve Docker Çalıştırıcısı: Docker komutlarını akış günlüğüyle çalıştırmaktan sorumlu bir modül olup, derleme ve yürütme sürecinin gerçek zamanlı izlenmesine olanak tanır.
    • Dil Çalıştırıcıları: Çeşitli diller (C, C++, C#, Python, JavaScript, TypeScript) için kodun doğrulanması, derlenmesi ve yürütülmesi için mantığı birleştirin. Her çalıştırıcı, yeni diller için işlevselliğin genişletilmesini basitleştiren tek bir arayüz uygular.


Aşağıdaki diyagram, gRPC, Redis ve WebSocket kullanılarak istemciden çalışan sürece ve geriye doğru veri akışını gösterir.


2. Teknolojiler ve seçim gerekçeleri

Gitmek

Go'nun Avantajları:

  • Performans ve ölçeklenebilirlik: Go, özellikle çok sayıda paralel isteğin işlenmesi için önemli olan yüksek bir yürütme hızına sahiptir.

  • Dahili eşzamanlılık desteği: Goroutine ve kanalların mekanizmaları, karmaşık çoklu iş parçacığı desenleri olmadan bileşenler arasında eşzamansız etkileşimin uygulanmasına olanak tanır.


gRPC

gRPC’nin Avantajları:

  • Verimli veri aktarımı: İkili aktarım protokolü (Protokol Arabellekleri) sayesinde gRPC düşük gecikme süresi ve düşük ağ yükü sağlar.
  • Güçlü yazım: Bu, mikro hizmetler arasındaki verilerin yanlış yorumlanmasıyla ilişkili hata sayısını azaltır.
  • Çift yönlü akış desteği: Bu, özellikle günlükleri ve yürütme sonuçlarını gerçek zamanlı olarak değiştirmek için kullanışlıdır.

Karşılaştırma: REST API'nin aksine gRPC, yüksek oranda eşzamanlı sistemler için kritik öneme sahip olan servisler arası iletişimi daha verimli ve güvenilir hale getirir.


Redis

Neden Redis?

  • Yüksek performans: Redis saniyede çok sayıda işlemi işleyebilir, bu da onu görev ve sonuç kuyrukları için ideal hale getirir.

  • Pub/Sub ve Liste Desteği: Kuyruk ve abonelik mekanizmalarının uygulanmasının basitliği, servisler arasındaki asenkron etkileşimlerin düzenlenmesini kolaylaştırır.

  • Diğer mesaj brokerlarıyla karşılaştırma: RabbitMQ veya Kafka'nın aksine Redis daha az yapılandırma gerektirir ve gerçek zamanlı sistemler için yeterli performans sağlar.


Liman işçisi

Docker'ın rolü:

  • Ortam izolasyonu: Docker konteynerları, kodun tamamen izole edilmiş bir ortamda çalıştırılmasına olanak tanır; bu da yürütme güvenliğini artırır ve ana sistemle çakışma riskini azaltır.

  • Yönetilebilirlik ve tutarlılık: Docker'ı kullanmak, ana bilgisayar sisteminden bağımsız olarak kodu derlemek ve yürütmek için aynı ortamı sağlar.

  • Karşılaştırma: Kodu doğrudan ana bilgisayarda çalıştırmak güvenlik riski oluşturabilir ve bağımlılık çatışmalarına yol açabilir, ancak Docker bu sorunları çözmenize olanak tanır.


WebSoketi

  • Gerçek zamanlı: İstemciyle sürekli bağlantı, verilerin (kayıtlar, yürütme sonuçları) anında aktarılmasını sağlar.
  • Gelişmiş kullanıcı deneyimi: WebSocket ile IDE, kodun sonuçlarını dinamik olarak görüntüleyebilir.


3. Mikroservis Mimarisinin Faydaları

Bu proje, bir dizi önemli avantajı olan bir mikro servis yaklaşımını kullanıyor:


  • Bağımsız ölçekleme: Her servis (gRPC sunucusu, Worker, WebSocket sunucusu, Redis) yüke bağlı olarak ayrı ayrı ölçeklenebilir. Bu, kaynakların verimli kullanılmasını ve istek sayısındaki artışa hızlı adaptasyon sağlar.
  • Hata toleransı: Sistemi bağımsız modüllere bölmek, bir mikro servisin arızasının tüm sistemin arızalanmasına yol açmaması anlamına gelir. Bu, genel kararlılığı artırır ve hatalardan kurtarmayı basitleştirir.
  • Geliştirme ve dağıtım esnekliği: Mikro hizmetler bağımsız olarak geliştirilir ve dağıtılır, bu da yeni özelliklerin ve güncellemelerin tanıtımını basitleştirir. Bu ayrıca her bir belirli hizmet için en uygun teknolojileri kullanmanıza da olanak tanır.
  • Entegrasyon kolaylığı: Açıkça tanımlanmış arayüzler (örneğin gRPC aracılığıyla), mevcut mimaride büyük değişiklikler yapmadan yeni hizmetleri bağlamayı kolaylaştırır.
  • Yalıtım ve güvenlik: Her mikro servis kendi konteynerinde çalışabilir; bu da güvenli olmayan kod yürütmeyle ilişkili riskleri en aza indirir ve ek bir koruma katmanı sağlar.


4. Mimari yaklaşımların karşılaştırmalı analizi

Uzaktan kod yürütme için modern WEB IDE'leri oluştururken, genellikle çeşitli mimari çözümler karşılaştırılır. İki yaklaşımı ele alalım:


Yaklaşım A: Mikroservis mimarisi (gRPC + Redis + Docker)


  • Gecikme: 40 ms
  • Verim: 90 adet
  • Güvenlik: 85 birim
  • Ölçeklenebilirlik: 90 birim


Özellikler:
Bu yaklaşım, hızlı ve güvenilir hizmetler arası iletişim, kod yürütmenin yüksek izolasyonu ve konteynerleştirme nedeniyle esnek ölçekleme sağlar. Tepkiselliğin ve güvenliğin önemli olduğu modern WEB IDE'leri için mükemmeldir.


Yaklaşım B: Geleneksel Monolitik Mimari (HTTP REST + Merkezi Yürütme)


  • Gecikme: 70 ms
  • Verim: 65 birim
  • Güvenlik: 60 birim
  • Ölçeklenebilirlik: 70 birim


Özellikler:
Genellikle web IDE'lerinin erken sürümlerinde kullanılan monolitik çözümler, HTTP REST ve merkezi kod yürütmeye dayanır. Bu tür sistemler ölçekleme sorunları, artan gecikme ve başka birinin kodunu yürütürken güvenliği sağlamada zorluklarla karşı karşıyadır.


Not: WEB IDE geliştirmenin modern bağlamında, HTTP REST ve merkezi yürütme yaklaşımı, gerekli esnekliği ve ölçeklenebilirliği sağlamadığı için mikroservis mimarisinin avantajlarına göre daha düşüktür.


Karşılaştırmalı metriklerin görselleştirilmesi

Grafikte mikroservis mimarisinin (Yaklaşım A) monolitik çözüme (Yaklaşım B) kıyasla daha düşük gecikme, daha yüksek verim, daha iyi güvenlik ve ölçeklenebilirlik sağladığı açıkça görülmektedir.


5. Docker mimarisi: izolasyon ve ölçeklenebilirlik

Sistem güvenliği ve istikrarının temel unsurlarından biri Docker kullanımıdır. Çözümümüzde, tüm hizmetler ayrı kapsayıcılarda dağıtılır ve bu da şunları sağlar:


  • Yürütme ortamının izolasyonu: Her hizmet (gRPC sunucusu, Worker, WebSocket sunucusu) ve mesaj aracısı (Redis) kendi konteynerinde çalışır, bu da güvenli olmayan kodun ana sistemi etkilemesi riskini en aza indirir. Aynı zamanda, kullanıcının tarayıcıda çalıştırdığı kod (örneğin, WEB IDE aracılığıyla) her görev için ayrı bir Docker konteynerinde oluşturulur ve yürütülür. Bu yaklaşım, potansiyel olarak güvenli olmayan veya hatalı kodun ana altyapının çalışmasını etkileyememesini sağlar.
  • Ortam tutarlılığı: Docker kullanımı, ayarların geliştirme, test ve üretim ortamlarında aynı kalmasını sağlar; bu da hata ayıklamayı büyük ölçüde basitleştirir ve kod yürütmenin öngörülebilirliğini garanti eder.
  • Ölçeklenebilirlik esnekliği: Her bileşen bağımsız olarak ölçeklenebilir, bu da değişen yüklere etkili bir şekilde uyum sağlamanızı sağlar. Örneğin, istek sayısı arttıkça, her biri kullanıcı kodunu yürütmek için ayrı kapsayıcılar oluşturacak ek Worker kapsayıcıları başlatabilirsiniz.

Bu şema içerisinde Worker, Redis'ten sadece görevleri almakla kalmaz, aynı zamanda her istek için kullanıcı kodunu izole bir şekilde yürütmek üzere ayrı bir kapsayıcı (Container: Code Execution) oluşturur.


6. Küçük kod bölümleri

Aşağıda sistemin nasıl çalıştığını gösteren ana kod bölümlerinin küçültülmüş bir versiyonu bulunmaktadır:

  1. Küresel çalıştırıcı kayıt defterini kullanarak hangi dilin çalıştırılacağını belirler.
  2. RunInDockerStreaming işlevini kullanarak kullanıcı kodunu çalıştırmak için bir Docker konteyneri başlatır.



1. Koşucu kaydı aracılığıyla dil tespiti

Sistem, her dilin kendi çalıştırıcısına sahip olduğu küresel bir kayıt defteri kullanır. Bu, yeni diller için desteği kolayca eklemenize olanak tanır, çalıştırıcı arayüzünü uygulamak ve kaydetmek yeterlidir:


 package languages import ( "errors" "sync" ) var ( registry = make(map[string]Runner) registryMu sync.RWMutex ) type Runner interface { Validate(projectDir string) error Compile(ctx context.Context, projectDir string) (<-chan string, error) Run(ctx context.Context, projectDir string) (<-chan string, error) } func Register(language string, runner Runner) { registryMu.Lock() defer registryMu.Unlock() registry[language] = runner } func GetRunner(language string) (Runner, error) { registryMu.RLock() defer registryMu.RUnlock() if runner, exists := registry[language]; exists { return runner, nil } return nil, errors.New("unsupported language") }


Yeni bir dil kaydetme örneği:


 func init() { languages.Register("python", NewGenericRunner("python")) languages.Register("javascript", NewGenericRunner("javascript")) }


Bu nedenle bir istek alındığında sistem şunu çağırır:


 runner, err := languages.GetRunner(req.Language)


ve kodu çalıştırmak için karşılık gelen koşucuyu alır.


2. Kodu yürütmek için bir Docker konteynerini başlatma

Her kullanıcı kodu isteği için ayrı bir Docker konteyneri oluşturulur. Bu, koşucu yöntemlerinin içinde yapılır (örneğin, Run'da). Konteyneri çalıştırmanın ana mantığı RunInDockerStreaming işlevindedir:


 package compiler import ( "bufio" "fmt" "io" "log" "os/exec" "time" ) func RunInDockerStreaming(image, dir, cmdStr string, logCh chan < -string) error { timeout: = 50 * time.Second cmd: = exec.Command("docker", "run", "--memory=256m", "--cpus=0.5", "--network=none", "-v", fmt.Sprintf("%s:/app", dir), "-w", "/app", image, "sh", "-c", cmdStr) cmd.Stdin = nil stdoutPipe, err: = cmd.StdoutPipe() if err != nil { return fmt.Errorf("error getting stdout: %v", err) } stderrPipe, err: = cmd.StderrPipe() if err != nil { return fmt.Errorf("error getting stderr: %v", err) } if err: = cmd.Start();err != nil { return fmt.Errorf("Error starting command: %v", err) } // Reading logs from the container go func() { reader: = bufio.NewReader(io.MultiReader(stdoutPipe, stderrPipe)) for { line, isPrefix, err: = reader.ReadLine() if err != nil { if err != io.EOF { logCh < -fmt.Sprintf("[Error reading logs: %v]", err) } break } msg: = string(line) for isPrefix { more, morePrefix, err: = reader.ReadLine() if err != nil { break } msg += string(more) isPrefix = morePrefix } logCh < -msg } close(logCh) }() doneCh: = make(chan error, 1) go func() { doneCh < -cmd.Wait() }() select { case err: = < -doneCh: return err case <-time.After(timeout): if cmd.Process != nil { cmd.Process.Kill() } return fmt.Errorf("Execution timed out") } }


Bu fonksiyon, şu şekilde docker run komutunu üretir:


  • image, belirli bir dil için seçilen Docker image'dır (runner yapılandırması tarafından tanımlanır).
  • dir, bu istek için oluşturulan kodun bulunduğu dizindir.
  • cmdStr kodu derlemek veya çalıştırmak için kullanılan komuttur.


Bu nedenle runner'ın Run metodu çağrıldığında aşağıdakiler gerçekleşir:


  • RunInDockerStreaming fonksiyonu, kodun yürütüldüğü Docker konteynerini başlatır.
  • Yürütme günlükleri logCh kanalına aktarılır ve bu da yürütme süreci hakkında gerçek zamanlı bilgi iletmenize olanak tanır.


3. Entegre yürütme süreci

Kod yürütmenin ana mantığının (executor.ExecuteCode) küçültülmüş parçası:


 func ExecuteCode(ctx context.Context, req CodeRequest, logCh chan string) CodeResponse { // Create a temporary directory and write files projectDir, err: = util.CreateTempProjectDir() if err != nil { return CodeResponse { "", fmt.Sprintf("Error: %v", err) } } defer os.RemoveAll(projectDir) for fileName, content: = range req.Files { util.WriteFileRecursive(filepath.Join(projectDir, fileName), [] byte(content)) } // Get a runner for the selected language runner, err: = languages.GetRunner(req.Language) if err != nil { return CodeResponse { "", err.Error() } } if err: = runner.Validate(projectDir); err != nil { return CodeResponse { "", fmt.Sprintf("Validation error: %v", err) } } // Compile (if needed) and run code in Docker container compileCh, _: = runner.Compile(ctx, projectDir) for msg: = range compileCh { logCh < -"[Compilation]: " + msg } runCh, _: = runner.Run(ctx, projectDir) var output string for msg: = range runCh​​ { logCh < -"[Run]: " + msg output += msg + "\n" } return CodeResponse { Output: output } }


Bu minimal örnekte:


  • Dil algılama, yeni bir dil için desteğin kolayca eklenmesine olanak tanıyan languages.GetRunner(req.Language) çağrısı yoluyla yapılır.
  • Docker konteyner başlatma, kodu izole bir şekilde yürütmek için RunInDockerStreaming'i kullanan Derleme/Çalıştır yöntemlerinin içinde uygulanır.


Bu temel parçalar, sistemin genişletilebilirliği (yeni dillerin kolayca eklenmesi) nasıl desteklediğini ve her istek için ayrı bir Docker konteyneri oluşturarak izolasyon sağladığını gösterir. Bu yaklaşım, özellikle modern WEB IDE'leri için önemli olan platformun güvenliğini, kararlılığını ve ölçeklenebilirliğini iyileştirir.

7. Sonuç

Bu makale, gRPC + Redis + Docker yığınını kullanan bir mikro hizmet mimarisi üzerine inşa edilmiş uzaktan kod yürütme platformunu ele almaktadır. Bu yaklaşım şunları yapmanıza olanak tanır:


  • Verimli hizmetler arası iletişim sayesinde gecikmeyi azaltın ve yüksek verim sağlayın.
  • Kod yürütmeyi ayrı Docker kapsayıcılarında izole ederek ve her kullanıcı isteği için ayrı bir kapsayıcı oluşturarak güvenliği sağlayın.
  • Mikroservislerin bağımsız ölçeklenmesi sayesinde sistemin esnek bir şekilde ölçeklenmesi.
  • Özellikle modern WEB IDE'leri için önemli olan WebSocket aracılığıyla sonuçları gerçek zamanlı olarak sunun.


Karşılaştırmalı bir analiz, mikroservis mimarisinin tüm temel metriklerde geleneksel monolitik çözümlerden önemli ölçüde daha iyi performans gösterdiğini göstermektedir. Bu yaklaşımın avantajları gerçek verilerle doğrulanmıştır ve bu da onu yüksek performanslı ve hataya dayanıklı sistemler oluşturmak için çekici bir çözüm haline getirir.



Yazar: Oleksii Bondar
Tarih: 2025–02–07