추적을 사용하여 Lambda: Python의 전체 예시를 검사합니다.

우리는 벌집 AWS Lambda의 열렬한 팬이다.말씀하신 대로 may have read은 최근에 Lambda를 이용하여 더 많은 데이터를 더 짧은 시간 안에 처리함으로써 스토리지 엔진에 중대한 개선을 했습니다.우리의 스토리지 엔진과 같은 복잡한 시스템을 변경하는 것은 두려운 일이지만, 좋은 검사와 추적을 통해 이런 어려움을 줄일 수 있다.이 프로젝트의 경우 라임다에서 기기를 꺼내 벌집으로 들어간다는 의미다.Lambda는 네가 상상하는 것보다 더 복잡하게 만드는 독특한 제한이 있기 때문에 이 글에서 우리는 0부터 응용 프로그램을 소개할 것이다.

응용 프로그램 시작


시작하기 전에 Serverless 프레임워크와 최신 Python 버전이 설치되어 있는지 확인해야 합니다. (저는 3.6을 사용합니다.)이 예에서는 서버 없음 Examples 리포에서 서버 없음 Python TODO API 템플릿을 선택했습니다.나는 이 특수한 프레젠테이션 템플릿을 좋아한다. 왜냐하면 외부 의존항 (DynamoDB) 을 설정했기 때문에 추적할 때 재미있는 것을 볼 수 있기 때문이다.데모 응용 프로그램을 설치하려면 다음과 같이 하십시오.
$ sls install --url https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-dynamodb --name my-sls-app
다음 항목이 포함된 항목 디렉토리가 표시되어야 합니다.
$ cd my-sls-app && ls
README.md    package.json    serverless.yml    todos
우리가 시작하기 전에 보충해야 할 것이 하나 더 있다.애플리케이션에 honeycomb-beeline을 설치하고자 하므로 Python 요구 사항을 패키지화해야 합니다.
# install the serverless-python-requirements module
$ npm install --save-dev serverless-python-requirements
# install beeline-python in a venv, then export the requirements.txt
$ virtualenv venv --python=python3
$ source venv/bin/activate
$ pip install honeycomb-beeline
$ pip freeze > requirements.txt
이제 serverless.yml을 편집하고 다음을 추가합니다.
# essentially, this injects your python requirements into the package
# before deploying. This runs in docker if you're not deploying from a linux host
plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: non-linux
이제 sls deploy을 사용하여 배포할 수 있습니다.
Serverless: Packaging service...
[...]
endpoints:
  POST - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
  GET - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
  GET - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos/{id}
  PUT - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos/{id}
  DELETE - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos/{id}
functions:
  create: my-sls-app-dev-create
  list: my-sls-app-dev-list
  get: my-sls-app-dev-get
  update: my-sls-app-dev-update
  delete: my-sls-app-dev-delete
새 포트에 대한curl 호출은 우리의 상태가 양호하다는 것을 확인합니다.
$ curl https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
# db is empty initially
[]
$ curl -X POST -d '{"text": "write a blog post"}' https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
{"id": "267199de-25c0-11ea-82d7-e6f595c02494", "text": "write a blog post", "checked": false, "createdAt": "1577131779.711644", "updatedAt": "1577131779.711644"}
$ curl https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
[{"checked": false, "createdAt": "1577131779.711644", "text": "write a blog post", "id": "267199de-25c0-11ea-82d7-e6f595c02494", "updatedAt": "1577131779.711644"}]

추적 실현


첫 번째 단계는 선을 초기화하는 것입니다.todos/init.py 파일은 init 코드를 삭제하기에 좋은 곳입니다. 모든 Lambda 프로세서에 끌려갈 수 있습니다.
import beeline
beeline.init(writekey='YOURWRITEKEY', service_name='todo-app', dataset='my-sls-app')
이제 우리가 전에 만든 곱슬머리를 봅시다.이것은 API의 list 함수를 명중시켰다.이것을 열고 계기를 좀 첨가합시다.
# ...

import beeline
from beeline.middleware.awslambda import beeline_wrapper

