Google Cloud'da Spring Yerel

1. Genel Bakış

Bu codelab'de Spring Native projesi hakkında bilgi edinecek, bu projeyi kullanan bir uygulama geliştirip Google Cloud'a dağıtacağız.

Projenin bileşenlerini, projenin yakın geçmişini, bazı kullanım alanlarını ve elbette projeyi projelerinizde kullanmanız için gereken adımları inceleyeceğiz.

Spring Native projesi şu anda deneysel aşamadadır. Bu nedenle, başlamak için bazı özel yapılandırmalar gerekir. Bununla birlikte, SpringOne 2021'de duyurulduğu gibi Spring Native, birinci sınıf destek ile Spring Çerçevesi 6.0 ve Spring Boot 3.0'a entegre edilecektir. Bu nedenle, yayınlanmadan birkaç ay önce projeye daha yakından bakmak için en uygun zamandır.

Tam zamanında derleme, uzun çalışan işlemler gibi özelliklere göre çok iyi optimize edilmiş olsa da, önceden derlenmiş uygulamaların daha iyi performans gösterdiği belirli kullanım alanları da mevcuttur. Bu durumu codelab'de açıklayacağız.

Demoda aşağıdaki işlemleri yapmayı öğreneceksiniz:

  • Cloud Shell'i kullanma
  • Cloud Run API'yi etkinleştirme
  • Spring Yerel uygulaması oluşturma ve dağıtma
  • Böyle bir uygulamayı Cloud Run'a dağıtma

Gerekenler

Anket

Bu eğiticiden nasıl yararlanacaksınız?

Yalnızca okuma Okuyun ve alıştırmaları tamamlayın

Java deneyiminizi nasıl değerlendirirsiniz?

Acemi Orta Yeterli

Google Cloud hizmetlerini kullanma deneyiminizi nasıl değerlendirirsiniz?

Acemi Orta Yeterli

2. Arka plan

Spring Native projesi, geliştiricilere yerel uygulama performansı sunmak için çeşitli teknolojilerden yararlanır.

İlkbaharda Doğal kullanımı tam olarak anlamak için bu bileşen teknolojilerinden birkaçını, bizim için ne sağladıklarını ve burada birlikte nasıl çalıştıklarını anlamak yararlı olacaktır.

AOT derlemesi

Geliştiriciler, derleme sırasında Javac'yi normal bir şekilde çalıştırdıklarında, .java kaynak kodumuz, bayt kodu ile yazılan .class dosyaları olarak derlenir. Bu bayt kodunun yalnızca Java sanal makinesi tarafından anlaşılması amaçlandığından, kodumuzu çalıştırabilmemiz için JVM'nin bu kodu diğer makinelerde yorumlaması gerekir.

Bu işlem, bize Java'nın imza taşınabilirliğini sağlayarak "bir kez yazıp her yerde çalıştırmamıza" olanak tanır ancak yerel kod çalıştırmaya kıyasla pahalıdır.

Neyse ki JVM çoğu uygulaması, bu yorumlama maliyetini azaltmak için tam zamanında derleme kullanır. Bu işlem, bir işlevin çağrıları sayılarak gerçekleştirilir. İşlev, bir eşiği ( varsayılan olarak 10.000) geçmeye yetecek kadar sık çağrılırsa daha pahalı yorumlamayı önlemek için çalışma zamanında yerel koda derlenir.

Önceden derleme işlemi, erişilebilir olan tüm kodları, derleme sırasında yürütülebilir yerel bir uygulamada derleyerek tam tersi bir yaklaşım uygular. Bu sayede taşınabilirlik yerine çalışma zamanında bellek verimliliği ve performansta daha fazla avantaj elde edilir.

5042e8e62a05a27.png

Bu elbette bir ödün vermektir ve her zaman almaya değmez. Ancak AOT derlemesi, aşağıdaki gibi belirli kullanım alanlarında başarılı olabilir:

  • Başlatma süresinin önemli olduğu kısa ömürlü uygulamalar
  • JIT'in çok maliyetli olabileceği, yüksek düzeyde bellek kısıtlaması olan ortamlar

İşin eğlenceli bir yanı da, AOT derlemesi JDK 9'da deneysel bir özellik olarak kullanıma sunulmuştu. Ancak bu uygulamanın sürdürülmesi pahalıydı ve uzun süre ilgi görmedi. Bu nedenle, yalnızca GraalVM kullanan geliştiricilerin lehine olan Java 17'de AOT derlemesi sessizce kaldırıldı.

GraalVM

