NODEJS 在广发证券的应用

大纲

  • 背景
  • 定位&选型
  • Microservice&Devops
  • Q&A

背景

我们是谁

  • 广发证券
  • 信息技术部
  • 互联网金融

定位&选型

业务1

业务2

业务3

证券交易所

柜台

中间件

业务-后台

用户-浏览器

证券交易所

柜台

中间件

行情

基金

为什么选择 NodeJS

  • 团队成员大多有前端基础
  • 业务高并发
  • 内存占用小
  • 支持 async/await 解决异步问题

选择什么框架

express koa
Github Stars 34k+ 17k+
Contributions 217 136
Middlewares 3128 1038
优点 最流行、最出名、生态成熟 依赖模块少,优雅的异步处理和错误处理
缺点 异步处理和错误处理 生态相比不够成熟

性能

为什么选择Koa2

  • 优雅的异步处理
  • 优雅的错误处理
  • 可以通过简单的包装直接使用 express 的中间件
  • 中间件开发简单
  • 性能也不赖


const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {
  console.log(1);
  await next();
  console.log(2);
});

app.use(async (ctx, next) => {
  console.log(3);
  await next();
  console.log(4);
});

app.listen(3000);
const logger = require('../lib/logger').getLogger();

module.exports = async function(ctx, next) {
  let start = +new Date;
  try {
    await next();
  } catch (error) {
    error = error || new Error('unknow error');
    if (error.expected) return;
    logger.ctx(ctx).fatal(`error: ${error.message}, stack: ${error.stack}`);
    ctx.set('cache-control', 'no-cache, max-age=0');
    ctx.status = error.status || 500;
    ctx.type = 'json';
    ctx.body = {
      code: error.code,
      error: error.error,
      message: error.message,
    };
  } finally {
    let time_cost = +new Date - start;
    // todo report
  }
};

process.on('unhandledRejection', (err) => {
  logger.fatal(`unhandledRejection: ${err.message}, stack: ${err.stack}`);
});

process.on('uncaughtException', (err) => {
  logger.fatal(`uncaughtException: ${err.message}, stack: ${err.stack}`);
});

异常处理示例

使用 express 中间件

日志应该怎么记

  • 设置好日志级别
  • 利用好 debug 模块
  • 每个请求一个reqid
  • 每个用户一个uid
  • 每条日志都要记录 reqid 和 uid
  • 密码等敏感信息不能记录到日志中
  • 不换行





require('request-debug')(rp, function(type, data, r) {
  if(type === 'request') {
    let {debugId, uri, method, body} = data;
    let userId = data.headers.userId;
    let more = body ? '' : ('-' + body) + userId ? '' : ('userId:' + userId);
    debug(`${debugId}-${method}-${uri}-${more}`.replace(/\s+/g, ' '));
  }

  if(type === 'response') {
    let {debugId, statusCode, body} = data;
    debug(`${debugId}-resp-${statusCode}-${JSON.stringify(body)}`.replace(/\s+/g, ' '));
  }
});

代码质量检查&测试用例

  • eslint
  • supertest & ava

  • 贵在坚持

Microservice&Devops

服务应该怎么部署

  • pm2
  • docker
pm2 docker
优点 简单、方便、适用于小项目 环境稳定、版本控制好、方便跨集群部署、结合 CI 可自动化部署
缺点 不方便回滚、不方便跨集群部署 需要与之配套的发布工具及环境
建议 个人项目、小项目使用 公司有条件支持时使用

优缺点

Dockerfile 怎么写

# base image
FROM node:slim

# image name
ENV IMAGE_NAME example

# work dir
RUN mkdir -p /www/$IMAGE_NAME
ADD .        /www/$IMAGE_NAME
WORKDIR      /www/$IMAGE_NAME

# install node_modules
RUN npm install --production --verbose

# env
ENV PORT=8000

# start
CMD ["./start.sh"]

几条命令

  • docker build -t example:latest .
  • docker push example:latest .
  • docker run -d -p 8000:8000 --name=example example:latest
  • docker tag example:latest example:1.0.0

Gitlab CI

Gateway-Nginx

用户-浏览器

后台-Gateway

后台服务

docker

前端资源

html/css

k8s

k8s

开发和运维

整体架构

监控-内存占用

监控-CPU使用率

监控-QPS

监控-延时

Q&A

Node

By loskael

Node

  • 1,080