# The beeline_wrapper decorator wraps the Lambda handler here in a span. By default,
# this also starts a new trace. The span and trace are finished when the function exits
# (but before the response is returned)
@beeline_wrapper
def list(event, context):
    table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])
    beeline.add_context_field("table_name", table)

    # This call to our db dependency is worth knowing about - let's wrap it in a span.
    # That's easy to do with a context manager.
    with beeline.tracer("db-scan"):
        # fetch all todos from the database
        result = table.scan()

    # .. capture any results we want to include from this function call
    beeline.add_context({
        'status_code': 200,
        'num_items': len(result['Items'])
    })

    # create a response
    response = {
        "statusCode": 200,
        "body": json.dumps(result['Items'], cls=decimalencoder.DecimalEncoder)
    }
    return response
그리고 sls deploy.일단 배치하면 나는 다시 권곡을 운행할 수 있다.지금 제 데이터가 집중적으로 추적이 됐어요!

추적은 Lambda가 6.7ms로 실행되는 것을 보여 주지만 클라이언트를 보면 속도가 느린 것 같아서 Lambda 실행 로그를 보았는데 다음과 같습니다.
REPORT RequestId: def28374-1e35-429b-8667-3ab481b61ad4 Duration: 37.27 ms
왜 차이가 나죠?

계기 성능세