GraalVM, son derece hızlı başlatma süreleri, AOT yerel görüntü derlemesi ve geliştiricilerin birden fazla dili tek bir uygulamada birleştirmesine olanak tanıyan çok dilli (çok dilli) özelliklerine sahip, son derece optimize edilmiş bir açık kaynak JDK dağıtımıdır.

GraalVM aktif geliştirme aşamasında olduğu için sürekli yeni beceriler ediniyor ve mevcut becerileri sürekli geliştiriyor. Bu yüzden geliştiricilerin bizi takip etmeye devam etmesini öneririm.

Yakın zamandaki bazı ara hedefler şunlardır:

  • Yeni ve kullanıcı dostu bir yerel görüntü derleme çıkışı ( 18.01.2021)
  • Java 17 desteği ( 18.01.2022)
  • Çok dilli derleme sürelerini iyileştirmek için varsayılan olarak çok katmanlı derlemeyi etkinleştirme ( 20.04.2021)

İlkbahar Yerel

Kısacası Spring Yerel, GraalVM'nin yerel görüntü derleyicisini kullanarak Spring uygulamalarını yerel yürütülebilir dosyalara dönüştürmeyi mümkün kılar.

Bu işlem, uygulamanızda giriş noktasından erişilebilen tüm yöntemleri bulmak için derleme sırasında uygulamanızın statik analizini içerir.

Bu temelde, kapalı bir dünya oluşturur. tüm kodların derleme sırasında bilindiği varsayılan ve çalışma zamanında yeni bir kod yüklenmesine izin verilmediği uygulamanızın konseptini oluşturur.

Yerel görüntü oluşturma işleminin, normal bir uygulamayı derlemekten daha uzun süren, bellek yoğun bir işlem olduğunu ve Java'nın belirli yönlerine sınırlamalar getirdiğini unutmayın.

Bazı durumlarda, uygulamanın Spring Yerel ile çalışması için kod değişikliği gerekmez. Ancak bazı durumlarda düzgün çalışmak için belirli bir yerel yapılandırma gerekir. Böyle durumlarda Spring Yerel, bu işlemi basitleştirmek için genellikle Yerel İpuçları sağlar.

3. Kurulum/Ön Çalışma

Spring Yerel'i uygulamaya başlamadan önce uygulamamızı oluşturup dağıtmamız gerekiyor. Böylece daha sonra yerel sürümle karşılaştırabileceğimiz bir performans temel çizgisi belirleyeceğiz.

1. Projeyi oluşturma

İlk olarak uygulamamızı start.spring.io'dan edineceğiz:

curl https://start.spring.io/starter.zip -d dependencies=web \
           -d javaVersion=11 \
           -d bootVersion=2.6.4 -o io-native-starter.zip

Bu başlangıç uygulaması, ilkbaharda yerel projenin desteklediği en son sürüm olan Spring Boot 2.6.4 sürümünü kullanır.

GraalVM 21.0.3 sürümünden bu yana bu örnek için de Java 17'yi kullanabileceğinizi unutmayın. İlgili yapılandırmayı en aza indirmek amacıyla bu eğitimde Java 11'i kullanmaya devam edeceğiz.

Zip dosyasını komut satırına yerleştirdikten sonra projemiz için bir alt dizin oluşturabilir ve bu dizindeki klasörü açabiliriz:

mkdir spring-native

cd spring-native

unzip ../io-native-starter.zip

2. Kod değişiklikleri

Proje başladığında, bize hızlıca bir hareket işareti ekleyecek ve projeyi çalıştırdıktan sonra Baharda Yerel performansı sergileyeceğiz.

DemoApplication.java dosyasını buna uyacak şekilde düzenleyin:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.time.Instant;

@RestController
@SpringBootApplication
public class DemoApplication {
    private static Instant startTime;
    private static Instant readyTime;

    public static void main(String[] args) {
        startTime = Instant.now();
                SpringApplication.run(DemoApplication.class, args);
    }

    @GetMapping("/")
    public String index() {
        return "Time between start and ApplicationReadyEvent: "
                + Duration.between(startTime, readyTime).toMillis()
                + "ms";
    }

    @EventListener(ApplicationReadyEvent.class)
    public void ready() {
                readyTime = Instant.now();
    }
}

Temel uygulamamız bu noktada kullanıma hazırdır. Bu nedenle, yerel uygulamaya dönüştürmeden önce başlatma süresi hakkında fikir edinmek için bir görüntü derleyip yerel olarak çalıştırabilirsiniz.

Görüntümüzü oluşturmak için:

mvn spring-boot:build-image

Taban resmin boyutu hakkında fikir edinmek için docker images demo kullanabilirsiniz: 6ecb403e9af1475e.png

