AWSラムダRustランタイムとAWS SDK Rustを使用したさびにラムダを書く


先週、私はさびとAWSラムダサービスで実験する機会を得ました.私は、さびに書かれたHTTPトリガラムダ関数を書くことを学び、それをノードで書かれた同様のラムダ関数と比較しました.js

何が計画ですか。



要するに、私は、HTTPイベントを扱うことができて、S 3からオブジェクトを得ることができるラムダを持つために、aws-lambda-rust-runtimeaws-sdk-rustのReadmesに続きました.主な手順は次のとおりです.
  • Rust Toolchainをインストールしました(そしてMacを使用している場合は、MUSICクロスを使用しているので、MacからLinuxをコンパイルすることができます.
  • HTTPイベントを扱うことができるラムダ関数を書くAwsLabs aws-lambda-rust-runtimeこんにちはhttp例に従ってください.
  • は、S 3クライアントAPIを使用するために貨物依存性としてAWSLAB aws-sdk-rustを加えます.
  • メールを受信し、対応するユーザのデータをS 3から取得するラムダロジックを書き込みます.
  • AWS環境で一緒に物事を配線します.
  • 類似のノードで初期化と実行期間を比較します.ラムダ関数.
  • ラストインストール


    これは、例で覆われていない場合は、- Rustup錆をインストールするには、推奨される方法であり、簡単に新しいビルドターゲットを追加できるようになります.

    AWSラムダRustランタイムREADMEに従って、例をコンパイルし、AWS上で実行します


    このセクションでは、小さなHTTPの例でaws-lambda-rust-runtime READMEについて説明します.
  • 新しいツールチェーンターゲットを追加しました.
  • rustup target add x86_64-unknown-linux-musl
    
  • MUSLクロスコンパイラのインストールと設定
  • brew install filosottile/musl-cross/musl-cross
    mkdir ~/.cargo
    echo $'[target.x86_64-unknown-linux-musl]\nlinker = "x86_64-linux-musl-gcc"' > .cargo/config
    
  • は、hello-httpの例をコンパイルし、AWS用にラップします
  •   cargo build -p lambda_http  --example hello-http --release --target x86_64-unknown-linux-musl
    
    実行可能ファイルの名前を変更し、ZIPラムダカスタムランタイムがどのようになるかを確認します.
      cp ./target/x86_64-unknown-linux-musl/release/examples/hello-http ./bootstrap && zip lambda.zip bootstrap && rm bootstrap
    
  • AWSで新しいラムダ関数を作成します.私はAWSコンソールを使ってそれをしました、「カスタム・ランタイム」を選ぶことはあなた自身のブートストラップをアマゾンLinux 2に提供して、そこにZIPファイルをアップロードしました.

  • 私もHTTPゲートウェイを作成しました.

    依存性としてAWS SDK Rust S 3クライアントを加えてください


    aws-sdk-rustは開発中で、「アルファ」だけがリリースされるさびのための新しいAWS SDKです.私はちょうどS 3クライアントをそれから使用しました.
    [dependencies]
    ...
    s3 = {git = "https://github.com/awslabs/aws-sdk-rust", tag = "v0.0.15-alpha", package = "aws-sdk-s3"}
    
  • 私は、AWS SDK Rust/S 3に関連していると思いますが、どうにか、ring Crateを使用して、私はMUSLのためのものをコンパイルしようとしました.
  •   error: failed to run custom build command for `ring v0.16.20`
      ...
      No such file or directory (os error 2)', /Users/user/.cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/build.rs:653:9
    
    Macでは、TargetRencc環境変数を追加することが私にとって解決されました(いくつかのGithubの問題を見ましたが、今は見つけられません.Linuxマシンでは、MUSLパッケージをインストールするためのソリューションです)
      export TARGET_CC=x86_64-linux-musl-gcc
    
    最後に、以下のようになります.
      Finished release [optimized] target(s) in 2m 01s
    

    私たちのさびGetHorseユーザーデータラムダハンドラ関数


    私はコメントすることができますので、ここで徹底的に行くコードはそんなに長くはない.
    (認証なしのおもちゃの例ですので、実データでこれを使用するのは安全ではありません).
    // lambda_http imports
    use lambda_http::{
    
        // runtime related imports
        handler,
        lambda_runtime::{self, Context, Error},
    
        // imports that define the signature of our lambda
        IntoResponse, Request, RequestExt,
    };
    
    // used to calculate sha2 of user's email
    use sha2::{Digest, Sha256};
    
    // used to get user data from s3
    use s3::Client;
    
    #[tokio::main]
    async fn main() -> Result<(), Error> {
        lambda_runtime::run(handler(get_user_data)).await?;
        Ok(())
    }
    
    
    // this is our lambda 
    // get_user_data is a lambda that returns user data given it's email in query parameters (assuming the user authenticated somewhere else!)
    // from the signature you can see that it handles `Request` objects and returns things that can turn `IntoResponse`
    async fn get_user_data(event: Request, _: Context) -> Result<impl IntoResponse, Error> {
    
        // get email from query string params
        let params = event.query_string_parameters();
        let email = params.get("email").unwrap();
    
            // hash it and encode
        let hash = Sha256::new().chain(email).chain("some-salt").finalize();
        let hash = base64::encode(hash);
    
        // calculate key of s3 object with the hash above
        let key = format!("user-data/{}/some.json", hash);
    
        // use s3 API to get this object from s3
        let s3 = Client::from_env();
        let result = s3
            .get_object()
            .bucket("my-bucket")
            .key(key)
            .response_content_type("application/json")
            .send()
            .await?;
    
        // return the content as a response
        let data = result.body.collect().await?;
        let response = String::from_utf8(data.into_bytes().to_vec())?.into_response();
    
        Ok(response)
    }
    
    // TODO - handle errors
    // TODO - do something smarter than from_utf8(data.into_bytes().to_vec())
    // TODO - JWT authentication
    
    // Please comment below with suggestions/feedback 
    

    AWS環境で一緒に物事を配線する


    コンパイルして、Zoodupして、AWSにアップロードされた後に、あなたはラムダがS 3にアクセスするのを許容しなければなりません(さもなければ、あなたはそれをテストするとき、アクセス拒否の応答を得ます).
    私がしたことは、S 3の上で私のテストバケットとオブジェクトを作成することでした、そして、次に、ラムダUIから、「パーミッション」の下で新しい役割を加えてください、そして、私のテストオブジェクトのためにちょうどs 3読み込みアクセスを与える方針で.

    ノードと比較する。JS実施


    ノードの同様の論理.JSは次のようになります.
    //  a lambda that returns user data given it's email in query parameteres (assuming the user authenticated somewhere else!)
    const S3 = require("aws-sdk/clients/s3");
    const crypto = require("crypto");
    
    exports.handler = async (event) => {
      const email = event.queryStringParameters.email;
    
      const s3 = new S3();
      const hash = crypto
        .createHash("sha256")
        .update(email)
        .update("some-salt")
        .digest("base64");
    
      const params = {
          Bucket: "my-bucket",
          Key: `user-data/${hash}/some.json`,
        }
    
      const data = await s3
          .getObject({
            Bucket: "my-bucket",
            Key: `user-data/${hash}/some.json`,
          })
          .promise();
    
      const data = data.Body.toString("utf-8");
    
      const response = {
            statusCode: 200,
            body: data,
        };
        return response;
    };
    
    
    AWSラムダはノードをサポートします.JPランタイムので、実際に新しいノード機能を作成することができますし、コンソールでコードを直接編集することができます🙃).
    両方のラムダを同じポリシーとテストセットアップで実行します(実行中にラムダがスリープ状態になるのを待つことなく)
    # each line is a new run.
    # first run in each block is after few minutes of inactivity]
    # followed by 4 consecutive runs
    
    # Rust
    Duration: 358.57 ms Billed Duration: 393 ms Memory Size: 128 MB Max Memory Used: 31 MB  Init Duration: 33.60 ms 
    Duration: 39.76 ms  Billed Duration: 40 ms  Memory Size: 128 MB Max Memory Used: 31 MB  
    Duration: 52.98 ms  Billed Duration: 53 ms  Memory Size: 128 MB Max Memory Used: 31 MB  
    Duration: 49.17 ms  Billed Duration: 50 ms  Memory Size: 128 MB Max Memory Used: 31 MB  
    Duration: 50.71 ms  Billed Duration: 51 ms  Memory Size: 128 MB Max Memory Used: 31 MB  
    
    # node.js
    Duration: 915.67 ms Billed Duration: 916 ms Memory Size: 128 MB Max Memory Used: 81 MB  Init Duration: 236.67 ms
    Duration: 90.40 ms  Billed Duration: 91 ms  Memory Size: 128 MB Max Memory Used: 81 MB
    Duration: 331.29 ms Billed Duration: 332 ms Memory Size: 128 MB Max Memory Used: 81 MB
    Duration: 320.97 ms Billed Duration: 321 ms Memory Size: 128 MB Max Memory Used: 81 MB
    Duration: 267.81 ms Billed Duration: 268 ms Memory Size: 128 MB Max Memory Used: 81 MB
    
    私がそれを得るならば
  • 錆の中で実際のメモリ使用量が低い(両方の128 MBのランタイムで実行された)
  • 初期化期間は錆でより低いです(多分私は私のNode . js実装で何か悪いことをしていますか?)
  • 実行持続時間は錆の方が低い(いくつかのテストでは、ノードラムダはかなり近い)
  • 側の注意:上記のおもちゃの例では、実際にラムダの中のデータを読む必要がないので、合理的なアプローチは、オブジェクトにURLをプレサインし、URLをユーザに返すことです.
    const params = {
          Bucket: "my-bucket",
          Key: `user-data/${hash}/user.json`,
          Expires: 60
    }  
    
    const url = s3.getSignedUrl('getObject', params);
    
    これは実行時間を大幅に改善しますが、AWS SDK Rustではまだ実装されていません.この機能を追跡するgithub issueがあり、それをサポートする他の錆S 3クライアントがあります.
    それは、-読書をありがとう、私は今さびを学習しており、あなたのフィードバックに感謝します!