람바다 용기의 생명주기는 매우 복잡하다.너는 아마 이미 냉각 시동을 걸었다는 것을 알고 있을 것이다.코드를 호출하기 전에는 제대로 작동하지 않고, 실행할 때 용기가 작동해야 하며, 이것은 초기 호출에 지연을 증가시킨다는 것이다.함수가 응답을 되돌리면 동결 상태로 들어가 실행 중인 모든 라인의 실행을 정지합니다.그곳에서 용기는 추후 요청을 통해 다시 사용하거나 중지할 수 있다.이런 종지는 우아하게 완성되지 않아 운행하는 함수는 내무 처리를 할 기회가 없다.
만약 당신이 원격 측정 데이터를 보내고 싶다면, 이것은 무엇을 의미합니까?
  • 은 일괄 처리를 지연시키는 전형적인 클라이언트 모드(예를 들어 우리의 SDK에서 사용하는 모드)를 사용하는 것은 Lambda에서 신뢰할 수 없습니다. 일괄 처리 전송 루틴이 함수에서 종료된 후에 영원히 실행되지 않을 수도 있기 때문입니다.
  • 함수가
  • 으로 되돌아오기 전에 신뢰할 수 있는 발송이 필요한 모든 내용을 보내야 한다
    이것이 바로 Lambda의 직선 중간부품 코드를 열면 이 줄을 볼 수 있는 이유입니다.
    beeline.get_beeline().client.flush()
    
    이것은 함수가 종료되기 전에 이벤트 비트를 보내는 것을 확보하는 방법입니다.하지만 그것은 공짜가 아니다.이렇게 하면 Lambda에서 우리의 API까지의 왕복 시간을 지연시켜 클라이언트에 대한 응답을 지연시키는 효과가 있다.많은 용례에서, 이것은 람다에서 기기를 얻는 받아들일 수 있는 절충안이다.그러나 만약 응용 프로그램(또는 사용자)이 지연에 민감하다면 어떻게 합니까?

    클라우드워치가 구조 작전을 기록했습니다.


    뚜렷한 막힘 없이 Lambda 함수에서 데이터를 동기화할 수 있는 방법이 있습니다: 로그 기록.
    성능에 영향을 주지 않는 상황에서 상세한 원격 측정을 원한다면 이것은 현재 유일한 방법입니다.모든 Lambda 함수는 자신의 Cloudwatch 로그 흐름을 기록합니다. AWS는 다른 Lambda 함수로 이 흐름을 구독하기 쉽습니다.이곳은 우리가 Honeycomb Publisher for Lambda을 소개하는 곳이다.
    게시자는 하나 이상의 클라우드 워치 로그 흐름을 구독하여 JSON 형식으로 이벤트 데이터를 가져와 정확한 데이터 집합으로 보낼 수 있습니다.그것을 사용하려면, 그것을 배치하고 Lambda 함수의 로그 흐름에 구독한 다음, 프로그램을 로그를 통해 이벤트를 보내는 것으로 설정해야 합니다.

    로그 출력으로 전환


    파이썬 직선을 easy으로 만들어 이벤트 전송 메커니즘을 덮어씁니다.이 곳에서 우리는 내장된 FileTransmission을 사용하여sys에 출력할 것입니다.stdout:
    import sys
    import beeline
    import libhoney
    from libhoney.transmission import FileTransmission
    beeline.init(
        writekey='can be anything',
        service_name='todo-app',
        dataset='my-sls-app',
        transmission_impl=FileTransmission(output=sys.stdout)
    )
    
    우리가 해야 할 일은 벌집 API가 아니라 사건을 클라우드워치로 흐르게 하는 것이다.FileTransmission을 사용할 때 올바른 writekey를 설정할 필요가 없습니다.게시자는 API 트래픽을 검증합니다.
    이 프로그램을 배치한 후에 프로그램을 실행하려면 클라우드워치 로그에서 Lambda 함수의span 데이터를 보아야 합니다.
    { 
        "time": "2019-12-17T16:54:20.355317Z", 
        "samplerate": 1, 
        "dataset": "my-sls-app",
        ...
        "data": {
           "service_name": "todo-app",
           "meta.beeline_version": "2.11.2",
           ...
          "duration_ms": 6.47 
        } 
    }
    
    또한 Lambda는 종료하기 전에 API 호출을 차단하지 않았기 때문에 실행 시간이 더 짧습니다.
    REPORT RequestId: 30ff2be3-2c0b-4869-8da3-7af280dfc76c Duration: 9.41 ms
    

    배포 서버 배포


    Publisher는 또 다른 Lambda 함수이기 때문에 창고에 제3자 Lambda 함수를 집적하는 데 익숙하다면 가장 적합한 도구와 방법을 사용해야 합니다.Dell은 설치를 안내하고 AWS 의존도를 기록하는 유용한 범용 Cloudformation Template을 제공합니다.단, 본 강좌에서 우리가 사용하는 것은 서버가 없기 때문에 프로젝트의'원생'부분으로 사용할 수 있는지 봅시다!
    Serverless를 사용하면 스택과 함께 회전할 수 있는 보조 AWS 리소스를 설명할 수 있습니다.우리의 예에서, 우리가 응용 프로그램을 배치할 때마다, 우리는 발표자와 의존 관계를 강화하기를 바란다.serverless.yml에서 예제 어플리케이션의 resources 블록에 다음 내용을 추가합니다.
    resources:
      Resources:
        TodosDynamoDbTable:
          # ...
        PublisherLambdaHandler:
          Type: 'AWS::Lambda::Function'
          Properties:
            Code:
              S3Bucket: honeycomb-integrations-${opt:region, self:provider.region}
              S3Key: agentless-integrations-for-aws/LATEST/ingest-handlers.zip
            Description: Lambda function for publishing asynchronous events from Lambda
            Environment:
              Variables:
                HONEYCOMB_WRITE_KEY: 'YOURHONEYCOMBKEY'
                DATASET: 'my-sls-app'
            FunctionName: PublisherLambdaHandler-${self:service}-${opt:stage, self:provider.stage}
            Handler: publisher
            MemorySize: 128
            Role:
              "Fn::GetAtt":
                - LambdaIAMRole
                - Arn
            Runtime: go1.x
            Timeout: 10
        ExecutePermission:
          Type: "AWS::Lambda::Permission"
          Properties:
            Action: 'lambda:InvokeFunction'
            FunctionName:
              "Fn::GetAtt":
                - PublisherLambdaHandler
                - Arn
            Principal: 'logs.amazonaws.com'
        LambdaIAMRole:
          Type: "AWS::IAM::Role"
          Properties:
            AssumeRolePolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: "Allow"
                  Principal:
                    Service:
                      - "lambda.amazonaws.com"
                  Action:
                    - "sts:AssumeRole"
        LambdaLogPolicy:
          Type: "AWS::IAM::Policy"
          Properties:
            PolicyName: "lambda-create-log"
            Roles:
                - Ref: LambdaIAMRole
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: Allow
                  Action:
                    - logs:CreateLogGroup
                    - logs:CreateLogStream
                    - logs:PutLogEvents
                  Resource: 'arn:aws:logs:*:*:*'
        # add one of me for each function in your app
        CloudwatchSubscriptionFilterList:
          Type: "AWS::Logs::SubscriptionFilter"
          Properties:
            DestinationArn:
              "Fn::GetAtt":
                - PublisherLambdaHandler
                - Arn
            LogGroupName: /aws/lambda/${self:service}-${opt:stage, self:provider.stage}-list
            FilterPattern: ''
          DependsOn: ExecutePermission
    
    그것은 매우 많은 케케묵은 말이다!주의해야 할 주요 사항은 HONEYCOMB_WRITE_KEY에 유효한 값을 설정하고 창고의 함수마다 SubscriptionFilter 자원을 추가하는 것입니다.sls deploy을 다시 실행하면 Lambda 함수와 함께 배치된 새로운 함수 PublisherLambdaHandler-my-sls-app-dev을 볼 수 있습니다.게시자는 응용 프로그램의 클라우드 워치 로그 흐름을 구독하고 이벤트를 벌집에 전송합니다.

    분산 추적을 사용한 업그레이드


    Lambda 함수는 항상 진공에서 실행되지 않습니다. 보통 더 큰 이벤트 체인의 일부분으로 실행됩니다.분산 추적을 통해 Lambda 플러그를 전체 응용 프로그램 플러그와 연결할 수 있습니다.이를 위해서는 호출된 응용 프로그램에서 Lambda가 지원하는 서비스로 컨텍스트 추적을 전달해야 합니다.우리는 기존 응용 프로그램의 기초 위에서 실제 예를 볼 것이다.우리는 이미 Lambda에서 todo API를 실현했다.UI를 구축하고 있다고 가정합니다.일부 코드는 API에서 항목 목록을 가져와 보여 줍니다.
    @beeline.traced(name="todo_list_view")
    def todo_list_view():
        with beeline.tracer(name="requests_get"):
            todo_list = requests.get('https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos')
    
        render_list(todo_list)
    
    @beeline.traced(name="render_list")
    def render_list(l):
        # ...
    
    todo 항목 목록을 가져오는 HTTP 요청을 requests 라이브러리로 완료합니다.이 get은 요청 시간을 측정하기 위해 추적 범위에 포장되어 있습니다.우리는 list이 추적을 가지고 있다는 것을 알고 있기 때문에 만약 우리가 이 경계를 우리의 추적에 연결할 수 있다면 매우 좋겠다.
    @beeline.traced(name="todo_list_view")
    def todo_list_view():
        with beeline.tracer(name="requests_get"):
            context = beeline.get_beeline().tracer_impl.marshal_trace_context()
            todo_list = requests.get('https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos', 
                                    headers={'X-Honeycomb-Trace': context})
    
        render_list(todo_list)
    
    marshal_trace_context은 서열화된 추적 상하문 대상을 구축하는데 이 대상은 요청 헤더나 부하를 통해 다른 응용 프로그램에 전달할 수 있다.Lambda 중간부품은 자동으로 X-Honeycomb-Trace이라는 헤더를 찾고 상하문 대상을 추출합니다. 새로운 추적을 시작하지 않고 추적 ID와 호출자의span ID를 부항으로 합니다.우리가 해야 할 일은 list 단점을 호출하기 전에 이 상하문 대상을 요청 헤더로 전달하는 것이다.여기에 수동으로 추가 헤더를 보여 주지만, 직선은 요청 라이브러리에 패치를 제공하여 이 작업을 완성할 수 있습니다.beeline.patch.requests 라이브러리를 가져온 후 requests을 응용 프로그램에 가져오기만 하면 됩니다.
    UI 애플리케이션에서 todo_list_view을 호출하면 다음과 같은 두 서비스 범위에 대한 추적이 표시됩니다.

    자신 있게 가다


    Lambda를 사용하여 앱을 구축하고 실행하는 것은 복잡할 수도 있고 도전이 없는 것도 아니지만 분포식 추적과 풍부한 도구가 있으면 어둠 속에서 모색할 필요가 없다.
    당신의 무서버 응용을 위해 기기를 설치할 준비가 되었습니까?Honeycomb for free부터 시작합니다.

    좋은 웹페이지 즐겨찾기