Carbon Aware SDK: İş Yüklerini Zaman ve Mekan Ötesinde Taşıma
BİT sektörü yaklaşık olarak tüketiyor Yılda 460-700 TWh elektrik küresel veri merkezlerinde, Yapay zeka iş yüklerindeki patlama nedeniyle bu rakamın 2030 yılına kadar ikiye katlanması bekleniyor. Ama bunların hepsi değil enerji aynıdır: şebekenin %90'ı elektrikle beslendiğinde bir kilowatt saat üretilir Yenilenebilir enerji, talebin en yüksek olduğu dönemde üretilene kıyasla CO₂ emisyonunun onda birine neden oluyor gaz santralleri tarafından kapsanmaktadır. Uzayda da aynı mantık geçerlidir: Bir işi Avrupa bulut bölgesinde yürütmek temiz enerji karışımıyla enerji sağlanan bir bölgeye göre dört kat daha yeşil olabilir esas olarak kömürden.
Bu kavram — yazılımı çalıştırmak Ne zaman e Nerede elektrik temizleyici - buna denir talep değişimi o karbon farkındalığına sahip bilgi işlem, ve yeşil yazılım mühendisliğinin temel ilkelerinden biridir. Orada Yeşil Yazılım Vakfı bu ilke etrafında referans bir açık kaynak araç seti oluşturmuştur: Karbon Bilinçli SDK, GitHub'da MIT lisansı altında mevcuttur ve UBS, Vestas ve Microsoft gibi şirketler tarafından üretimde kullanılmaktadır.
Bu makalede Carbon Aware SDK'nın içeriden nasıl çalıştığını göreceğiz: mimari, veri kaynakları, REST API, Python, Kubernetes ve GitHub Actions ile entegrasyon. Somut örnekler oluşturacağız zaman değişimi (karbon yoğunluğu düştüğünde bir işi 6-8 saat hareket ettirin) e konum değiştirme (iş yüklerini en yeşil bulut bölgesine yönlendirin gerçek zamanlı olarak).
Ne Öğreneceksiniz
- Carbon Aware SDK nasıl çalışır: WebAPI mimarisi, CLI ve istemci kitaplığı
- Karbon yoğunluğu veri kaynakları: WattTime, ElectricityMaps, Ember Climate
- Zaman kaydırma: toplu işlerin düşük karbon yoğunluklu pencerelerde planlanması
- Konum değiştirme: en temiz enerji karışımına sahip bulut bölgesini seçin
- Carbon Aware SDK istemcisiyle Python entegrasyonu
- Kubernetes + KEDA: uygulama kodunda değişiklik yapmadan karbona duyarlı otomatik ölçeklendirme
- GitHub Eylemleri: Akıllı planlamayla karbona duyarlı CI/CD hattı
- Marjinal ve ortalama karbon yoğunluğu: hangi sinyal kullanılmalı ve neden
- Ölçülebilir emisyon azaltımıyla sınırlar, ödünler ve gerçek kullanım örnekleri
Yeşil Yazılım Mühendisliği Serisi — Tüm Makaleler
| # | Başlık | Ders |
|---|---|---|
| 1 | Yeşil Yazılım Mühendisliğinin İlkeleri | 8 GSF ilkeleri, SCI spesifikasyonu ISO/IEC 21031 |
| 2 | CodeCarbon ile Emisyonların Ölçülmesi | Python, MLflow, kontrol panelinde CO₂ takibi |
| 3 | Climatiq API: Bulut Sistemlerinde Karbon Yoğunluğu | REST API, bulut emisyon hesaplaması ve tedarik zinciri |
| 4 | Carbon Aware SDK (bu makale) | Zaman kaydırma, konum değiştirme, Kubernetes, CI/CD |
| 5 | Kapsam 3 ve ÇSY Boru Hattı | Yukarı/aşağı yönde emisyonlar, CSRD veri hattı |
| 6 | Kapsam 1, 2, 3 modelleme | Sera Gazı Protokolü muhasebe çerçeveleri, SBTi |
| 7 | Yapay Zeka Karbon Ayak İzi | Yüksek Lisans eğitimi, çıkarım, enerji optimizasyonu |
| 8 | Sürdürülebilir Yazılım Kalıpları | Yeşil desen tasarımı, verimli mimariler |
| 9 | Yazılım için ESG ve CSRD | Mevzuata uygunluk, zorunlu AB raporlaması |
| 10 | GreenOps: Sürdürülebilir Operasyonlar | FinOps+GreenOps, operasyonel ölçümler, kültür değişimi |
Talep Kaydırma: Karbon Bilinçli Bilgi İşlemin Arkasındaki Prensip
Bir kilowatt saat elektriğin karbon yoğunluğu sabit değildir; her saat değişir Şebekede ne kadar yenilenebilir enerji bulunduğuna bağlı. Almanya'da güneşli bir günde, karbon yoğunluğu i'nin altına düşebilir 100 gCO₂/kWh saatler içinde enerji santralleri; gece, güneş enerjisinin kapalı olması ve endüstriyel talebin azalmasıyla birlikte, 400 gCO₂/kWh. Aynı değişkenlik uzayda da mevcut: İsveç, beslenen neredeyse tamamen hidroelektrik ve nükleer kaynaklı olup, 15 ila 40 gCO₂/kWh arasında değişirken, Polonya, hâlâ kömüre bağımlıdır ve genellikle 700 gCO₂/kWh'yi aşmaktadır.
Il talep değişimi esnek iş yüklerini taşıyarak bu değişkenlikten yararlanın — toplu işleme, makine öğrenimi eğitimi, yedekleme, veri analizi, CI/CD testi — bu anlara ve bölgelere yönelik elektrik daha temiz. Bu, hesaplamayı bırakmakla ilgili değil: bu, en iyi zamanı seç çalıştırmak için.
Talep Kaydırma Türleri
| Tip | Tanım | Pratik örnek | Tipik CO₂ azaltımı |
|---|---|---|---|
| Zaman Kaydırma | İş yükünü aynı bölgedeki düşük karbon yoğunluklu bir zaman penceresine taşıyın | ML eğitimini öğleden sonra 14:00 yerine 02:00'de çalıştırın | %20-45 |
| Konum Değiştirme | İş yükünü daha temiz bir güç karışımıyla bulut bölgesinde çalıştırın | İşi us-east-1'den eu-north-1'e (Stockholm) yönlendirin | %30-70 |
| Talep Şekillendirme | Karbon yoğunluğunun yüksek olduğu durumlarda sunulan özellikleri azaltın | Emisyonların zirve yaptığı sırada 4K video çözünürlüğünü devre dışı bırakın | %10-25 |
Açıkçası tüm iş yükleri taşınabilir değildir: bir kullanıcının HTTP isteğinin hemen sunulması gerekir, bir finansal işlem bekleyemez. Ancak şaşırtıcı derecede yüksek bir yük yüzdesi kurumsal bilgi işlem esnek zaman: ML model eğitimi, ETL işlem hattı gecelik, rapor oluşturma, yedekleme, güvenlik taramaları, CI/CD hattı. Tam olarak bunlar Karbon bilinçli planlama için ideal adaylar.
Carbon Aware SDK: Mimari ve Bileşenler
Il Karbon Bilinçli SDK Yeşil Yazılım Vakfı'nın açık kaynaklı bir projesidir,
MIT lisansı altında yayınlandı ve şu anda durumda Bitirilen Proje (en yüksek seviye
GSF portföyünün vadesi). Depo GitHub'dadır.
Green-Software-Foundation/carbon-aware-sdk ve esas olarak C# ile geliştirilmiştir.
ASP.NET Core WebAPI, ancak herhangi bir dil tarafından kullanılabilecek arayüzleri ortaya çıkarır.
Mimari modülerdir ve temel bir konsept etrafında döner: tek bir arayüz normalleştirilmiş çıktılar her zaman mevcut olacak şekilde, farklı sağlayıcılardan karbon yoğunluğu verilerine erişmek gCO₂eş/kWh kaynağı ne olursa olsun. Bu çok önemli çünkü her sağlayıcı farklı birimler, coğrafi ayrıntı düzeyi ve hesaplama metodolojileri kullanır.
Carbon Aware SDK'nın Bileşenleri
| Bileşen | Teknoloji | Kullanmak | Ne zaman kullanılmalı? |
|---|---|---|---|
| WebAPI | ASP.NET Çekirdeği (C#), Docker | Swagger/OpenAPI içeren REST API, mikro hizmet olarak dağıtılabilir | Herhangi bir yığınla, mikro hizmet mimarileriyle entegrasyon |
| CLI | dotnet aracı, platformlar arası | Terminal sorgusu, bash/PowerShell komut dosyası oluşturma | Dağıtım komut dosyaları, DevOps otomasyonu, hızlı test |
| SDK Kitaplığı | NuGet paketi (C#) | Uygulama .NET koduna doğrudan entegrasyon | Gömülü karbon farkındalığı gerektiren .NET uygulamaları |
| Python İstemcisi | openapi oluşturucu, Python 3.8+ | WebAPI'nin OpenAPI spesifikasyonundan otomatik olarak oluşturulan istemci | ML işlem hattı, veri mühendisliği komut dosyaları, Airflow DAG |
Tipik akış şu şekildedir: Docker kapsayıcısı olarak WebAPI, karbon yoğunluğu sağlayıcınızın kimlik bilgileriyle yapılandırılır ve uç noktalar sorgulanır Planlama uygulamasından REST. WebAPI verileri normalleştirme ve çağrıları yönetmeyle ilgilenir sağlayıcılara en uygun zaman pencerelerini veya bölgelerini geri gönderin.
Veri Kaynakları: WattTime, ElectricityMaps ve Ember Climate
Carbon Aware SDK, her biri kendi özelliklerine sahip birden fazla karbon yoğunluğu veri sağlayıcısını destekler ve farklı coğrafi kapsam. Sağlayıcı seçiminin önemli ve metodolojik sonuçları vardır (marjinal ve ortalama) ve pratik (kapsam, maliyet, güncelleme sıklığı).
Karbon Yoğunluğu Sağlayıcı Karşılaştırması
| Sağlayıcılar | Sinyal Türü | Kapsam | Sıklık | Tahmin etmek | Maliyet |
|---|---|---|---|---|---|
| Watt Zamanı | Marjinal (MOER) | Tam ABD, 50'den fazla ülke | 5 dakika | 24-72 saat | Sınırlı ücretsiz plan, ticari planlar |
| ElektrikHaritaları | Ortalama (LCA) | 85+ ülke, tam AB | Saatlik/saat altı | 24 saat | Geliştirici ücretsiz, ticari plan |
| Korİklim | Tarihsel ortalama | Küresel (50'den fazla ülke) | Günlük/tarihsel | Hayır (yalnızca tarihsel) | Açık veriler, ücretsiz |
| Statik JSON | Yapılandırılabilir | Gelenek | Manuel | No | Ücretsiz (geliştirme/test) |
Marjinal ve Ortalama Karbon Yoğunluğu: Önemli Bir Ayrım
Sinyal arasındaki seçim marjinal e orta fark bu Karbon bilinçli hesaplamanın en önemli metodolojik yaklaşımıdır ve sonuçlar üzerinde somut çıkarımlara sahiptir. elde edilebilir.
Sinyal marjinal (MOER — Marjinal İşletme Emisyon Oranı)WattTime tarafından sağlanmıştır, şu soruyu yanıtlıyor: "Şu anda tüketimimi 1 kWh artırsaydım hangi santral Bu ek talebi karşılamak için mi faaliyete geçti?”. Cevap neredeyse her zaman yenilenebilir enerji santralleri değil, en esnek gaz santrali ("marjinal jeneratör" olarak da bilinir) zaten maksimumda açık durumdalar. Bu sinyal kararlarla en alakalı sinyaldir Emisyonları azaltmak isteyenlerin gerçek zamanlı olarak sebep oldu artan tüketiminden.
Sinyal ortalama (LCA — Yaşam Döngüsü Ortalaması)ElectricityMaps tarafından sağlanan yanıt sorunun yerine: "Üretilen tüm elektriğin ortalama emisyonu nedir? şu anda ağda mısın?". %50 güneş ve %50 gaz içeren bir şebekede ortalama sinyal ~250 gCO₂/kWh, kenarda ne olursa olsun. Bu sinyal daha ÇSY raporlaması ve piyasa bazlı Kapsam 2 muhasebesi için uygundur.
Önemli: ElectricityMaps'in 2025'teki Yaklaşım Değişikliği
2025 yılında ElectricityMaps, marjinal sinyal süreksizdir API'nizden Verilerin doğrulanabilirliği ve AB düzenlemelerine uyum konusundaki endişeleri dile getirerek ve ABD Kapsam 2 muhasebesinde marjinal faktörlerin kullanımını yasaklamaktadır. ElektrikHaritaları artık yalnızca LCA (Yaşam Döngüsü Değerlendirmesi) metodolojisine dayalı ortalama sinyaller sunuyor. Eğer kullanım durumunuz marjinal sinyal gerektiriyor, WattTime tek ana hizmet sağlayıcı olmaya devam ediyor bu onu destekliyor. Carbon Aware SDK, bu farkı şeffaf bir şekilde ele alır. sağlayıcı yapılandırması.
Hangi Sinyal Ne Zaman Kullanılmalı
| Kullanım Örneği | Önerilen sinyal | Sağlayıcılar | Neden |
|---|---|---|---|
| Zaman değiştiren toplu işler | Marjinal | Watt Zamanı | kaynaklanan emisyonların gerçek azaltımını en üst düzeye çıkarır |
| Çok bölgeli konum değiştirme | Orta veya marjinal | ElectricityMaps veya WattTime | Her ikisi de faydalıdır; daha istikrarlı bölgeler arası ortalama |
| ÇSY / Kapsam 2 raporlaması | Orta | ElektrikHaritaları | Sera Gazı Protokolü ve AB/ABD yönetmeliklerinin gerektirdiği |
| Geliştirme ve test | Statik JSON | Yerel dosya | Maliyet yok, test için deterministik veriler |
Carbon Aware SDK'nın Kurulumu ve Yapılandırması
Carbon Aware SDK'yı yerel olarak başlatmanın en hızlı yolu Docker Compose'dur. Sağlayıcı olarak ElectricityMaps ile tüm yapılandırmayı görelim (en kolay geliştiricilere yönelik ücretsiz API anahtarı sayesinde yapılandırın).
# docker-compose.yml - Carbon Aware SDK WebAPI
version: '3.8'
services:
carbon-aware-api:
image: ghcr.io/green-software-foundation/carbon-aware-sdk:latest
ports:
- "8080:80"
environment:
# Provider: ElectricityMaps (segnale medio LCA)
CarbonAwareVars__CarbonIntensityDataSource: "ElectricityMaps"
CarbonAwareVars__ElectricityMapsClient__APITokenHeader: "auth-token"
CarbonAwareVars__ElectricityMapsClient__APIToken: "${ELECTRICITY_MAPS_TOKEN}"
CarbonAwareVars__ElectricityMapsClient__BaseURL: "https://api.electricitymap.org/v3/"
# Oppure WattTime (segnale marginale MOER)
# CarbonAwareVars__CarbonIntensityDataSource: "WattTime"
# CarbonAwareVars__WattTimeClient__Username: "${WATTTIME_USER}"
# CarbonAwareVars__WattTimeClient__Password: "${WATTTIME_PASS}"
# CarbonAwareVars__WattTimeClient__BaseURL: "https://api2.watttime.org/v2/"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 3
Geliştirme ve test ortamı için, veri gerektirmeyen statik JSON veri kaynağını kullanabilirsiniz. API anahtarı. SDK önceden yüklenmiş örnek veri kümelerini içerir.
# appsettings.json - Configurazione con JSON statico (dev/test)
{
"CarbonAwareVars": {
"CarbonIntensityDataSource": "Json",
"JsonDataFileLocation": "./data/test-data.json",
"Proxy": {
"UseProxy": false
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Kapsayıcı başlatıldıktan sonra Swagger belgelerine şuradan ulaşılabilir:
http://localhost:8080/swagger. Her şeyin bir tane ile çalışıp çalışmadığını kontrol edelim
CLI'ye test çağrısı:
# Installazione Carbon Aware CLI (dotnet tool)
dotnet tool install -g GSF.CarbonAware.Cli
# Verifica emissioni attuali in una location
carbon-aware emissions location --location "westeurope" \
--config ./appsettings.json
# Output esempio:
# Location: westeurope
# Time: 2025-09-15T14:30:00Z
# Rating: 180.5 gCO2eq/kWh
# Duration: PT1H
API Uç Noktaları: Karbon Bilinçli SDK'nın Kalbi
WebAPI, OpenAPI/Swagger ile belgelenen bir dizi REST uç noktasını ortaya çıkarır. Başlıca olanları görelim gerçek çağrı örnekleri ve cevapların yorumlanmasıyla.
GET /emisyonlar/bylocations — Konuma Göre Güncel Emisyonlar
Bir zaman aralığında bir veya daha fazla konum için karbon yoğunluğu verilerini döndürür. Farklı bölgeler arasındaki mevcut karbon yoğunluğunu karşılaştırmak için kullanılır (konum değiştirme).
# Confronto carbon intensity tra regioni cloud (location shifting)
GET /emissions/bylocations?locations=westeurope&locations=eastus&locations=northeurope
&time=2025-09-15T14:00:00Z
&toTime=2025-09-15T15:00:00Z
# Risposta JSON:
[
{
"location": "westeurope",
"timestamp": "2025-09-15T14:00:00Z",
"duration": 60,
"rating": 185.3
},
{
"location": "eastus",
"timestamp": "2025-09-15T14:00:00Z",
"duration": 60,
"rating": 312.7
},
{
"location": "northeurope",
"timestamp": "2025-09-15T14:00:00Z",
"duration": 60,
"rating": 32.1
}
]
# North Europe (Irlanda/Stoccolma) quasi 10x più verde di East US!
GET /emisions/bylocation/best — En İyi Konum
Aralıktaki en düşük karbon yoğunluğuna sahip konumu doğrudan döndürür belirtildi. Otomatik iş yükü yönlendirmesi için idealdir.
GET /emissions/bylocation/best?locations=westeurope&locations=eastus&locations=northeurope
&time=2025-09-15T14:00:00Z
&toTime=2025-09-15T15:00:00Z
# Risposta:
{
"location": "northeurope",
"timestamp": "2025-09-15T14:00:00Z",
"duration": 60,
"rating": 32.1
}
GET /emisyonlar/tahminler/akım — Karbon Yoğunluğu Tahmini
Bu, en güçlü uç noktadır. zaman değişimi: geri döner iş yükünün çalıştırılacağı en uygun zaman aralığıyla birlikte önümüzdeki 24-72 saate ilişkin tahmin. İşin süresini belirterek, söz konusu uzunluktaki en iyi pencereyi bulmanızı sağlar.
GET /emissions/forecasts/current?locations=westeurope
&dataStartAt=2025-09-15T16:00:00Z
&dataEndAt=2025-09-16T16:00:00Z
&windowSize=60
# Risposta con finestra ottimale:
[
{
"generatedAt": "2025-09-15T14:30:00Z",
"location": "westeurope",
"dataStartAt": "2025-09-15T16:00:00Z",
"dataEndAt": "2025-09-16T16:00:00Z",
"windowSize": 60,
"optimalDataPoints": [
{
"location": "westeurope",
"timestamp": "2025-09-16T02:00:00Z",
"duration": 60,
"rating": 95.2
}
],
"forecastData": [
{ "timestamp": "2025-09-15T16:00:00Z", "rating": 195.8 },
{ "timestamp": "2025-09-15T17:00:00Z", "rating": 210.3 },
{ "timestamp": "2025-09-15T18:00:00Z", "rating": 230.1 },
{ "timestamp": "2025-09-15T22:00:00Z", "rating": 155.4 },
{ "timestamp": "2025-09-16T01:00:00Z", "rating": 105.7 },
{ "timestamp": "2025-09-16T02:00:00Z", "rating": 95.2 }, // OTTIMALE
{ "timestamp": "2025-09-16T03:00:00Z", "rating": 98.6 },
{ "timestamp": "2025-09-16T06:00:00Z", "rating": 120.3 }
]
}
]
# Il job da 1 ora dovrebbe partire alle 02:00 UTC (risparmio ~51% CO2 vs ora corrente)
POST /emisyonlar/tahminler/toplu iş — Çoklu Tahminler
Aynı anda birden fazla işi planlamak için toplu tahmin istekleri göndermenize olanak tanır, bağımlılıkları olan karmaşık işlem hatlarını planlamak için kullanışlıdır.
POST /emissions/forecasts/batch
Content-Type: application/json
[
{
"requestedAt": "2025-09-15T14:00:00Z",
"location": "westeurope",
"dataStartAt": "2025-09-15T20:00:00Z",
"dataEndAt": "2025-09-16T08:00:00Z",
"windowSize": 120
},
{
"requestedAt": "2025-09-15T14:00:00Z",
"location": "westeurope",
"dataStartAt": "2025-09-15T20:00:00Z",
"dataEndAt": "2025-09-16T08:00:00Z",
"windowSize": 30
}
]
Python entegrasyonu: CarbonAwareClient ve Zaman Kaydırma
Python işlem hatları için (genellikle veri mühendisliği, makine öğrenimi eğitimi veya toplu analiz) Carbon Aware SDK, OpenAPI spesifikasyonu tarafından otomatik olarak oluşturulan bir Python istemcisi sunar. Bir makine öğrenimi eğitimi işi için eksiksiz bir zaman kaydırma sisteminin nasıl oluşturulacağını görelim.
Python İstemci Kurulumu ve Yapılandırması
# requirements.txt
carbon-aware-sdk-client>=1.0.0 # Client auto-generato da OpenAPI
requests>=2.31.0
python-dateutil>=2.8.2
apscheduler>=3.10.4 # Scheduling job
pytz>=2023.3
# Installazione da PyPI (se disponibile) oppure da sorgente:
# pip install openapi-python-client
# openapi-python-client generate \
# --url http://localhost:8080/swagger/v1/swagger.json
Python'da Carbon Aware istemcisi
"""
carbon_aware_client.py
Client Python per il Carbon Aware SDK WebAPI
Implementa time shifting e location shifting
"""
import requests
from datetime import datetime, timedelta, timezone
from typing import Optional
import logging
logger = logging.getLogger(__name__)
class CarbonAwareClient:
"""
Client per il Carbon Aware SDK WebAPI.
Incapsula le chiamate REST e fornisce metodi ad alto livello
per time shifting e location shifting.
"""
def __init__(self, base_url: str = "http://localhost:8080"):
self.base_url = base_url.rstrip("/")
self.session = requests.Session()
self.session.headers.update({
"Content-Type": "application/json",
"Accept": "application/json"
})
def get_current_emissions(
self,
locations: list[str],
time: Optional[datetime] = None,
to_time: Optional[datetime] = None
) -> list[dict]:
"""
Recupera la carbon intensity corrente per una o più location.
Args:
locations: Lista di location name (es. ["westeurope", "eastus"])
time: Inizio intervallo (default: ora corrente)
to_time: Fine intervallo (default: time + 1 ora)
Returns:
Lista di dict con location, timestamp, rating (gCO2eq/kWh)
"""
now = datetime.now(timezone.utc)
time = time or now
to_time = to_time or (time + timedelta(hours=1))
params = {
"locations": locations,
"time": time.isoformat(),
"toTime": to_time.isoformat()
}
response = self.session.get(
f"{self.base_url}/emissions/bylocations",
params=params
)
response.raise_for_status()
return response.json()
def get_best_location(
self,
locations: list[str],
time: Optional[datetime] = None,
to_time: Optional[datetime] = None
) -> dict:
"""
Trova la location con la più bassa carbon intensity.
Returns:
Dict con location, timestamp, rating della migliore location
"""
now = datetime.now(timezone.utc)
time = time or now
to_time = to_time or (time + timedelta(hours=1))
params = {
"locations": locations,
"time": time.isoformat(),
"toTime": to_time.isoformat()
}
response = self.session.get(
f"{self.base_url}/emissions/bylocation/best",
params=params
)
response.raise_for_status()
return response.json()
def get_optimal_window(
self,
location: str,
window_size_minutes: int,
search_start: Optional[datetime] = None,
search_end: Optional[datetime] = None
) -> dict:
"""
Trova la finestra temporale ottimale (più bassa carbon intensity)
per eseguire un job di durata window_size_minutes nella location indicata.
Args:
location: Location name (es. "westeurope")
window_size_minutes: Durata del job in minuti
search_start: Inizio finestra di ricerca (default: ora corrente)
search_end: Fine finestra di ricerca (default: search_start + 24 ore)
Returns:
Dict con optimalDataPoints (timestamp ottimale) e forecastData
"""
now = datetime.now(timezone.utc)
search_start = search_start or now
search_end = search_end or (search_start + timedelta(hours=24))
params = {
"locations": [location],
"dataStartAt": search_start.isoformat(),
"dataEndAt": search_end.isoformat(),
"windowSize": window_size_minutes
}
response = self.session.get(
f"{self.base_url}/emissions/forecasts/current",
params=params
)
response.raise_for_status()
forecasts = response.json()
if not forecasts:
raise ValueError(f"Nessun forecast disponibile per {location}")
return forecasts[0]
def calculate_carbon_savings(
self,
current_rating: float,
optimal_rating: float,
duration_hours: float,
power_kw: float
) -> dict:
"""
Calcola il risparmio di CO2 del time shifting.
Args:
current_rating: Carbon intensity attuale (gCO2/kWh)
optimal_rating: Carbon intensity ottimale (gCO2/kWh)
duration_hours: Durata del job in ore
power_kw: Potenza media del job in kW
Returns:
Dict con emissioni attuali, ottimali e risparmio
"""
energy_kwh = duration_hours * power_kw
current_emissions_g = current_rating * energy_kwh
optimal_emissions_g = optimal_rating * energy_kwh
savings_g = current_emissions_g - optimal_emissions_g
savings_pct = (savings_g / current_emissions_g) * 100 if current_emissions_g > 0 else 0
return {
"energy_kwh": energy_kwh,
"current_emissions_gco2": round(current_emissions_g, 2),
"optimal_emissions_gco2": round(optimal_emissions_g, 2),
"savings_gco2": round(savings_g, 2),
"savings_percentage": round(savings_pct, 1)
}
Zaman Kaydırma: ML Eğitimi için Zamanlayıcı
"""
ml_training_scheduler.py
Scheduler carbon-aware per job di training ML.
Calcola la finestra ottimale nelle prossime 12 ore
e pianifica l'avvio del training.
"""
from datetime import datetime, timedelta, timezone
from apscheduler.schedulers.blocking import BlockingScheduler
from carbon_aware_client import CarbonAwareClient
import subprocess
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class MLTrainingScheduler:
"""
Scheduler carbon-aware per training ML.
Trova la finestra a più bassa carbon intensity
nelle prossime 12 ore e schedula il training.
"""
def __init__(
self,
location: str = "westeurope",
training_duration_minutes: int = 120,
max_wait_hours: int = 12,
carbon_aware_url: str = "http://localhost:8080"
):
self.location = location
self.training_duration_minutes = training_duration_minutes
self.max_wait_hours = max_wait_hours
self.client = CarbonAwareClient(base_url=carbon_aware_url)
self.scheduler = BlockingScheduler(timezone="UTC")
def find_optimal_start(self) -> datetime:
"""
Interroga il Carbon Aware SDK per trovare
il momento ottimale nelle prossime max_wait_hours.
"""
now = datetime.now(timezone.utc)
search_end = now + timedelta(hours=self.max_wait_hours)
logger.info(
f"Ricerca finestra ottimale in {self.location} "
f"per job da {self.training_duration_minutes} minuti..."
)
forecast = self.client.get_optimal_window(
location=self.location,
window_size_minutes=self.training_duration_minutes,
search_start=now,
search_end=search_end
)
optimal_points = forecast.get("optimalDataPoints", [])
if not optimal_points:
logger.warning("Nessuna finestra ottimale trovata, uso ora corrente")
return now
optimal_timestamp_str = optimal_points[0]["timestamp"]
optimal_timestamp = datetime.fromisoformat(
optimal_timestamp_str.replace("Z", "+00:00")
)
optimal_rating = optimal_points[0]["rating"]
# Recupera rating corrente per calcolo risparmio
current_data = self.client.get_current_emissions([self.location])
current_rating = current_data[0]["rating"] if current_data else 300.0
# Calcola risparmio
savings = self.client.calculate_carbon_savings(
current_rating=current_rating,
optimal_rating=optimal_rating,
duration_hours=self.training_duration_minutes / 60,
power_kw=150 # GPU server: ~150kW stima
)
wait_minutes = (optimal_timestamp - now).total_seconds() / 60
logger.info(
f"Finestra ottimale trovata:\n"
f" Inizio: {optimal_timestamp.strftime('%Y-%m-%d %H:%M UTC')}\n"
f" Carbon intensity: {optimal_rating:.1f} gCO2/kWh\n"
f" Carbon intensity attuale: {current_rating:.1f} gCO2/kWh\n"
f" Attesa: {wait_minutes:.0f} minuti\n"
f" Risparmio CO2: {savings['savings_gco2']:.0f}g ({savings['savings_percentage']}%)"
)
return optimal_timestamp
def run_training(self):
"""Esegue il job di training ML."""
logger.info("Avvio training ML carbon-optimized...")
result = subprocess.run(
["python", "train_model.py", "--config", "config.yaml"],
capture_output=True,
text=True
)
if result.returncode == 0:
logger.info("Training completato con successo")
else:
logger.error(f"Training fallito: {result.stderr}")
def schedule_and_run(self):
"""Trova la finestra ottimale e schedula il training."""
optimal_start = self.find_optimal_start()
now = datetime.now(timezone.utc)
if optimal_start <= now + timedelta(minutes=5):
# Avvio immediato se il momento ottimale è imminente
logger.info("Avvio immediato (finestra ottimale = ora)")
self.run_training()
else:
# Schedula l'avvio
self.scheduler.add_job(
self.run_training,
"date",
run_date=optimal_start,
id="ml_training"
)
logger.info(f"Training schedulato per {optimal_start}")
self.scheduler.start()
# Utilizzo:
if __name__ == "__main__":
scheduler = MLTrainingScheduler(
location="westeurope",
training_duration_minutes=120, # Job da 2 ore
max_wait_hours=12 # Aspetta massimo 12 ore
)
scheduler.schedule_and_run()
Konum Değiştirme: Çok Bölgeli Karbon Bilinçli Yönlendirme
Yer değiştirmek çoğu zaman zaman değiştirmekten daha etkilidir, çünkü aradaki fark
Bulut bölgeleri arasındaki karbon yoğunluğu zamansal değişimden çok daha büyük olabilir
tek bir bölge içerisinde. Yürütülen bir iş
europe-north1 (Finlandiya, ~9 gCO₂/kWh) yerine
asia-east1 (Tayvan, ~550 gCO₂/kWh) emisyonları %98'den fazla azaltır.
Bulut Bölgesine Göre Karbon Yoğunluğu Ortalaması (2025)
| Bulut Sağlayıcıları | Bölge | Konum | Karbon Yoğunluğu Ortalaması (gCO₂/kWh) | Ana Kaynak |
|---|---|---|---|---|
| Google Bulut | Avrupa-Kuzey1 | Finlandiya | 9 | Hidroelektrik, nükleer |
| Azure | İsveç merkezi | İsveç | 18 | Hidroelektrik, nükleer |
| Azure | Kuzey Avrupa | İrlanda | 280 | Rüzgar, gaz |
| AWS | ab-batı-1 | İrlanda | 320 | Rüzgar, gaz |
| AWS | abd-doğu-1 | Virjinya | 380 | Gaz, nükleer, kömür |
| Google Bulut | asya-doğu1 | Tayvan | 545 | Havagazı |
| AWS | ap-güneydoğu-1 | Singapur | 408 | Doğal gaz |
Python: Toplu İşler için Otomatik Konum Değiştirme
"""
location_shifter.py
Location shifting carbon-aware per batch job multi-cloud.
Seleziona automaticamente la regione più verde
per eseguire un job Kubernetes.
"""
from carbon_aware_client import CarbonAwareClient
from datetime import datetime, timezone
import subprocess
import json
import logging
logger = logging.getLogger(__name__)
# Mapping location Carbon Aware SDK -> region cloud reale
LOCATION_TO_CLOUD_REGION = {
"northeurope": {
"aws": "eu-west-1",
"azure": "northeurope",
"gcp": "europe-west1"
},
"swedencentral": {
"azure": "swedencentral",
"gcp": "europe-north1"
},
"westeurope": {
"aws": "eu-central-1",
"azure": "westeurope",
"gcp": "europe-west4"
},
"eastus": {
"aws": "us-east-1",
"azure": "eastus",
"gcp": "us-east1"
}
}
CANDIDATE_LOCATIONS = ["swedencentral", "northeurope", "westeurope", "eastus"]
TARGET_CLOUD = "azure" # Cloud provider di destinazione
class LocationShifter:
def __init__(self, carbon_aware_url: str = "http://localhost:8080"):
self.client = CarbonAwareClient(base_url=carbon_aware_url)
def select_greenest_region(self) -> tuple[str, str, float]:
"""
Seleziona la regione cloud con la più bassa carbon intensity
tra le candidate.
Returns:
Tuple (location_name, cloud_region, carbon_intensity_rating)
"""
best = self.client.get_best_location(
locations=CANDIDATE_LOCATIONS
)
best_location = best["location"]
best_rating = best["rating"]
# Mappa a regione cloud reale
cloud_regions = LOCATION_TO_CLOUD_REGION.get(best_location, {})
cloud_region = cloud_regions.get(TARGET_CLOUD, "westeurope")
logger.info(
f"Regione selezionata: {best_location} -> {TARGET_CLOUD}:{cloud_region}\n"
f"Carbon intensity: {best_rating:.1f} gCO2/kWh"
)
# Log emissioni di tutte le candidate per confronto
all_emissions = self.client.get_current_emissions(CANDIDATE_LOCATIONS)
logger.info("Confronto regioni:")
for em in sorted(all_emissions, key=lambda x: x["rating"]):
marker = " <- SELEZIONATA" if em["location"] == best_location else ""
logger.info(f" {em['location']:20s} {em['rating']:6.1f} gCO2/kWh{marker}")
return best_location, cloud_region, best_rating
def deploy_job_to_region(self, cloud_region: str, job_config: dict):
"""
Deploya un batch job Kubernetes nella regione selezionata.
Usa kubectl con il context della regione target.
"""
# Sostituisce la regione nel manifest Kubernetes
manifest = job_config.copy()
manifest["metadata"]["annotations"]["target-region"] = cloud_region
manifest_json = json.dumps(manifest)
logger.info(f"Deploy job in regione {cloud_region}...")
result = subprocess.run(
["kubectl", "apply", "-f", "-", "--context", f"aks-{cloud_region}"],
input=manifest_json,
capture_output=True,
text=True
)
if result.returncode == 0:
logger.info(f"Job deployato con successo in {cloud_region}")
else:
raise RuntimeError(f"Deploy fallito: {result.stderr}")
def run_carbon_aware_job(self, job_config: dict):
"""Workflow completo: seleziona regione e deploya."""
location, cloud_region, rating = self.select_greenest_region()
logger.info(f"Avvio job carbon-aware in {cloud_region} ({rating:.1f} gCO2/kWh)")
self.deploy_job_to_region(cloud_region, job_config)
# Utilizzo
if __name__ == "__main__":
shifter = LocationShifter()
# Configurazione job Kubernetes
batch_job = {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "data-processing-carbon-aware",
"annotations": {
"green-software.io/carbon-aware": "true",
"target-region": "" # Verrà popolato dal location shifter
}
},
"spec": {
"template": {
"spec": {
"containers": [{
"name": "processor",
"image": "myapp/data-processor:latest",
"resources": {
"requests": {"cpu": "2", "memory": "4Gi"},
"limits": {"cpu": "4", "memory": "8Gi"}
}
}],
"restartPolicy": "Never"
}
}
}
}
shifter.run_carbon_aware_job(batch_job)
Kubernetes ve KEDA: Karbon Bilinçli Otomatik Ölçeklendirme
Microsoft, üretim Kubernetes ortamları için şu sürümü yayımladı: Karbon Bilinçli KEDA Operatörü (Azure GitHub'da açık kaynak), Carbon Aware SDK'yı doğrudan KEDA ölçeklendirme katmanına entegre eden. Prensip basittir: Karbon yoğunluğu düşük olduğunda (temiz enerji mevcuttur), KEDA maksimum kopya sayısına kadar ölçeklenebilir; yüksek olduğunda maksimum sayı çoğaltma sayısı otomatik olarak azaltılır.
Mimarlık üç unsurdan oluşur: Kubernetes Karbon Yoğunluğu Dışa Aktarıcı (Verileri Carbon Aware SDK'dan alın ve orada kümede ConfigMap olarak gösterilir), Karbon Bilinçli KEDA Operatörü (ConfigMap'i okur ve KEDA ölçeklendirme sınırlarını günceller) ve özel kaynak CarbonAwareKedaScaler ölçeklendirme eşiklerini tanımlar.
Karbon Yoğunluğu İhracatçısı kurulumu
# Installa il Carbon Intensity Exporter con Helm
helm repo add azure-carbon https://azure.github.io/carbon-aware-keda-operator
helm repo update
# Crea il secret con le credenziali WattTime
kubectl create secret generic watttime-credentials \
--from-literal=username=MY_WATTTIME_USER \
--from-literal=password=MY_WATTTIME_PASS \
--namespace kube-system
# Installa l'exporter
helm install carbon-intensity-exporter azure-carbon/carbon-intensity-exporter \
--namespace kube-system \
--set carbonDataProvider=WattTime \
--set watttime.username=MY_WATTTIME_USER \
--set watttime.password=MY_WATTTIME_PASS \
--set location=westus \
--set forecastIntervalHours=12
Dışa Aktarıcı Tarafından Oluşturulan ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: carbon-intensity
namespace: kube-system
data:
# Recuperata ogni 12 ore dall'exporter
lastUpdated: "2025-09-15T14:00:00Z"
forecastDateTime: "2025-09-15T14:00:00Z"
message: "Carbon intensity data for westus"
# Array JSON con forecast delle prossime 24 ore
# Format: ISO timestamp + gCO2/kWh
forecastData: |
[
{ "timestamp": "2025-09-15T14:00:00Z", "intensity": 312.5 },
{ "timestamp": "2025-09-15T15:00:00Z", "intensity": 298.3 },
{ "timestamp": "2025-09-15T16:00:00Z", "intensity": 285.1 },
{ "timestamp": "2025-09-15T22:00:00Z", "intensity": 195.7 },
{ "timestamp": "2025-09-16T02:00:00Z", "intensity": 145.2 },
{ "timestamp": "2025-09-16T03:00:00Z", "intensity": 138.9 }
]
# Intensità corrente
currentIntensity: "312.5"
currentIntensityUnit: "gCO2/kWh"
CarbonAwareKedaScaler: Özel Kaynak Tanımı
apiVersion: carbonaware.azure.com/v1alpha1
kind: CarbonAwareKedaScaler
metadata:
name: batch-processor-carbon-scaler
namespace: default
spec:
# Riferimento al KEDA ScaledJob da controllare
kedaTargetRef:
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
name: batch-processor-scaledjob
# Sorgente dati carbon intensity (ConfigMap dell'exporter)
carbonIntensityForecastDataSource:
localConfigMap:
name: carbon-intensity
namespace: kube-system
key: forecastData
mockCarbonForecast: false
# Soglie: definiscono maxReplicas in base all'intensità carbonica
# Ordinate per intensità crescente
# - Se intensità <= 150: max 20 repliche (energia molto pulita)
# - Se intensità <= 300: max 10 repliche (energia moderatamente pulita)
# - Se intensità <= 500: max 4 repliche (energia poco pulita)
# - Se intensità > 500: max 1 replica (energia sporca)
maxReplicasByCarbonIntensity:
- carbonIntensityThreshold: 150
maxReplicas: 20
- carbonIntensityThreshold: 300
maxReplicas: 10
- carbonIntensityThreshold: 500
maxReplicas: 4
Toplu İşleme için ScaledJob KEDA
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
name: batch-processor-scaledjob
namespace: default
labels:
app: batch-processor
green-software.io/carbon-aware: "true"
spec:
# Sorgente trigger: RabbitMQ, Kafka, Azure Queue, ecc.
jobTargetRef:
parallelism: 1
completions: 1
activeDeadlineSeconds: 3600
backoffLimit: 2
template:
metadata:
labels:
app: batch-processor
spec:
containers:
- name: processor
image: myapp/batch-processor:v2.1.0
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2"
memory: "2Gi"
env:
- name: BATCH_SIZE
value: "1000"
- name: OUTPUT_BUCKET
value: "gs://my-processed-data"
restartPolicy: Never
# Trigger: coda Azure Service Bus
triggers:
- type: azure-servicebus
metadata:
queueName: batch-jobs
namespace: my-servicebus-namespace
messageCount: "50"
# Scaling: min 0, max viene controllato dal CarbonAwareKedaScaler
pollingInterval: 60 # Controlla la coda ogni 60 secondi
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 3
minReplicaCount: 0
maxReplicaCount: 20 # Overridato dal CarbonAwareKedaScaler
Karbon Bilinçli KEDA Operatörü Uygulamada Nasıl Çalışıyor?
Carbon Aware KEDA Operatörü her saat başı ihracatçıdan güncellenen ConfigMap'i okur ve günceller
alan maxReplicaCount karşılık gelen eşiğe dayalı olarak KEDA ScaledJob'un
mevcut karbon yoğunluğuna. Kuyrukta 200 iş varsa ve karbon yoğunluğu
312 gCO₂/kWh (300-500 eşiği), KEDA maksimum 10 işçiye kadar ölçeklenebilir
20 yerine. Yoğunluk 150'nin altına düştüğünde (örneğin kuvvetli rüzgarla sabah saat 2:00'de),
limit otomatik olarak 20'ye çıkar ve işler daha hızlı işlenir.
Uygulama kodunda herhangi bir değişiklik yapılmasına gerek yoktur.
Init Container ile Kubernetes CronJob Karbon Farkındalığı
Periyodik olarak programlanan işler için farklı bir model kullanılabilir: başlatma kabı işe başlamadan önce Carbon Aware SDK'yı sorgulayan ve yürütülüp yürütülmeyeceğine veya erteleneceğine karar verir. Bu yaklaşım KEDA gerektirmez ve standart Kubernetes CronJobs.
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-etl-pipeline
namespace: default
annotations:
green-software.io/carbon-aware: "true"
green-software.io/max-intensity: "200"
spec:
# Schedulato per le 00:00 UTC ogni notte
# L'init container deciderà se eseguire o saltare
schedule: "0 0 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 7
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
initContainers:
# Init container che controlla la carbon intensity
- name: carbon-aware-check
image: curlimages/curl:8.5.0
env:
- name: CARBON_AWARE_API
value: "http://carbon-aware-api.monitoring.svc.cluster.local:8080"
- name: LOCATION
value: "westeurope"
- name: MAX_INTENSITY
value: "200"
command:
- sh
- -c
- |
set -e
echo "Controllo carbon intensity per ${LOCATION}..."
# Interroga il Carbon Aware SDK
RESPONSE=$(curl -sf "${CARBON_AWARE_API}/emissions/bylocations?locations=${LOCATION}")
INTENSITY=$(echo "$RESPONSE" | grep -o '"rating":[0-9.]*' | head -1 | cut -d: -f2)
echo "Carbon intensity corrente: ${INTENSITY} gCO2/kWh (massimo: ${MAX_INTENSITY})"
if [ $(echo "${INTENSITY} > ${MAX_INTENSITY}" | bc -l) -eq 1 ]; then
echo "ATTENZIONE: Intensità carbonica troppo alta (${INTENSITY} > ${MAX_INTENSITY})"
echo "Il job verrà rimandato al prossimo ciclo di scheduling"
exit 1 # Fallisce l'init container, il job non parte
fi
echo "OK: Intensità carbonica accettabile. Avvio job ETL..."
exit 0
containers:
- name: etl-pipeline
image: myapp/etl-pipeline:v1.5.0
command: ["python", "run_etl.py"]
env:
- name: PIPELINE_DATE
value: "$(date +%Y-%m-%d)"
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "4"
memory: "8Gi"
restartPolicy: Never
GitHub Eylemleri: Karbon Bilinçli CI/CD İşlem Hattı
CI/CD testi ve derleme hatları, karbon farkındalığı oluşturmanın en kolay iş yükleri arasında yer alıyor. çünkü çoğu aslında zaman açısından esnek: bir entegrasyon test paketi özellikle işlem hatları için geliştirici iş akışını etkilemeden 2-4 saat bekleyebilir gece veya planlanmış.
2024'te yapılan bir araştırma, GitHub Actions'ın tüm ekosistem için karbon ayak izini tahmin etti şu sırayla 450-1000 MTCO₂eş/yıl. Karbon farkındalığına sahip planlamayla yalnızca en ağır iş akışları bile (derlemeyle oluşturma, eksiksiz test paketleri, eğitim modellerde), azalma önemli olabilir.
Karbon Bilinçli Planlama ile İş Akışı GitHub Eylemleri
# .github/workflows/carbon-aware-build.yml
# Pipeline CI/CD carbon-aware con scheduling intelligente
name: Carbon-Aware Build and Test
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
# Scheduled: ogni 6 ore per trovare la finestra migliore
schedule:
- cron: '0 */6 * * *'
workflow_dispatch:
inputs:
force_run:
description: 'Forza esecuzione indipendentemente dalla carbon intensity'
required: false
default: 'false'
env:
CARBON_AWARE_API: ${{ secrets.CARBON_AWARE_API_URL }}
MAX_INTENSITY: "250"
LOCATION: "westeurope"
jobs:
# Job 1: Controlla carbon intensity e decide se procedere
carbon-check:
name: Carbon Intensity Check
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.check.outputs.should_run }}
intensity: ${{ steps.check.outputs.intensity }}
optimal_time: ${{ steps.check.outputs.optimal_time }}
steps:
- name: Check Carbon Intensity
id: check
run: |
# Per PR e push diretti: esegui sempre (developer experience)
if [[ "${{ github.event_name }}" == "push" || \
"${{ github.event_name }}" == "pull_request" || \
"${{ github.event.inputs.force_run }}" == "true" ]]; then
echo "Event: ${{ github.event_name }} - Esecuzione forzata"
echo "should_run=true" >> $GITHUB_OUTPUT
echo "intensity=0" >> $GITHUB_OUTPUT
exit 0
fi
# Per scheduled e manual: controlla carbon intensity
RESPONSE=$(curl -sf \
"${CARBON_AWARE_API}/emissions/bylocations?locations=${LOCATION}" \
--max-time 30) || {
echo "WARN: Carbon Aware API non raggiungibile, esecuzione forzata"
echo "should_run=true" >> $GITHUB_OUTPUT
echo "intensity=-1" >> $GITHUB_OUTPUT
exit 0
}
INTENSITY=$(echo "$RESPONSE" | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(data[0]['rating'] if data else 999)
")
echo "Carbon intensity corrente: ${INTENSITY} gCO2/kWh"
echo "Soglia massima: ${MAX_INTENSITY} gCO2/kWh"
echo "intensity=${INTENSITY}" >> $GITHUB_OUTPUT
if python3 -c "exit(0 if float('$INTENSITY') <= float('$MAX_INTENSITY') else 1)"; then
echo "Intensità accettabile - Avvio build"
echo "should_run=true" >> $GITHUB_OUTPUT
else
echo "Intensità troppo alta - Skip build"
echo "should_run=false" >> $GITHUB_OUTPUT
# Recupera finestra ottimale per info
FORECAST=$(curl -sf \
"${CARBON_AWARE_API}/emissions/forecasts/current?locations=${LOCATION}&windowSize=60")
OPTIMAL=$(echo "$FORECAST" | python3 -c "
import json, sys
data = json.load(sys.stdin)
pts = data[0].get('optimalDataPoints', []) if data else []
print(pts[0]['timestamp'] if pts else 'N/A')
")
echo "optimal_time=$OPTIMAL" >> $GITHUB_OUTPUT
echo "Finestra ottimale: $OPTIMAL"
fi
- name: Summary Carbon Check
run: |
echo "### Carbon Intensity Check" >> $GITHUB_STEP_SUMMARY
echo "| Parametro | Valore |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Location | ${LOCATION} |" >> $GITHUB_STEP_SUMMARY
echo "| Intensity | ${{ steps.check.outputs.intensity }} gCO2/kWh |" >> $GITHUB_STEP_SUMMARY
echo "| Max Threshold | ${MAX_INTENSITY} gCO2/kWh |" >> $GITHUB_STEP_SUMMARY
echo "| Will Run | ${{ steps.check.outputs.should_run }} |" >> $GITHUB_STEP_SUMMARY
# Job 2: Build e test (condizionale alla carbon intensity)
build-and-test:
name: Build and Test
runs-on: ubuntu-latest
needs: carbon-check
if: needs.carbon-check.outputs.should_run == 'true'
steps:
- uses: actions/checkout@v4
- name: Carbon Intensity Badge
run: |
echo "Esecuzione con carbon intensity: ${{ needs.carbon-check.outputs.intensity }} gCO2/kWh"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Test
run: npm test -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
Örnek Olay: %35 CO₂ Azaltmayla ML Eğitimi
Akademik literatürde belgelenen kalıplara dayalı gerçekçi bir vaka çalışması sunuyoruz (Springer Nature, 2024) ve Carbon Aware SDK ile kurumsal uygulamalardan.
Senaryo: E-Ticaret Öneri Modeli Eğitim Hattı
| Parametre | Değer |
|---|---|
| Ajans | Orta ölçekli e-ticaret (500.000 aktif müşteri) |
| İş yükleri | Tavsiye modelinin haftalık eğitimi |
| İşin süresi | 3-4 saat (veri kümesi boyutuna bağlıdır) |
| Donanım | 4x NVIDIA A100 (bulut VM), ~300W toplam |
| Çalıştırma başına enerji tüketimi | ~1,2 kWh |
| Bulut bölgesi | Azure Batı Avrupa (Amsterdam) |
| Sıklık | Haftada bir kez (Pazar gecesi) |
| Zamansal esneklik | 12 saat (Pazar 20.00'den Pazartesi 08.00'e kadar) |
Carbon Aware SDK'nın Benimsenmesinden Önceki ve Sonraki Sonuçlar
Emisyon Karşılaştırması: Öncesi ve Sonrası (yıllık bazda)
| Metrik | Önce (sabit planlama Pazar 22:00) | Sonra (karbona duyarlı zaman kaydırma) | Varyasyon |
|---|---|---|---|
| Uygulama sırasındaki ortalama karbon yoğunluğu | 265 gCO₂/kWh | 172 gCO₂/kWh | -35% |
| Tek çalıştırma başına emisyonlar | 318 gCO₂ | 206 gCO₂ | -112g (-35%) |
| Yıllık emisyonlar (52 çalıştırma) | 16,5 kgCO₂ | 10,7 kgCO₂ | -5,8 kg (-35%) |
| Ortalama zaman kayması | 0 saat | 6,2 saat | Yok |
| 12 saatlik pencerede gerçekleştirilen işler | %100 | %100 | değişmedi |
| Hesaplamalı maliyet | değişmedi | değişmedi | 0% |
Sonucu -%35 CO₂ emisyonu basitçe elde edildi yürütme süresini halihazırda mevcut olan 12 saatlik bir pencereye taşımak. Eğitim kodunda değişiklik yok, ek maliyet yok, işlevsellikte azalma yok. Karbon bilinçli bilgi işlemin gücü budur: çevresel faydaların bir bedeli vardır Zaman açısından esnek iş yükleri için sıfıra yakın çalışma.
Örnek Olay 2: Karbon Farkındalığa Sahip Çok Bölgeli Dağıtım
İkinci bir senaryo ise konuyla ilgili konum değiştirme veri işleme boru hatları için Bunlar küresel olarak dağıtılmış bir veri kümesinde haftalık gruplar halinde çalıştırılır.
Konum Değiştirme Karşılaştırması: Bölgelere Göre Emisyonlar (4 saatlik iş, 500 W)
| Bölge | Karbon Yoğunluğu Ortalaması | Çalıştırma Başına Emisyon (gCO₂) | En İyiye Karşı |
|---|---|---|---|
| asya-doğu1 (Tayvan) | 545 gCO₂/kWh | 1090 gCO₂ | +%11850 (en kötü durum) |
| abd-doğu-1 (Virginia) | 380 gCO₂/kWh | 760 gCO₂ | +%8160 |
| eu-west-1 (İrlanda) | 280 gCO₂/kWh | 560 gCO₂ | +%5933 |
| İsveç merkez (Azure) | 18 gCO₂/kWh | 36 gCO₂ | +%289 |
| Avrupa-Kuzey1 (Finlandiya) | 9 gCO₂/kWh | 9,2 gCO₂ | EN İYİ (Tayvan'a karşı %-99) |
Konum doğru değişiyor europe-north1 onun yerine asia-east1
emisyonları azaltır %99'un üzerinde tamamen aynı iş yükü için.
Açıkça fizibilite, verinin nerede bulunduğuna (veri yoğunluğu), gereksinimlere bağlıdır.
gecikme ve veri yerleşimi düzenlemeleri (GDPR, vb.). Ancak iş yükleri için
aktarılabilir veri kümeleri üzerindeki analizler, mevcut en güçlü kaldıraçtır.
Ulusal Şebeke Operatörlerinin API'leriyle Karşılaştırma
Carbon Aware SDK tarafından yerel olarak desteklenen sağlayıcılara ek olarak, genel API'ler de mevcuttur. karbon yoğunluğu veya enerji karışımı verilerini sağlayan ulusal ağ operatörleri gerçek zamanlı. Bunlar, aşırı yerelleştirilmiş veriler isteyenler veya bunlara bağlı kalmak istemeyenler için faydalıdır. ticari sağlayıcılardan.
Karbon Yoğunluğu için Genel API Izgara Operatörleri
| Operatör | Köy | API'ler | Mevcut Veriler | Notlar |
|---|---|---|---|---|
| Terna | İtalya | şeffaflık.terna.it | RT enerji karışımı, D+1 tahmini | Ücretsiz, REST JSON |
| RTE | Fransa | data.rte-france.com | Enerji karışımı, CO₂ emisyonları, fiyatlar | OAuth2, ücretsiz |
| CAISO | Kaliforniya (ABD) | caiso.com/awe | Yenilenebilir yüzde, karbon yoğunluğu | Ücretsiz, XML/JSON |
| Ulusal Şebeke ESO | UK | carbonintensity.org.uk | Birleşik Krallık bölgesel karbon yoğunluğu | Ücretsiz, REST JSON, tahmin |
| ENTSO-E | Avrupa | şeffaflık.entsoe.eu | Enerji karışımı 40'tan fazla AB ülkesi | Kayıt, SFTP/API |
Birleşik Krallık Karbon Yoğunluğu API'si (Ulusal Şebeke ESO) ile Entegrasyon
Birleşik Krallık'ın Ulusal Şebekesi ESO, özellikle iyi belgelenmiş, ücretsiz, halka açık bir API sunmaktadır. bölgesel veriler, tahminler ve bölgelere göre enerji karışımı ile. Harika bir başlangıç noktası masrafsız denemek isteyenler için.
"""
uk_carbon_intensity.py
Integrazione con API National Grid ESO (UK) per carbon intensity.
Alternativa gratuita per workload in regioni UK.
"""
import requests
from datetime import datetime, timezone
class UKCarbonIntensityClient:
"""
Client per l'API pubblica National Grid ESO.
Documentazione: https://carbon-intensity.github.io/api-definitions/
"""
BASE_URL = "https://api.carbonintensity.org.uk"
def get_current_intensity(self) -> dict:
"""Intensità carbonica attuale per UK nazionale."""
response = requests.get(f"{self.BASE_URL}/intensity")
response.raise_for_status()
return response.json()["data"][0]
def get_regional_intensity(self, region_id: int) -> dict:
"""
Intensità per regione UK specifica.
Region IDs: 1=North Scotland, 6=Yorkshire, 13=South East, ecc.
"""
response = requests.get(f"{self.BASE_URL}/regional/regionid/{region_id}")
response.raise_for_status()
return response.json()["data"][0]
def get_forecast_48h(self) -> list[dict]:
"""Forecast 48 ore per UK nazionale."""
response = requests.get(f"{self.BASE_URL}/intensity/date")
response.raise_for_status()
return response.json()["data"]
def find_optimal_window(self, duration_hours: int = 2) -> dict:
"""
Trova la finestra a più bassa carbon intensity
nelle prossime 48 ore.
"""
forecast = self.get_forecast_48h()
# Calcola media su finestra scorrevole
best_window_start = None
best_avg_intensity = float("inf")
slots_per_window = duration_hours * 2 # Dati ogni 30 min
for i in range(len(forecast) - slots_per_window + 1):
window = forecast[i : i + slots_per_window]
intensities = [
slot["intensity"]["actual"] or slot["intensity"]["forecast"]
for slot in window
if (slot["intensity"]["actual"] or slot["intensity"]["forecast"]) is not None
]
if not intensities:
continue
avg_intensity = sum(intensities) / len(intensities)
if avg_intensity < best_avg_intensity:
best_avg_intensity = avg_intensity
best_window_start = window[0]["from"]
return {
"optimal_start": best_window_start,
"avg_intensity_gco2_kwh": round(best_avg_intensity, 1),
"duration_hours": duration_hours
}
# Utilizzo:
client = UKCarbonIntensityClient()
# Intensità corrente
current = client.get_current_intensity()
print(f"Carbon intensity UK ora: {current['intensity']['actual']} gCO2/kWh")
print(f"Indice: {current['intensity']['index']}") # very low / low / moderate / high / very high
# Finestra ottimale per job da 2 ore
optimal = client.find_optimal_window(duration_hours=2)
print(f"Finestra ottimale: {optimal['optimal_start']}")
print(f"Intensità media: {optimal['avg_intensity_gco2_kwh']} gCO2/kWh")
Sınırlar ve Ödün Vermeler: Gecikme ve Sürdürülebilirlik
Karbon farkındalığına sahip bilgi işlem tavizsiz bir çözüm değildir. Bu temel Çözdüğünden daha fazla sorun yaratmamak için pratik sınırları ve ödünleşimleri anlayın.
Evlat Edinmeden Önce Dikkat Edilmesi Gereken Sınırlar
-
Veri ağırlığı: Bilgisayarınızı taşımak kolaydır ancak verileriniz
aktarılamayacak kadar büyük olması. 10 TB veriye erişen bir iş
us-east-1onu çalıştırmaya değmezeu-north-1transferin elde edilen tasarruftan daha fazla CO₂ yayması durumunda. - Tahmin doğruluğu: 24-72 saatlik karbon yoğunluğu tahminleri zaman ufku ile artan bir hata marjına sahiptirler. Hava koşulları (rüzgar, güneş) 6-12 saatin ötesinde yüksek doğrulukla tahmin etmek zordur.
- Gecikme ve sürdürülebilirlik: Zaman kaydırma, doğal gecikmeyi beraberinde getirir sonuçlarda. Bir veri bilimi ekibi bir eğitim işinin sonuçlarını bekliyorsa, 8 saat geciktirmenin gerçek bir üretim maliyeti vardır.
- Marjinal ve ortalama paradoks: Son araştırmalarda vurgulandığı gibi, marjinal sinyal ve ortalama sinyal için optimizasyon yapılması zıt kararlara yol açabilir. Kullanım durumunuz için yanlış sinyali seçmek emisyonları bile artırabilir.
- Geri tepme etkisi: Karbon bilinçli bilgi işlem tüketimi teşvik ederse "yeşil" saatlerde daha fazla hesaplama yapılırsa net etki sıfır veya negatif olabilir (Yazıma uygulanan Jevons paradoksu).
- Coğrafi kapsam: WattTime ve ElectricityMaps'in kapsama alanı var ABD ve AB'de mükemmel, ancak veri merkezlerinin bulunduğu birçok gelişmekte olan ülkede sınırlıdır. hızla büyüyorlar.
İş Yükü Türüne Göre Fizibilite Matrisi
İş Yükü Türüne Göre Karbon Bilinçli Bilgi İşlemin Uygulanabilirliği
| İş yükü türü | Zaman Kaydırma | Konum Değiştirme | Motivasyon |
|---|---|---|---|
| ML modellerini eğitme | Optimum | Optimum | Yüksek esneklik, yüksek enerji yoğunluğu |
| Toplu ETL hattı | Optimum | İyi | Zamanlayıcı zaten mevcut, veri konumuna bağlı |
| Veri yedekleme ve çoğaltma | Optimum | Sınırlı | Zaman açısından esnek ancak çok bölgeli yedekleme zaten planlanmış |
| Engellenmeyen CI/CD işlem hatları | İyi | İyi | Ekip tarafından kabul edilen bekleme eşiğine bağlıdır |
| Rapor oluşturma | Optimum | Sınırlı | Yüksek zamansal esneklik, SLA gecikmesine bağlıdır |
| API sunumu (gerçek zamanlı) | Uygulanamaz | Sınırlı | SLA gecikmesi zamansal yer değiştirmeye izin vermez |
| İşlemsel veritabanı | Uygulanamaz | Sınırlı | Tutarlılık ve gecikme hareketi engeller |
| Gerçek zamanlı akış (Kafka) | Uygulanamaz | Uygulanamaz | Sürekli, gecikmeye duyarlı, durum bilgisi olan |
Carbon Aware SDK'nın Benimsenmesine İlişkin En İyi Uygulamalar
Karbon Bilinçli Bilgi İşlem Uygulama Kontrol Listesi
- Zaman açısından esnek iş yüklerini belirleyin her şeyden önce: katalog toplu işleri kabul edilebilir esneklik pencereleriyle. En yüksek performanslı işlerle başlayın enerji tüketimi ve maksimum zaman esnekliği.
- Kullanım durumunuz için doğru sağlayıcıyı seçin: Optimizasyon için WattTime gerçek marjinal emisyonların; Piyasa bazlı ÇSY ve Kapsam 2 raporlaması için ElectricityMaps.
- Açık SLA'lar tanımlayın: Kabul edilebilir maksimum bekleme penceresini belirtir her türlü iş için. Bir makine öğrenimi eğitimi 12 saat bekleyebilir; yönetici raporu sabah 9'dan önce hazır olmalı.
- Zarif geri dönüşler uygulayın: Carbon Aware SDK'ya ulaşılamıyorsa veya tahmin kullanılamıyorsa işi normal şekilde çalıştırın. Asla engelleme çevresel optimizasyona yönelik üretim.
- Ölç ve raporla: Karbon yoğunluğu ölçümlerini gösterge tablolarına entegre edin operasyonel. Ekibi motive etmek ve ESG yatırım getirisini göstermek için birikmiş tasarrufları sergileyin.
- Zaman ve konum değiştirmeyi birleştirin: Tasarrufu en üst düzeye çıkarmak, Moment ve bölgenin optimal kombinasyonunu bulun, iki boyutu optimize etmeyin ayrı ayrı.
- Veri aktarımına dikkat edin: Transfer emisyonlarını dikkate alır toplam konum değiştirme hesaplamasındaki veriler. Bazen en iyi "yeşil" bölge veri taşıma maliyeti nedeniyle uygun değildir.
- Carbon Aware SDK'yı sepet veya paylaşılan hizmet olarak dağıtın: hayır her ekibin kendi dağıtımını yapılandırması gerekir. Merkezi bir örnek Önbelleğe alma maliyetleri azaltır ve yönetimi basitleştirir.
TypeScript: Next.js ve Node.js için Carbon-Aware yardımcı programı
// carbon-aware.utils.ts
// Utility TypeScript per integrazione Carbon Aware SDK
// Usabile in Next.js (SSR/cron), Node.js, Deno
interface EmissionsData {
location: string;
timestamp: string;
duration: number;
rating: number;
}
interface OptimalWindow {
optimalTimestamp: string;
rating: number;
currentRating: number;
savingsPercentage: number;
}
export class CarbonAwareUtils {
private readonly baseUrl: string;
constructor(baseUrl: string = process.env.CARBON_AWARE_API_URL ?? 'http://localhost:8080') {
this.baseUrl = baseUrl;
}
/**
* Controlla se la carbon intensity corrente è sotto la soglia.
* Usabile come guard per job schedulati.
*/
async isCarbonIntensityAcceptable(
location: string,
maxIntensityGco2: number
): Promise<{ acceptable: boolean; current: number }> {
try {
const url = new URL(`${this.baseUrl}/emissions/bylocations`);
url.searchParams.append('locations', location);
const response = await fetch(url.toString(), {
signal: AbortSignal.timeout(10_000)
});
if (!response.ok) {
// Fail open: se l'API è down, procedi comunque
console.warn(`Carbon Aware API error: ${response.status}. Proceeding anyway.`);
return { acceptable: true, current: -1 };
}
const data: EmissionsData[] = await response.json();
const current = data[0]?.rating ?? 0;
return {
acceptable: current <= maxIntensityGco2,
current
};
} catch (error) {
// Timeout o rete non disponibile: fail open
console.warn('Carbon Aware API unreachable. Proceeding with job.', error);
return { acceptable: true, current: -1 };
}
}
/**
* Trova la migliore regione cloud per eseguire un job ora.
*/
async getBestRegion(locations: string[]): Promise<EmissionsData> {
const url = new URL(`${this.baseUrl}/emissions/bylocation/best`);
locations.forEach(loc => url.searchParams.append('locations', loc));
const response = await fetch(url.toString());
if (!response.ok) {
throw new Error(`Carbon Aware API error: ${response.status}`);
}
return response.json() as Promise<EmissionsData>;
}
/**
* Trova la finestra temporale ottimale per le prossime N ore.
*/
async getOptimalWindow(
location: string,
jobDurationMinutes: number,
searchHours: number = 24
): Promise<OptimalWindow | null> {
const now = new Date();
const searchEnd = new Date(now.getTime() + searchHours * 60 * 60 * 1000);
const url = new URL(`${this.baseUrl}/emissions/forecasts/current`);
url.searchParams.append('locations', location);
url.searchParams.append('dataStartAt', now.toISOString());
url.searchParams.append('dataEndAt', searchEnd.toISOString());
url.searchParams.append('windowSize', jobDurationMinutes.toString());
const response = await fetch(url.toString());
if (!response.ok) return null;
const forecasts = await response.json() as Array<{
optimalDataPoints: Array<{ timestamp: string; rating: number }>;
forecastData: Array<{ timestamp: string; rating: number }>;
}>;
const forecast = forecasts[0];
if (!forecast?.optimalDataPoints?.length) return null;
const optimal = forecast.optimalDataPoints[0];
const currentRating = forecast.forecastData[0]?.rating ?? 0;
const savingsPercentage = currentRating > 0
? Math.round(((currentRating - optimal.rating) / currentRating) * 100)
: 0;
return {
optimalTimestamp: optimal.timestamp,
rating: optimal.rating,
currentRating,
savingsPercentage
};
}
}
// Decorator per funzioni che supportano carbon-aware execution
export function carbonAware(
location: string,
maxIntensity: number = 300
) {
return function (
_target: object,
_propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: unknown[]) {
const client = new CarbonAwareUtils();
const { acceptable, current } = await client.isCarbonIntensityAcceptable(location, maxIntensity);
if (!acceptable) {
console.log(`Job skipped: carbon intensity ${current} gCO2/kWh > threshold ${maxIntensity}`);
return null;
}
console.log(`Job starting: carbon intensity ${current} gCO2/kWh (threshold: ${maxIntensity})`);
return originalMethod.apply(this, args);
};
return descriptor;
};
}
Sonuçlar: Operasyonel Standart Olarak Karbon Farkında Bilgi İşlem
Carbon Aware SDK, günümüzde en olgun ve en iyi desteklenen aracı temsil etmektedir. uygulamak talep değişimi kurumsal yazılım sistemlerinde. Bir API ile Standart REST, büyük veri sağlayıcıları için destek (WattTime, ElectricityMaps) ve Kubernetes/KEDA ve GitHub Actions için hazır entegrasyonlar, maliyetleri önemli ölçüde azaltır Yeşil yazılım mühendisliğinin benimsenmesinin önündeki teknik engel.
Sonuçlar somut ve belgelenmiştir: İş yükleri nedeniyle emisyonlarda %20-45 azalma Zaman kaydırmalı toplu iş, Avrupa bölgelerine konum değiştirmeyle %99'a kadar hidroelektrik ve nükleer. Ve kilit nokta, bu tasarrufların sıfıra yakın işletme maliyeti: Farklı donanım gerektirmezler, azalmazlar uygulama özellikleri bulutun maliyetini artırmaz.
Yön net: büyük bulut sağlayıcıları ölçümleri entegre ediyor konsollarındaki karbon yoğunluğu (AWS Müşteri Karbon Ayak İzi Aracı, Google Cloud Carbon Ayak İzi, Azure Emisyonları Etki Kontrol Paneli). Karbon farkındalığına sahip bilgi işlem, bugün fark yaratan bir özellik ileri düzeyde, önümüzdeki yıllarda kuruluşlar için standart bir gereklilik haline gelecektir ESG ve CSRD düzenlemelerine tabidir. Şimdi başlamak, beceri ve altyapı edinmek anlamına gelir önceden.
Sonraki Adımlar
-
Keşfedin resmi depo su
github.com/Green-Software-Foundation/carbon-aware-sdkve başlat İlk deneyleri yapmak için JSON yapılandırmasıyla yerel olarak Docker konteyneri API anahtarı olmadan. - Serideki önceki makaleyi okuyun: Climatiq API: Karbon Yoğunluğu nei Bulut SistemleriEmisyonları optimize etmeden önce nasıl ölçüleceğini anlamak.
- Şununla devam et: Kapsam 3 ve ÇSY Boru Hattı karbon verilerini entegre etmek CSRD'nin gerektirdiği kurumsal sürdürülebilirlik raporlamasındaki yoğunluk.
- ML modelleriyle çalışıyorsanız daha derine inin Yapay Zeka Karbon Ayak İzi nerede tüm eğitim + çıkarım döngüsünü teknikler aracılığıyla nasıl optimize edeceğimizi görelim Karbon bilinçli planlama ve model verimliliğinin birleşimi.
- Kayıt ol Yeşil Yazılım Vakfı ücretsiz bir destekçi olarak topluluğa, teknik web seminerlerine ve sertifika programına erişim "Yeşil Yazılım Uygulayıcısı".
Kaynaklar ve Referanslar
- Carbon Aware SDK — Yeşil Yazılım Vakfı:
carbon-aware-sdk.greensoftware.foundation - GitHub Deposu:
github.com/Green-Software-Foundation/carbon-aware-sdk - Azure Karbon Bilinçli KEDA Operatörü:
github.com/Azure/carbon-aware-keda-operator - WattTime API Belgeleri:
docs.watttime.org - ElectricityMaps API'si:
portal.electricitymaps.com/developer-hub/api - Birleşik Krallık Karbon Yoğunluğu API'si:
carbonintensity.org.uk - Springer 2024: "Karbon açısından verimli Yüksek Lisans eğitimi için zaman kaydırma stratejileri"
- MDPI Sürdürülebilirlik 2025: "Uç Bulutta Karbon Farkındalığı Olan Uzay-Zamansal İş Yükünün Değiştirilmesi"
- Yeşil Yazılım Vakfı SCI Şartnamesi: ISO/IEC 21031:2024







