LWDW!

Learn the work from doing the work🍺

R项目小结
Posted on 2023-01-09

最近结束的一个项目有很多值得学习的地方,挑一些不敏感的在此记录。其中的每一点其实都有深入挖掘的空间,日后想必会再次遇到。


文档设计

有哪些文档可以整理归总?有的文档适合单独总结,有的适合放在Readme中,但总之,以下是一些可以考虑的点。

系统设计文档

这里的设计指的是系统的架构,尤其要关注系统之间是如何连接的

而以下内容不应该被包含在其中:

  • 服务的具体细节。
  • 组件的设计模式。

组件文档

整理所有的组件/服务,可以有以下关注点:

  • 介绍
  • 服务类型(比如SSR /Static)
  • 路由前缀
  • 生产环境域名
  • 预发环境域名
  • 测试环境域名(规则)
  • 仓库地址
  • 流水线地址
  • 发布分支
  • 涉及技术栈

开发者FAQ

目的是收集开发者关心的常见问题,比如项目如何本地启动,必要权限如何申请等。

开发者验证指南

目的是保证开发者提交的组件可以在生产环境中运行,而不是完全依赖QA。常见的手段有测试用例,code review等,且很可能与CI/CD流程有关。个人觉得开发者很容易对一些小改动有迷之自信,结果却提交无法在测试环境运行的代码甚至搞崩线上。该步骤非常重要又容易被忽视。

AWS服务

aws服务太常见了,稍微记录一下我本次接触的,不至于一些名词都没有概念。

ECS

ECS is Amazon Elastic Container Service.

  • Container Orchestration Service (容器编排工具)
  • Manages the whole container lifecycle.
    • start
    • re-schedule
    • load balance
  • ECS Cluster(ECS集群)是Control Plane,管理所有运行着容器的虚拟机器。

How does ECS work

  • 而这些虚拟机是什么?是EC2 Instance,你还是需要管理这些Instance的,比如在增加container的时候,需要确保Instance的资源足够。
  • 但如果我们想在AWS上hosting infrastructure。可以用AWS Fargate。那就不需要手动管理Instance,他会根据你想要运行的container来自动分配资源。节省呀!

EKS

EKS is Elastic Kubernetes Service.

Kubernetes 是ECS的竞品,非常Popular,所以EKS就是为了在AWS使用Kubernetes推出的。

EKS的工作方式和ECS差不多。

ECR

ECR is Elastic Container Registry, a private docker registry.

whole story, Jenkins involved here!

ELB

ELB is Elastic load balancing service.

负载均衡服务

使用这样一个 load balancer有很多好处

  • 将流量分配给了很多下级实例
  • 只暴露出一个入口(DNS)
  • 无缝处理下级应用的failures
  • 对实例进行健康检查
  • 提供https
  • 强制使用cookies,所以用户可以访问到同一个instance

AWS lambda

这是一个Serverless服务,基本上可以理解为它提供了根据事件自动触发Function的能力。

其中事件可以指的是S3的内容变化,API的请求,或其他各种各样的AWS服务事件。

这里涉及到一个概念,Serverless,值得说一说。

我个人的理解是这样的:

首先Serverless并不是说没有Server,而是Server对用户不可见,which means:

  • 不需要手动管理server。
  • 会根据使用自动扩容。
  • 只有当被使用的时候,才会产生费用(而不是为Server本身付费)。

环境变量

环境变量 in Next.js

Before const HOST_NAME = 'www.sample.com'.

After const HOST_NAME = 'process.env.NEXT_PUBLIC_HOST_NAME'.

这里涉及到Next.js的一个特性:expose env vars to the browser

  • During the build stage, next.js will find these env vars start with NEXT_PUBLIC_ and replace them with literal.
  • build stage很关键,在CI/CD流程中,可能有build、release等多个环节,在哪里传入环境变量很关键。