Uygulamamızı çalıştırmak için:

docker run --rm -p 8080:8080 demo:0.0.1-SNAPSHOT

3. Temel uygulamayı dağıtma

Artık uygulamamızı aldığımıza göre onu dağıtacağız ve zamanları not edeceğiz. Bu süreyi daha sonra yerel uygulama başlatma süreleriyle karşılaştıracağız.

Oluşturduğunuz uygulamanın türüne bağlı olarak öğelerinizi barındırmak için farklı seçenekler vardır.

Ancak örneğimiz çok basit ve anlaşılır bir web uygulaması olduğundan işleri basit tutabilir ve Cloud Run'a güvenebiliriz.

Süreci kendi makinenizde kullanıyorsanız gcloud KSA aracının yüklü ve güncel olduğundan emin olun.

İşlemin tamamlanması için Cloud Shell'deyseniz kaynak dizinde aşağıdaki komutu çalıştırmanız yeterlidir:

gcloud run deploy

4. Uygulama Yapılandırması

1. Maven depolarımızı yapılandırma

Bu proje hâlâ deneysel aşamada olduğu için uygulamamızı maven merkezi deposunda bulunmayan deneysel yapıları bulabilecek şekilde yapılandırmamız gerekiyor.

Aşağıdaki öğelerin pom.xml dosyasına eklenmesi gerekir. Aşağıdaki öğeleri istediğiniz düzenleyicide yapabilirsiniz.

Aşağıdaki depoları ve PluginRepositories bölümlerini ponumuza ekleyin:

<repositories>
    <repository>
        <id>spring-release</id>
        <name>Spring release</name>
        <url>https://repo.spring.io/release</url>
    </repository>
</repositories>

<pluginRepositories>
    <pluginRepository>
        <id>spring-release</id>
        <name>Spring release</name>
        <url>https://repo.spring.io/release</url>
    </pluginRepository>
</pluginRepositories>

2. Bağımlılıklarımızı ekleme

Ardından, Spring uygulamasını yerel görüntü olarak çalıştırmak için gerekli olan ilkbaharda yerel bağımlılığı ekleyin. Not: Gradle kullanıyorsanız bu adım gerekli değildir

<dependencies>
    <!-- ... -->
    <dependency>
        <groupId>org.springframework.experimental</groupId>
        <artifactId>spring-native</artifactId>
        <version>0.11.2</version>
    </dependency>
</dependencies>

3. Eklentilerimizi ekleme/etkinleştirme

Şimdi yerel resim uyumluluğunu ve ayak izini iyileştirmek için AOT eklentisini ekleyin ( Daha fazla bilgi):

<plugins>
    <!-- ... -->
    <plugin>
        <groupId>org.springframework.experimental</groupId>
        <artifactId>spring-aot-maven-plugin</artifactId>
        <version>0.11.2</version>
        <executions>
            <execution>
                <id>generate</id>
                <goals>
                    <goal>generate</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

Şimdi yerel görüntü desteğini etkinleştirmek için spring-boot-maven eklentisini güncelleyeceğiz ve yerel görüntümüzü oluşturmak için paketo oluşturucuyu kullanacağız:

<plugins>
    <!-- ... -->
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <image>
                <builder>paketobuildpacks/builder:tiny</builder>
                <env>
                    <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                </env>
            </image>
        </configuration>
    </plugin>    
</plugins>

Küçük oluşturucu resminin çeşitli seçeneklerden yalnızca biri olduğunu unutmayın. Saldırı yüzeyimizi en aza indirmeye yardımcı olan, çok az ekstra kitaplık ve yardımcı program içerdiğinden kullanım alanımız için iyi bir seçimdir.

Örneğin, bazı yaygın C kitaplıklarına erişmesi gereken bir uygulama geliştiriyorsanız veya uygulamanızın gereksinimlerinden henüz emin değilseniz tam geliştirici daha uygun olabilir.

5. Yerel uygulama oluşturma ve çalıştırma

Her şey tamamlandığında görüntümüzü derleyip yerel, derlenmiş uygulamamızı çalıştırabiliriz.

Derlemeyi çalıştırmadan önce göz önünde bulundurmanız gereken birkaç nokta aşağıda belirtilmiştir:

  • Bu işlem normal bir derlemeden daha fazla zaman alır (birkaç dakika) d420322893640701.png
  • Bu derleme işlemi çok fazla bellek (birkaç gigabayt) kaplayabilir cda24e1eb11fdbea.png
  • Bu derleme işlemi, Docker arka plan programının erişilebilir olmasını gerektirir
  • Bu örnekte, süreci manuel olarak ele alıyoruz. Bununla birlikte, derleme aşamalarınızı yerel derleme profilini otomatik olarak tetikleyecek şekilde yapılandırabilirsiniz.

