Blog
Die Säule der Nachhaltigkeit eines gut durchdachten Frameworks und Neuigkeiten von der re:Invent - Club Cloud Stories #5

In dieser Weihnachtsausgabe von Club Cloud Stories sprechen wir über ein paar Highlights von AWS Re:Invent 2021:
- Gut durchdachtes Rahmenwerk Säule Nachhaltigkeit
- re:Post
- Graviton 3 Prozessor
- Amplify Studio
- Rust SDK
- CDK v2
Während der re:Invent 2021 wurden eine Menge neuer Funktionen angekündigt. Für die Weihnachtsausgabe von Club Cloud Stories wollte ich einige "Zutaten" für eine Demo sammeln, um einige der neu angekündigten Funktionen auszuprobieren.
Zutaten
Die neue Säule der Nachhaltigkeit des Well Architected Framework fordert uns auf, möglichst wenig verschwenderische Ressourcen zu verwenden. Letztendlich werden alle Cloud-Berechnungen von irgendeinem Prozessor ausgeführt. Wenn uns also die Umwelt am Herzen liegt, sollten wir besser damit beginnen, die von AWS entwickelten Graviton ARM-Prozessoren zu verwenden: Graviton 1: billiger, aber weniger leistungsfähig als Intel/AMD Graviton 2: bis zu 40% schneller als Intel/AMD, und sie kosten 20% weniger Graviton 3: bis zu 50% schneller als Intel/AMD, und sie kosten 20% weniger und verbrauchen bis zu 60% weniger Energie Zutat 1: Graviton für Nachhaltigkeit Um einen solchen Prozessor optimal zu nutzen, müssten Sie eine kompilierte Sprache verwenden. Andernfalls würden Sie einige Taktzyklen für das Parsen verschwenden. Da ich für die Demo eine Lambda verwenden möchte, scheinen nur Go und .Net Core verfügbar zu sein, aber einige Nachforschungen haben ergeben, dass Sie Rust in einer so genannten 'Custom Runtime' ausführen können. Da das Rust SDK ebenfalls auf der re:Invent angekündigt wurde, haben wir unsere zweite Zutat gefunden: Zutat 2: Rust SDK (in einem Lambda) CDK v2 wurde ebenfalls angekündigt, warum also nicht dieses verwenden, um ein Beispiel einzurichten. Inhaltsstoff 3: CDK v2
0. Voraussetzungen
Ich fürchte, das ist eine ganze Reihe von Voraussetzungen:
- AWS-Konto
- AWS-Befehlszeilen-Tool
- nodejs
- Typoskript -
npm -g install typescript - CDK -
npm install -g aws-cdk - Rust
- Rust Cross-Kompilierung für ARM -
rustup target add aarch64-unknown-linux-gnu - Docker
1. Erstellen Sie ein Rust echo lambda ARM binary
Es werden nur 4 Dateien benötigt, damit das echo Lambda kompiliert werden kann. Cargo.toml erstellen
[Paket] name = "clubclouddemo" version = "0.1.0" edition = "2021"
[Abhängigkeiten] lambda_runtime = "0.4.1" tokio = "1.14.0" log = "0.4.14" simple_logger = "1.15.0" serde_json = "1.0.72"
src/main.rs erstellen
use lambda_runtime::{handler_fn, Error};
use serde_json::{Value};
use simple_logger::SimpleLogger;
#[tokio::main]
async fn main() -> Result<(), Error> {
SimpleLogger::new().with_level(log::LevelFilter::Info).init().unwrap();
let func = handler_fn(my_handler);
lambda_runtime::run(func).await?;
Ok(())
}
pub(crate) async fn my_handler(event: Value, _ctx: lambda_runtime::Context) -> Result<Value, Error> {
Ok(event)
}
Dockerdatei erstellen
FROM docker.io/rust:latest
WORKDIR /var/app
RUN mkdir -p src/ && echo "fn main() {}" > src/main.rs && uname -a
COPY Cargo.toml Cargo.lock .
RUN cargo build --release --target aarch64-unknown-linux-gnu
COPY src src
RUN cargo build --release --target aarch64-unknown-linux-gnu
CMD cat target/aarch64-unknown-linux-gnu/release/clubclouddemo
Build.sh erstellen
#!/bin/bash
LAMBDA_ARCH="linux/arm64" # set this to either linux/arm64 for ARM functions, or linux/amd64 for x86 functions.
docker build . -t localhost/clubclouddemo --platform ${LAMBDA_ARCH}
mkdir -p lambda
docker run --platform ${LAMBDA_ARCH} --rm localhost/clubclouddemo > lambda/bootstrap
(Sie müssen chmod +x build.sh verwenden, um den Befehl ./build.sh nutzen zu können)
Elvin Luff hat mir geholfen, eine Dockerdatei einzurichten, die das Layering hier nutzt. Die Cross-Kompilierung nach ARM kann jedes Mal sehr lange dauern, da die Abhängigkeiten nicht zwischengespeichert werden. Die hier verwendete Dockerdatei kompiliert die Abhängigkeiten nur neu, wenn sich die toml-Datei ändert. Das spart eine Menge Zeit!
2. Stellen Sie die Binärdatei mit CDK v2 auf AWS bereit.
Sobald Sie ein erstes CDK for typescript-Projekt mit CDK V2 eingerichtet haben, sollte die folgende Datei in lib/yourname-stack.ts abgelegt werden. Eine schöne Neuerung bei CDK V2 ist, dass alle AWS-Standardkonstrukte in einer Bibliothek enthalten sind. Das bedeutet, dass Sie nicht jede einzelne API, die Sie verwenden, installieren müssen. Abgesehen davon habe ich keine wesentlichen Änderungen an CDK gesehen.
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class BackendStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const server = new lambda.Function(this, "ClubCloudDemo", {
functionName: 'EchoLambda',
runtime: lambda.Runtime.PROVIDED_AL2,
code: lambda.Code.fromAsset("../binaries/clubclouddemo/lambda"),
handler: 'not.required',
architecture: lambda.Architecture.ARM_64
});
}
}
Das Verzeichnis, auf das ../binaries/clubclouddemo/lambda verweist, sollte die im vorherigen Schritt erstellte Binärdatei enthalten und bootstrap heißen.
4. Echo Echo Echo Echo
In der AWS-Konsole habe ich die Leistung des erstellten Lambdas getestet. Er lieferte Antwortzeiten von unter einer Millisekunde. Solche Reaktionszeiten habe ich bei der Verwendung von Python oder Nodejs noch nie gesehen. Für 1 $ können Sie diesen Lambda etwa 500 Millionen Mal aufrufen (ohne die Kosten für den Netzwerkverkehr). Das bringt natürlich nichts, daher werde ich im nächsten Abschnitt das Rust SDK verwenden, um einige Dinge mit DynamoDB zu tun.
3. Machen Sie etwas Nützlicheres mit dem Rust SDK
Die folgenden 2 Dateien sind erforderlich, um eine neue Binärdatei zu erstellen. Die toml-Dateien enthalten ein paar zusätzliche Abhängigkeiten. Sie können dieselbe Dockerdatei und build.sh wie bei der vorherigen Binärdatei verwenden.
Außerdem wird eine DynamoDB-Tabelle namens Blog mit PK als Partitionsschlüssel (String), SK als Sortierschlüssel (String) und einem globalen Index auf SK und SRT (ebenfalls String) benötigt.
[package]
name = "clubclouddemo"
version = "0.1.0"
edition = "2021"
[dependencies]
lambda_runtime = "0.4.1"
tokio = "1.14.0"
log = "0.4.14"
simple_logger = "1.15.0"
serde = "1.0.131"
serde_json = "1.0.72"
aws-config = "0.2.0"
aws-types = "0.2.0"
aws-sdk-dynamodb = "0.2.0"
Die folgende Datei ist recht umfangreich, daher habe ich nur die interessanten Teile in diesen Artikel aufgenommen (den vollständigen Quellcode finden Sie in meinem Git-Repository). Im Wesentlichen verwende ich das Rust SDK, um zwei verschiedene Abfragen auf eine DynamoDB-Tabelle (Index) durchzuführen. Die Routinen, die über die zurückgegebenen Ergebnisse iterieren, unterstützen das Paging. Da das Rust SDK so neu ist, sind bei der Google-Suche kaum Beispiele dafür zu finden. Vielleicht ist dies sogar eine weltweit erste Implementierung dieser Funktion. Schließlich teste ich die Ausführung dieser Abfragen sowohl seriell als auch parallel. (Rust unterstützt Threading und async/await durch die Verwendung von Tokio).
fn type_query(client: &Client, key: &String) -> aws_sdk_dynamodb::client::fluent_builders::Query {
client
.query()
.table_name("Blog")
.index_name("GSI1")
.limit(20)
.key_condition_expression("#key = :value".to_string())
.expression_attribute_names("#key".to_string(), "SK".to_string())
.expression_attribute_values(":value".to_string(), AttributeValue::S(key.to_string()))
}
fn author_query(client: &Client) -> aws_sdk_dynamodb::client::fluent_builders::Query {
type_query(client, &"USER".to_string())
}
#[derive(Clone, Debug, Serialize, Deserialize)]
struct Author {
id: String,
name: String,
}
async fn get_authors(client: &Client) -> HashMap::<String, Author> {
let mut last: Option<HashMap<String, AttributeValue>> = None;
let mut result = HashMap::<String, Author>::new();
loop {
match author_query(&client)
.set_exclusive_start_key(last)
.send()
.await {
Ok(resp) => {
if let Some(recs) = &resp.items {
for item in recs {
let auth = Author {
id: item["PK"].as_s().ok().unwrap().to_string(),
name: item["SRT"].as_s().ok().unwrap().to_string()
};
result.insert(auth.id.to_owned(), auth);
}
}
if let Some(lev) = resp.last_evaluated_key() {
last = Some(lev.to_owned())
} else {
break;
}
}
Err(e) => {
println!("error {}", e);
break;
}
}
}
return result;
}
Die serielle Ausführung benötigt 12 Millisekunden, während die parallele Version etwa 5 Millisekunden benötigt (bei Verwendung von 3 USER-Datensätzen und 10 POST-Datensätzen in der DynamoDB-Tabelle). Das bedeutet, dass Sie dieses Lambda für 1 $ noch etwa
Frühere Episoden
Cloud Club Geschichten #4 Cloud Club Geschichten #3 Cloud Club Geschichten #2 Cloud Club Geschichten #1 Juli 2021 Mai 2021 April 2021 Bild von PublicDomainPictures aus Pixabay
Verfasst von

Jacco Kulman
Jacco is a Cloud Consultant at Binx.io. As an experienced development team lead he coded for the banking- and hospitality- and media-industries. He is a big fan of serverless architectures. In his free time he reads science fiction, contributes to open source projects and enjoys being a life-long-learner.
Unsere Ideen
Weitere Blogs
Contact



