TL;DR

「五」更有趣一点

一、概念梳理

  1. 前情提要@midway/faas 是原生 serverless 模式的开发,但是目前还在演化中,个人的使用体验是离成熟还挺远
  2. 我想要的是 @midway 的语法糖,和原生 serverless
  3. deployType: egg 从外观上看满足了这个要求

二、锁版本

# dep
@midwayjs/cli@1.2.32
@midwayjs/decorator@2.4.7
@midwayjs/web@2.5.4
egg@2.29.1
egg-scripts@2.13.0
egg-view-nunjucks@2.2.0

# devDep
@midwayjs/egg-ts-helper@1.0.4

# 部分不影响本文但确是核心的依赖并没有列出来

三、提供接口

  1. 标准 egg 应用目录结构,没有特别的,把你的旧代码复制过来就能用
src/
  app/
    controller/
      api.ts
  config/
    config.default.ts

# app/controller/api.ts
@Provide()
@Controller('/')
export class ApiController {
  
  @Inject()
  ctx: Context;

  @Inject()
  dataService: DataService;
  
  @Get('/api/fetch-data')
  async fetchData(@Query('pn') pageNo: number=1, @Query('ps') pageSize: number=10) {
    const { page, data } = await this.dataService.fetchData(pageNo, pageSize);
    return { code: 0, message: 'ok', page, data };
  }
}
  1. package.json 关键配置:要指定 framework@midway/web
"scripts": {
  "start": "egg-scripts start --title=bilibili --framework=@midwayjs/web --env=prod",
  "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts"
},
"egg": {
  "framework": "@midwayjs/web"
},
  1. package.json 关键配置:ts 要手动构建,这里把钩子设在了生命周期的发布前阶段
"midway-integration": {
  "lifecycle": {
    "before:package:cleanup": "npm run build"
  }
},
  1. f.yml 关键配置:deployType: egg
  2. f.yml 关键配置:可以按前缀将一类请求都指向这个服务
functions:
  myservicename:
    runtime: nodejs12
    handler: index.handler
    events:
      - http:
          path: /api/*
    environment:
      FORCE_COLOR: 0

四、提供静态资源

  1. 和三实际上是一样的,这就是 deployType: egg 美妙之处,可以理解为后端真的起了一个 egg 应用,而不是像 faas 模式那样封装了一个长得很像 egg 的东西
# f.yml 概念代码,实际配置参考三
functions:
events:
- http:
  /api/*
  /public/*

五、那这不就是普通的 egg 吗,套娃了?

  1. 最近反微服务反中台的论调又多了起来,我司执行微服务(伪)中台(伪)也挺久了,最直观的感觉就是,对微服务种种的不满意,解决方案都是还不够微,粒度还是太粗了
  2. 老板说前端要千人千面,千是个虚指,翻译过来实际上是 2 亿人 2 亿面,似乎很有道理无法反驳,但是后端就区区 300 个应用就开始闹合并了,什么 SOLID / DRY 都来了,为啥呀
  3. 很多讨论 serverless 的文章都说是为了节省预算,然后反驳的文章都说实际上没有节省预算,300 个应用换成 300 个 serverless 当然不省预算,但是 2 亿个呢
  4. Serverless 是一种思想状态,它能让你更专注于解决眼前的问题,而不被原有代码影响,因为这里只有当前的代码,没有其它代码
  5. 解决需求变更的最好的方式,就是按需求收费,来一个需求做一套「系统」,然后等那些没有流量的「系统」自然淘汰

image

  1. 选择 traefik 的原因是它自带的 docker 模式很好用
  2. 选择 envoy 而不是 nginx 的原因是看上去前者应该就是未来了
  3. 终端客户认为自己购买了一个产品的四种功能,但实际上这四个功能是由四个独立团队分别开发的

image

六、为什么 serverless 这个事情是前端的同学比较上心

image

  1. 因为前端常年以来就是以「需求」为粒度开发的,「npm」的体量和质量就是很好的说明,正是因为有很多低质量的包,才说明这是一个活跃的市场;而且那些低质量的包,很有可能在某个场景粒度是性价比最好的
  2. serverless 不但可以让前端快速地响应客户的需求,也可以让中台更快速地响应前端的需求
  3. 甲方爸爸永远是对的,服务数量指数式激增管不了是乙方自己的问题

七、一些小技巧

  1. 同时开 n 个项目,node_modules 真的很占空间,所以必须要上 lerna
# 目录结构
packages/
  appa/
    package.json
    f.yml -> service: myappname, function: appa, path: /a/*
  appb/
    package.json
    f.yml -> service: myappname, function: appb, path: /b/*
lerna.json

# 在根目录执行
$ lerna run dev --scope appa --stream
$ lerna run deploy --scope appa --stream
  1. 阿里云函数计算的日志是以 service 为单位的,所以上述多个 package 子应用的日志部分配置必须一致,否则会互相覆盖
# f.yaml
service:
  name: myappname

provider:
  name: aliyun
  logConfig:
    project: myprojectname
    logstore: myappname

参考文献:

  1. Egg/Midway 应用迁移
  2. Serverless 是一种思想状态

系列文章:
阿里云函数计算(Midway FaaS)一探
阿里云函数计算(@Midway/Egg-Layer)二探


理斯特
18 声望9 粉丝

web/mobile/iot, front/back, js/java