Görüntümüzü oluşturmak için:

mvn spring-boot:build-image

Bu uygulama oluşturulduktan sonra yerel uygulamayı iş başında görmeye hazırız.

Uygulamamızı çalıştırmak için:

docker run --rm -p 8080:8080 demo:0.0.1-SNAPSHOT

Bu noktada, yerel uygulama denkleminin her iki tarafını da görmek için mükemmel bir konumdayız.

Derleme sırasında epey zaman kazanıp ekstra bellek kullanımından tasarruf ettik, ancak bunun karşılığında çok daha hızlı çalışabilen ve (iş yüküne bağlı olarak) önemli ölçüde daha az bellek tüketebilen bir uygulama elde ediyoruz.

Yerel resmin boyutunu orijinalle karşılaştırmak için docker images demo komutunu çalıştırırsak önemli bir küçülme görebiliriz:

e667f65a011c1328.png

Daha karmaşık kullanım alanlarında, AOT derleyiciyi uygulamanızın çalışma zamanında ne yapacağı konusunda bilgilendirmek için ek değişiklikler yapılması gerektiğini de unutmayın. Bu nedenle, belirli tahmin edilebilir iş yükleri (toplu işler gibi) buna çok uygunken bazılarında daha büyük artış görülebilir.

6. Yerel uygulamamızı dağıtma

Uygulamamızı Cloud Run'a dağıtmak için yerel görüntümüzü Artifact Registry gibi bir paket yöneticisine aktarmamız gerekiyor.

1. Docker depomuzu hazırlama

Bu işleme bir depo oluşturarak başlayabiliriz:

gcloud artifacts repositories create native-image-docker-repo --repository-format=docker \
--location=us-central1 --description="Repository for our native images"

Sonraki adımda, yeni kayıt defterimize aktarmak için kimliğimizin doğrulandığından emin olmak isteyeceğiz.

gcloud KSA bu işlemi oldukça basitleştirebilir:

gcloud auth configure-docker us-central1-docker.pkg.dev

2. Görüntümüzü Artifact Registry'ye aktarıyoruz

Sonra resmimizi etiketleyeceğiz:

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')


docker tag  demo:0.0.1-SNAPSHOT \
us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2

Ardından docker push kullanarak Artifact Registry'ye gönderebiliriz:

docker push us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2

3. Cloud Run'a dağıtma

Artık Artifact Registry'de depoladığımız görüntüyü Cloud Run'a dağıtmaya hazırız:

gcloud run deploy --image us-central1-docker.pkg.dev/$PROJECT_ID/native-image-docker-repo/quickstart-image:tag2

Uygulamamızı yerel görüntü olarak derleyip dağıttığımızdan, uygulamamızın çalışırken altyapı maliyetlerimizden mükemmel bir şekilde yararlandığından emin olabiliyoruz.

Temel uygulamamızın başlatma sürelerini bu yeni yerel uygulama ile kendiniz karşılaştırabilirsiniz.

6dde63d35959b1bb.png

7. Özet/Temizlik

Google Cloud'da Spring Yerel uygulaması derleyip dağıttığınız için tebrik ederiz.

Bu eğitimin sizi Spring Native projesine daha aşina olmanızı ve gelecekte ihtiyaçlarınızı karşılaması durumunda bu projeyi göz önünde bulundurmaya teşvik edeceğini umuyoruz.

İsteğe bağlı: Hizmeti temizleme ve/veya devre dışı bırakma

İster bu codelab için bir Google Cloud projesi oluşturmuş ister mevcut bir projeyi yeniden kullanıyor olun, yararlandığımız kaynaklardan gereksiz ücretlendirme yapmamaya özen gösterin.

Oluşturduğumuz Cloud Run hizmetlerini silebilir veya devre dışı bırakabilir, barındırdığımız görüntüyü silebilir veya projenin tamamını kapatabilirsiniz.

8. Ek kaynaklar

Spring Native projesi şu anda yeni ve deneysel bir proje olsa da ilk kullanıcıların sorunları gidermesine ve sürece dahil olmasına yardımcı olacak zengin kaynaklar mevcuttur:

Ek kaynaklar

Aşağıda, bu eğitim için alakalı olabilecek çevrimiçi kaynaklar verilmiştir:

Lisans

Bu çalışma, Creative Commons Attribution 2.0 Genel Amaçlı Lisans ile lisans altına alınmıştır.