网钛远程桌面管理助手
当前位置:首页 > 服务器资讯

服务器资讯

Serverless之Framework――图文玩转 AWS Lambda

时间:2020-10-16 04:31:15   作者:   来源:   阅读:151   评论:0
内容摘要: 即将开播:4月29日,民生银行郭庆谈商业银行金融科技赋能的探索与实践--> 前言微服务架构有别于传统的单体式应用方案,我们可将单体应用拆分成多个核心功能。每个功能都被称为一项服务,可以单独构建和部署,这意味着各项服务在工作时不会互相影响这种设计理念被进一步应用,就变......
即将开播:4月29日,民生银行郭庆谈商业银行金融科技赋能的探索与实践-->

 前言

微服务架构有别于传统的单体式应用方案,我们可将单体应用拆分成多个核心功能。每个功能都被称为一项服务,可以单独构建和部署,这意味着各项服务在工作时不会互相影响

这种设计理念被进一步应用,就变成了无服务(Serverless)。「无服务」看似挺荒唐的,其实服务器依旧存在,只是我们不需要关注或预置服务器。这让开发人员的精力更集中——只关注功能实现

Serverless 的典型便是 AWS Lambda

AWS Lambda

如果你是 Java 开发人员,你应该听说过或使用过 JDK 1.8 里面的 Lambda,但是 AWS 中的 Lambda 和 JDK 中的 Lambda 没有任何关系

这里的 AWS Lambda 就是一种计算服务,无需预置或管理服务器即可运行代码,借助 Lambda,我们几乎可以为任何类型的应用程序或后端服务运行代码,而且完全无需管理,我们要做的只是上传相应的代码,Lambda 会处理运行和扩展 HA 代码所需的一切工作

说的直白一点

Lambda 就好比实现某一个功能的方法 (现实中,通常会让 Lambda 功能尽可能单一),我们将这个方法做成了一个服务供调用

到这里你可能会有个困惑,Lambda 既然就是一个「方法」,那谁来调用?或怎么来调用呢?

如何调用 Lambda

为了回答上面这个问题,我们需要登陆到 AWS,打开 Lambda 服务,然后创建一个 Lambda Function (hello-lambda)

Lambda 既然是个方法,就要选择相应的 Runtime 环境,如下图所示,总有一款适合你的(最近在用 Node.js, 这里就用这个吧)

点击右下角的 Create function 按钮进入配置页面

在上图红色框线的位置就可以配置出发 Lambda 的触发器了,点击 Add trigger

从上图可以看出,AWS 内置的很多服务都可以触发 Lambda,我在工作中常用的有:

API Gateway (一会的 demo 会用到,也是最常见的调用方式)

  • ALB - Application Loac Balancer
  • CloudFront
  • DynamoDB
  • S3
  • SNS - Simple Notification Service
  • SQS - Simple Queue Service

上面只是 AWS 内置的一些服务,向下滑动,你会发现,你也可以配置很多非 AWS 的事件源

到这里,上面的问题你应该已经有了答案了。这里暂时先无需任何 trigger,先点击右上角的 Test 测试一下 Lambda

一个简单的 Lambda Function 就实现了,红色框线的 response 只是告诉大家,每个请求都会有相应的 Request ID,更有 START/END 标识快速定位 Log 内容 (可以通过 CloudWatch 查看,这里暂不展开说明)

你也可能已经开始发散你的思维了,如何运用 AWS Lambda,其实在 AWS 官网有很多样例:

经典案例

比如为了适应多平台图片展示,一张原始图片上传到 S3 后,会通过 Lambda resize 适应不同平台大小的图片

比如使用 AWS Lambda 和 Amazon API Gateway 构建后端,以验证和处理 API 请求,当某一个用户发布一条动态,订阅用户将收到相应的通知

接下来我们就用 Lambda 实现经典的分布式订单服务案例

订单服务 Demo

为了增强用户使用体验,或者为了提升程序吞吐量,亦或是为了架构设计程序解耦,考虑到以上这些情况,我们通常都会借助消息中间件来完成

假设有一常见场景,用户下订单时如果选择开具发票,则需要调用发票服务,很显然调用发票服务不是程序运行的关键路径,这种场景,我们就可以通过消息中间件来解耦。这里有两个服务:

  1. 订单服务
  2. 发票服务

