Docker Ortamında Spring Boot Uygulamalarında Artan Bellek Sorunu: Analiz ve Çözüm
İlgili Etiketler:1. Docker login, docker push ve docker pull hataları hakkında SSS
2. Ubuntu 20 Üzerine Docker Nasıl Kurulur
Spring Boot Giriş
Basit bir Spring Boot uygulaması neredeyse yalnızca bir kullanıcı tarafından kullanıldığında bellek 1,2 GB'a ulaşmaktadır ki bu oldukça kötüdür.
Basit bir Spring Boot uygulaması neredeyse yalnızca bir kullanıcı tarafından kullanıldığında bellek 1,2 GB'a ulaşmaktadır ki bu oldukça kötüdür.
Hizmet durumu
Hizmet sayısı az ve sunucu kaynakları yeterli olduğundan, birçok hizmet JVM parametreleri olmadan başlatılmıştır (eski sorunlar). Sonuç olarak, her hizmet başlangıcı 1,2 GB - 2 GB bellek kaplamaktadır ve bazı hizmetler bu kadarını hiç kullanmamaktadır. Peki, JVM bellek parametresi ayarlanmadığında Spring Boot'ta JVM belleği nasıl yapılandırılır?
Bir Spring Boot projesini çalıştırırken JVM bellek parametresi ayarlanmazsa, Spring Boot varsayılan olarak JVM'nin kendi varsayılan yapılandırma stratejisini kullanır. Kaynakların yeterli olduğu durumlarda geliştiriciler bellek ayarlarına pek önem vermezler. Ancak kaynak sıkıntısı ve JVM optimizasyonu söz konusu olduğunda, varsayılan JVM bellek yapılandırma stratejisini anlamanız gerekir.
JVM belleğiyle ilgili en yaygın ayarlar başlangıç yığın boyutu (-Xms) ve maksimum yığın belleğidir (-Xmx). Birçok kişi bunu ayarlamak yerine JVM'nin varsayılan değerini kullanır. Özellikle geliştirme ortamında çok sayıda mikro hizmet başlatılırsa bellek taşacaktır.
Spring Boot JVM varsayılan bellek yapılandırma stratejisi iki senaryoya ayrılır: büyük bellek alanı senaryosu ve küçük bellek alanı senaryosu (192 MB'den az).
4 GB bellek örneğinde, başlangıç yığın bellek boyutu ve maksimum yığın bellek boyutu aşağıdaki gibidir:
Spring Boot varsayılan olarak maksimum yığın bellek fiziksel belleğin 1/4'ünü kaplar; uygulama bu sınırı aşarsa OutOfMemoryError istisnası oluşturulur. Başlangıç yığın bellek boyutu fiziksel belleğin 1/64'üdür.
Uygulama bir cep telefonunda çalışıyorsa veya fiziksel bellek 192 MB'den azsa, JVM'nin varsayılan başlangıç yığın bellek boyutu ve maksimum yığın bellek boyutu aşağıdaki gibidir:
Maksimum yığın bellek fiziksel belleğin 1/2'si, başlangıç yığın bellek boyutu ise fiziksel belleğin 1/64'üdür; ancak başlangıç yığın belleği en az 8 MB olduğunda 8 MB olur.

Varsayılan boş yığın bellek %40'ın altına düştüğünde JVM yığını -Xmx üst sınırına kadar artırır; boş yığın bellek %70'in üzerine çıktığında JVM yığını -Xms alt sınırına kadar azaltır.
Bu nedenle, sunucuda genellikle her GC sonrası yığın yeniden boyutlandırmayı önlemek için -Xms ve -Xmx eşit ayarlanır. Bir nesnenin yığın belleği, çöp toplayıcı adı verilen otomatik bir bellek yönetim sistemi tarafından geri kazanılır.
Maksimum yığın bellek, JVM tarafından kullanılan belleğin üst sınırıdır ve gerçek çalışma sürecinde kullanılan miktar kadardır. Varsayılan olarak, yeni nesle ayrılan maksimum alan toplam yığın boyutunun üçte biridir.
Spring Boot bağlamında ilk soruna yanıt olarak, her program varsayılan yapılandırmaya göre başlatılırsa ve bir sunucuya birden fazla uygulama dağıtılırsa bellek sıkıntısı yaşanacak ve belirli bir miktarda israf oluşacaktır. En basit işlem, java -jar başlatma komutu çalıştırılırken ilgili JVM bellek ayar parametrelerini eklemektir.
java -Xms64m -Xmx128m -jar xxx.jar
Proje Docker dağıtımı kullanmaktadır; öncelikle orijinal Dockerfile dosyasına bakalım.
EXPOSE 8061
ADD target/certif-system-2.1.0.jar /certif-system-2.1.0.jar
ENTRYPOINT ["java", "-jar","/certif-system-2.1.0.jar"]
Spring Boot Optimizasyonu
JVM Belleğini Sınırlama
Spring Boot tüm ortam değişkenlerini uygulamaya aktarır; ancak JAVA_OPTS değişkenimiz uygulama için değil, Java çalışma zamanının kendisi içindir. Bu nedenle exec java komutu için $JAVA_OPTS değişkenini kullanmamız gerekir. Bu da Dockerfile dosyasında bazı küçük değişiklikler gerektirir:
ENTRYPOINT exec java $JAVA_OPTS -jar app.jar
Docker run komutunu çalıştırma
Bu, ortam değişkenindeki JAVA_OPTS parametre bilgilerinin çalışma zamanında -e ile sıfırlanarak üzerine yazıldığı anlamına gelir.
docker run -e JAVA_OPTS='-Xmx1344M -Xms1344M -Xmn448M -XX:MaxMetaspaceSize=192M -XX:MetaspaceSize=192M'
java.security.egd rolü
SecureRandom, Java'nın çeşitli bileşenlerinde yaygın olarak kullanılır ve güvenilir bir şekilde rastgele sayılar üretebilir. Ancak çok sayıda rastgele sayının üretildiği senaryolarda performans düşecektir. Bu durumda, rastgele sayı üretim sürecini hızlandırmak için "-Djava.security.egd=file:/dev/./urandom" parametresini kullanabilirsiniz.
Çok sayıda rastgele sayı kullanırken rastgele sayı üreteci olarak /dev/./urandom belirtilmesi önerilir.
Hatanın nedeni için lütfen aşağıdaki kaynak kodun dördüncü satırına dikkat edin. java.security.egd parametresi file:/dev/random veya file:/dev/urandom olarak belirtilirse, parametresiz NativeSeedGenerator yapıcısı çağrılır ve parametresiz yapıcı varsayılan olarak file:/dev/random kullanır. OpenJDK kodu HotSpot kodundan farklıdır; OpenJDK daha sonra rastgele sayı üretirken bu değişkeni kullanmaz.
2. Ubuntu 20 Üzerine Docker Nasıl Kurulur
Spring Boot Giriş
Basit bir Spring Boot uygulaması neredeyse yalnızca bir kullanıcı tarafından kullanıldığında bellek 1,2 GB'a ulaşmaktadır ki bu oldukça kötüdür.
Spring Boot uygulama belleğinin hızla artması
Basit bir Spring Boot uygulaması neredeyse yalnızca bir kullanıcı tarafından kullanıldığında bellek 1,2 GB'a ulaşmaktadır ki bu oldukça kötüdür.
Hizmet durumu
Hizmet sayısı az ve sunucu kaynakları yeterli olduğundan, birçok hizmet JVM parametreleri olmadan başlatılmıştır (eski sorunlar). Sonuç olarak, her hizmet başlangıcı 1,2 GB - 2 GB bellek kaplamaktadır ve bazı hizmetler bu kadarını hiç kullanmamaktadır. Peki, JVM bellek parametresi ayarlanmadığında Spring Boot'ta JVM belleği nasıl yapılandırılır?
Spring Boot JVM varsayılan bellek ayarları
Bir Spring Boot projesini çalıştırırken JVM bellek parametresi ayarlanmazsa, Spring Boot varsayılan olarak JVM'nin kendi varsayılan yapılandırma stratejisini kullanır. Kaynakların yeterli olduğu durumlarda geliştiriciler bellek ayarlarına pek önem vermezler. Ancak kaynak sıkıntısı ve JVM optimizasyonu söz konusu olduğunda, varsayılan JVM bellek yapılandırma stratejisini anlamanız gerekir.
JVM belleğiyle ilgili en yaygın ayarlar başlangıç yığın boyutu (-Xms) ve maksimum yığın belleğidir (-Xmx). Birçok kişi bunu ayarlamak yerine JVM'nin varsayılan değerini kullanır. Özellikle geliştirme ortamında çok sayıda mikro hizmet başlatılırsa bellek taşacaktır.
Spring Boot JVM varsayılan bellek yapılandırma stratejisi iki senaryoya ayrılır: büyük bellek alanı senaryosu ve küçük bellek alanı senaryosu (192 MB'den az).
4 GB bellek örneğinde, başlangıç yığın bellek boyutu ve maksimum yığın bellek boyutu aşağıdaki gibidir:
Spring Boot varsayılan olarak maksimum yığın bellek fiziksel belleğin 1/4'ünü kaplar; uygulama bu sınırı aşarsa OutOfMemoryError istisnası oluşturulur. Başlangıç yığın bellek boyutu fiziksel belleğin 1/64'üdür.
Uygulama bir cep telefonunda çalışıyorsa veya fiziksel bellek 192 MB'den azsa, JVM'nin varsayılan başlangıç yığın bellek boyutu ve maksimum yığın bellek boyutu aşağıdaki gibidir:
Maksimum yığın bellek fiziksel belleğin 1/2'si, başlangıç yığın bellek boyutu ise fiziksel belleğin 1/64'üdür; ancak başlangıç yığın belleği en az 8 MB olduğunda 8 MB olur.

Varsayılan boş yığın bellek %40'ın altına düştüğünde JVM yığını -Xmx üst sınırına kadar artırır; boş yığın bellek %70'in üzerine çıktığında JVM yığını -Xms alt sınırına kadar azaltır.
Bu nedenle, sunucuda genellikle her GC sonrası yığın yeniden boyutlandırmayı önlemek için -Xms ve -Xmx eşit ayarlanır. Bir nesnenin yığın belleği, çöp toplayıcı adı verilen otomatik bir bellek yönetim sistemi tarafından geri kazanılır.
Maksimum yığın bellek, JVM tarafından kullanılan belleğin üst sınırıdır ve gerçek çalışma sürecinde kullanılan miktar kadardır. Varsayılan olarak, yeni nesle ayrılan maksimum alan toplam yığın boyutunun üçte biridir.
Spring Boot bağlamında ilk soruna yanıt olarak, her program varsayılan yapılandırmaya göre başlatılırsa ve bir sunucuya birden fazla uygulama dağıtılırsa bellek sıkıntısı yaşanacak ve belirli bir miktarda israf oluşacaktır. En basit işlem, java -jar başlatma komutu çalıştırılırken ilgili JVM bellek ayar parametrelerini eklemektir.
java -Xms64m -Xmx128m -jar xxx.jar
Proje Docker dağıtımı kullanmaktadır; öncelikle orijinal Dockerfile dosyasına bakalım.
EXPOSE 8061
ADD target/certif-system-2.1.0.jar /certif-system-2.1.0.jar
ENTRYPOINT ["java", "-jar","/certif-system-2.1.0.jar"]
Spring Boot Optimizasyonu
JVM Belleğini Sınırlama
Spring Boot tüm ortam değişkenlerini uygulamaya aktarır; ancak JAVA_OPTS değişkenimiz uygulama için değil, Java çalışma zamanının kendisi içindir. Bu nedenle exec java komutu için $JAVA_OPTS değişkenini kullanmamız gerekir. Bu da Dockerfile dosyasında bazı küçük değişiklikler gerektirir:
ENTRYPOINT exec java $JAVA_OPTS -jar app.jar
Docker run komutunu çalıştırma
Bu, ortam değişkenindeki JAVA_OPTS parametre bilgilerinin çalışma zamanında -e ile sıfırlanarak üzerine yazıldığı anlamına gelir.
docker run -e JAVA_OPTS='-Xmx1344M -Xms1344M -Xmn448M -XX:MaxMetaspaceSize=192M -XX:MetaspaceSize=192M'
java.security.egd rolü
SecureRandom, Java'nın çeşitli bileşenlerinde yaygın olarak kullanılır ve güvenilir bir şekilde rastgele sayılar üretebilir. Ancak çok sayıda rastgele sayının üretildiği senaryolarda performans düşecektir. Bu durumda, rastgele sayı üretim sürecini hızlandırmak için "-Djava.security.egd=file:/dev/./urandom" parametresini kullanabilirsiniz.
Çok sayıda rastgele sayı kullanırken rastgele sayı üreteci olarak /dev/./urandom belirtilmesi önerilir.
Hatanın nedeni için lütfen aşağıdaki kaynak kodun dördüncü satırına dikkat edin. java.security.egd parametresi file:/dev/random veya file:/dev/urandom olarak belirtilirse, parametresiz NativeSeedGenerator yapıcısı çağrılır ve parametresiz yapıcı varsayılan olarak file:/dev/random kullanır. OpenJDK kodu HotSpot kodundan farklıdır; OpenJDK daha sonra rastgele sayı üretirken bu değişkeni kullanmaz.
İlgili Makaleler
-
Veri Depolama İçin 6 İsteğe Bağlı Teknoloji
Bilgi Bankası Ekibi
Daha Fazla Özel Teklifi Keşfedin
-
Kısa Mesaj Hizmeti (SMS) & E-posta Hizmeti
50.000 e-posta paketi 1,99 USD'den, 120 kısa mesaj ise sadece 1,00 USD'den başlayan fiyatlarla sunulmaktadır.