Trick: 如果在一些情形下,我们需要把用于node端的环境变量暴露给浏览器,可以怎么做?

  export const getServerSideProps = () => {
    // we can read server side env vars here.
    return {
      serverConstants: {
        TEST_HOST_NAME: process.env.TEST_HOST_NAME
      }
    }
  }
  
  // client side.
  export const Page = (props) => {
    const { serverConstants } = props;
    return (
      <p>TEST_HOST_NAME: {serverConstants.TEST_HOST_NAME}</p>
    )
  }

本地环境变量

关于在本地开发中使用环境变量,next.js 已经有了很好的支持,查看 这里

在实际场景下,可以创建一个.env.local.examlpe文件。

开发者可以拷贝该文件并将其作为自己的.env.local文件。

.env.local 不应该被提交到repo中!

环境变量 in Jest

方法是有很多的,按需采用,这里记录两种。

在jest的setup文件中设置环境变量

文档在此。简单来说,在这里设置的环境变量会作用于每个测试用例文件。

适合用于设置默认环境变量,但无法满足需要测试不同的环境变量的场景。

在测试用例文件中设置环境变量

当然我们可以在测试用例文件中设置环境变量。

只是要记住,在每个测试用例前,一定要使用 restModules ,且动态引入涉及环境变量的模块。

describe('environmental variables', () => {
  const OLD_ENV = process.env;

  beforeEach(() => {
    jest.resetModules() // Most important - it clears the cache
    process.env = { ...OLD_ENV }; // Make a copy
  });

  afterAll(() => {
    process.env = OLD_ENV; // Restore old environment
  });

  test('will receive process.env variables', () => {
    // Set the variables
    process.env.NODE_ENV = 'dev';
    process.env.PROXY_PREFIX = '/new-prefix/';
    process.env.API_URL = 'https://new-api.com/';
    process.env.APP_PORT = '7080';
    process.env.USE_PROXY = 'false';

    const testedModule = require('../../config/env').default // dynamic import

    // ... actual testing
  });
});

其他

本地一切安好,线上发布缺少依赖,可能是?

规则:如果NODE_ENV被设置成production,yarn不会安装devDependencies中的依赖,具体可看这里

所以这种cmd是合理的:yarn install && yarn test && NODE_ENV=production yarn export

相对的,如果NODE_ENV被设置的太早,很可能会导致yarn test缺少依赖。

如何更新包/组件/服务

除了更新逻辑,一般还有哪些步骤?

  1. 更新测试用例,保证本地测试用例通过。
  2. 本地成功运行服务。
  3. 开一个draft PR.
    1. 将其部署到测试环境。
    2. 在测试环境成功运行。
  4. 更新版本。(视具体情形)
  5. 找人review。
  6. 有了approvals,可以merge。
  7. 其余的就是QA、部署流程等。

JWT

JWT(JSON web token)是一种常见的在客户端与服务端间传递信息的方式。

  1. 除非知道签名,用户是无法伪造数据的。
  2. 而header和payload本身是并没有被加密的。

所以在实际应用场景中,任何人都可以查看请求的数据,但不知道签名的普通用户没办法自己构造、篡改请求。

进一步了解JWT

Yarn2

Yarn2 = yarn berry(更加准确)。和 yarn 1.x 比起来算是大改。

如果使用PnP特性,yarn会生成.pnp.cjs以代替node_modules

.pnp.cjs只是一些maps,包括如何在文件系统中找到packages。

而packages本身,是被zipped压缩过的,所以文件的数量远远少于node_modules

尽管package被压缩过,我们仍然可以借助fs的能力读取文件。

更多yarn2,欢迎阅读:

线上监控服务异常排查

如果怀疑有异常的线上流量,如何排查:

  1. 调整时间区间,来观察流量是否是一瞬间涌入的。
  2. 比较服务端和客户端的流量,观察流量是否是直接打到服务端的。
  3. 比较流量峰值日志是否有共同点:Client IP, Country, Region, City…