如果用 Lambda 来实现两个服务,整体设计思想就是这样滴:

现实中,我们不可能在 AWS console 通过点击按钮来创建各个服务的,在 AWS 实际开发中, 我们通过写 CloudFormation Template (以下会简称 CFT,其实就是一种 YAML 或者 JSON 格式的定义)来创建相关 AWS 服务,如果上述这个 Demo,从图中可以看出,我们要创建的服务还是非常多的:

  • Lambda * 2
  • API Gateway
  • SQS

如果写 AWS 原生的 CFT,要实现的内容还是挺多的

但是...... 懒惰的程序员总是能带来很多惊喜

Serverless Framework

写 JDBC 麻烦,就有了各种持久层框架的出现,同样写 AWS 原生 CFT 麻烦,就有了 Serverless Framework (以下会简称 SF)的出现帮助我们定义相关 Serverless 组件 (顺便问一下,GraphQL 你们有在用吗?)

SF 不但简化了 AWS 原生 CFT 的编写,还简化了跨云服务的定义,就好比设计模式当中的 Facade,在上面建立了一层门面,隐藏了底部不同服务的细节,降低了跨云并用云的门槛,目前支持的云服务有下面这些

这里暂时不会对 SF 展开深入的说明,在我们的 demo 中只不过是要应用 SF 来定义

安装 Serverless Framework如果你有安装 Node,那只需要一条 npm 命令全局安装即可:

  1. npm update -g serverless 

安装过后检查一下安装版本是否成功

  1. sls -version 

配置 Serverless Framework

由于要使用 AWS 的 Lambda,所以要对 SF 做基本的配置,至少要让 SF 有权限创建 AWS 服务,当你创建一个 AWS 用户时,你可以获取 AK 「access_key_id」和 SK 「secret_access_key」(不是 SKII 哦),其实就是一种用户名和密码形式

然后通过下面一条命令添加配置就可以了:

  1. serverless config credentials --provider aws --key 1234 --secret 5678 --profile custom-profile 
  • --provider 云服务商
  • --key 你的AK
  • --secret 你的SK
  • --profile 如果你有多个账户时,你可以添加这个 profile 做快速区分

运行上述命令后,就会在 ~/.aws/目录创建一个名为 credentials 的文件存储上述配置,就像这样:

到这里准备工作就都完成了,开始写我们的定义就好了

创建 Serverless

应用通过下面一条命令创建 serverless 应用

  1. sls create --template aws-nodejs --path ./demo --name lambda-sqs-lambda 
  • --template 指定创建的模版
  • --path 指定创建的目录
  • --name 指定创建的服务名称

运行上述命令后,进入 demo 目录就是下面这个结构和内容了

  1. ➜  demo tree 
  2. ├── handler.js 
  3. └── serverless.yml 
  4.  
  5. 0 directories, 2 files 

因为我们是用 Node.js 来编写 Serverless 应用,同样在 demo 目录下执行下面命令来初始化该目录,因为我们后面要用到两个 npm package

  1. npm init -y 

现在的结构是这样的(其实就多了一个 package.json):

  1. ➜  demo tree 
  2. ├── handler.js 
  3. ├── package.json 
  4. └── serverless.yml 
  5.  
  6. 0 directories, 3 files 

至此,准备工作都已就绪,接下来就在 serverless.yml 中写相应的定义就可以了 (门槛很低:按照相应的 key 写 YAML 即可,是不是很简单?),打开 serverless.yml 文件来看一下,瞬间懵逼?

  1. # Welcome to Serverless! 
  2. # This file is the main config file for your service. 
  3. # It's very minimal at this point and uses default values
  4. # You can always add more config options for more control. 
  5. # We've included some commented out config examples here. 
  6. # Just uncomment any of them to get that config option
  7. For full config options, check the docs: 
  8. #    docs.serverless.com 
  9. # Happy Coding! 
  10.  
  11. service: lambda-sqs-lambda 
  12. # app and org for use with dashboard.serverless.com 
  13. #app: your-app-name 
  14. #org: your-org-name 
  15.  
  16. # You can pin your service to only deploy with a specific Serverless version 
  17. Check out our docs for more details 
  18. # frameworkVersion: "=X.X.X" 
  19.  
  20. provider: 
  21.   name: aws 
  22.   runtime: nodejs12.x 
  23.  
  24. # you can overwrite defaults here 
  25. #  stage: dev 
  26. #  region: us-east-1 
  27.  
  28. # you can add statements to the Lambda function's IAM Role here 
  29. #  iamRoleStatements: 
  30. #    - Effect: "Allow" 
  31. #      Action
  32. #        - "s3:ListBucket" 
  33. #      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  } 
  34. #    - Effect: "Allow" 
  35. #      Action
  36. #        - "s3:PutObject" 
  37. #      Resource: 
  38. #        Fn::Join
  39. #          - "" 
  40. #          - - "arn:aws:s3:::" 
  41. #            - "Ref" : "ServerlessDeploymentBucket" 
  42. #            - "/*" 
  43.  
  44. # you can define service wide environment variables here 
  45. #  environment: 
  46. #    variable1: value1 
  47.  
  48. # you can add packaging information here 
  49. #package: 
  50. #  include: 
  51. #    - include-me.js 
  52. #    - include-me-dir/** 
  53. #  exclude: 
  54. #    - exclude-me.js 
  55. #    - exclude-me-dir/** 
  56.  
  57. functions: 
  58.   hello: 
  59.     handler: handler.hello 
  60. #    The following are a few example events you can configure 
  61. #    NOTE: Please make sure to change your handler code to work with those events 
  62. #    Check the event documentation for details 
  63. #    events: 
  64. #      - http: 
  65. #          path: users/create 
  66. #          method: get 
  67. #      - websocket: $connect 
  68. #      - s3: ${env:BUCKET} 
  69. #      - schedule: rate(10 minutes) 
  70. #      - sns: greeter-topic 
  71. #      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 
  72. #      - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx 
  73. #      - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx 
  74. #      - iot: 
  75. #          sql: "SELECT * FROM 'some_topic'" 
  76. #      - cloudwatchEvent: 
  77. #          event: 
  78. #            source: 
  79. #              - "aws.ec2" 
  80. #            detail-type: 
  81. #              - "EC2 Instance State-change Notification" 
  82. #            detail: 
  83. #              state: 
  84. #                - pending 
  85. #      - cloudwatchLog: '/aws/lambda/hello' 
  86. #      - cognitoUserPool: 
  87. #          pool: MyUserPool 
  88. #          trigger: PreSignUp 
  89. #      - alb: 
  90. #          listenerArn: arn:aws:elasticloadbalancing:us-east-1:XXXXXX:listener/app/my-load-balancer/50dc6c495c0c9188/ 
  91. #          priority: 1 
  92. #          conditions: 
  93. #            host: example.com 
  94. #            path: /hello 
  95.  
  96. #    Define function environment variables here 
  97. #    environment: 
  98. #      variable2: value2 
  99.  
  100. # you can add CloudFormation resource templates here 
  101. #resources: 
  102. #  Resources: 
  103. #    NewResource: 
  104. #      Type: AWS::S3::Bucket 
  105. #      Properties: 
  106. #        BucketName: my-new-bucket 
  107. #  Outputs: 
  108. #     NewOutput: 
  109. #       Description: "Description for the output" 
  110. #       Value: "Some output value" 

乍一看,你可能觉得眼花缭乱,其实这是一个相对完整的 Lambda 配置全集,我们不需要这么详细的内容,不过这个文件作为我们的参考

接下来我们就定义 demo 所需要的一切 (关键注释已经写在代码中)

  1. service: 
  2.   name: lambda-sqs-lambda # 定义服务的名称 
  3.  
  4. provider: 
  5.   name: aws # 云服务商为 aws 
  6.   runtime: nodejs12.x # 运行时 node 的版本 
  7.   region: ap-northeast-1 # 发布到 northeast region,其实就是东京 region 
  8.   stage: dev # 发布环境为 dev 
  9.   iamRoleStatements: # 创建 IAM role,允许 lambda function 向队列发送消息 
  10.     - Effect: Allow 
  11.       Action
  12.         - sqs:SendMessage 
  13.       Resource: 
  14.         - Fn::GetAtt: [ receiverQueue, Arn ] 
  15.        
  16. functions: # 定义两个 lambda functions 
  17.   order
  18.     handler: app/order.checkout # 第一个 lambda function 程序入口是 app 目录下的 order.js 里面的 checkout 方法 
  19.     events: # trigger