这里只按照我所知道的最大型架构来。

- - - - -
DNS负载均衡
负载分发
网关 + web/API 服务器
RPC服务器 服务注册
数据库 缓存 消息队列 搜索引擎 第三方接口
日志收集

技术

DNS负载均衡

DNS 负载均衡是把多个 A/CNAME 记录配置在 DNS 服务器上的一种均衡的办法。优点是不用另外配置服务器,缺点是规则生效慢,不宜多配。例如阿里巴巴华东节点就只配了4条记录。

负载分发

将请求分发到各台服务器的主力服务器。常见的负载分发服务器有 HAProxy, nginx, LVS。

通过负载分发出去的请求,为了保留用户 SESSION,一种方法是对用户id hash/取模,同一个用户的请求一直导向同一台服务器。但这种方法经常造成服务器使用不均,极不推荐。推荐的做法是把 SESSION 放在缓存服务器上,请求携带 token 一路往下传。

负载分发服务器虽然可以通过检测下游服务是否可用来动态更新分发规则,但本身有单点问题虽然可以用脚本和 keepalived 灾后抢救,但仍不能保证完全高可用。不知道有什么更好的替代。

lvs 是4层网络,nginx 是7层,所以 nginx 可以对应用层的数据做判断。

网关+web/API服务器

web/API服务器是放业务逻辑代码的地方,可以在上层放一层网关,也可以把网关代码和应用代码放一起。由于 API 是对外的,尤其是有第三方使用的情况下,除了要检查数据正确性外,还要注意 API 请求本身。网关应该拦截过于频繁的请求。如果有携带 token,且 token 随时间变化的话,一样的 token 可只放行第一个。

由于要经常改动,此层最合适的语言是 PHP 和 javascript(nodejs)。

服务注册

zookeeper 获得通知后要重新订阅才能再获得通知,所以不适合直接做注册中心。所以推荐 Apollo

数据库

在 MySQL 正式支持集群以前,还是只能搭建主从服务器,然后用一定的算法生成 id。常见的 id 生成算法是数据库id+时间哈希,是情况还可以增加 RPC id、版本号等信息。集群会失去顺序,这个时候可以考虑同一个用户的数据只写入同一台服务器。下面贴一个蚂蚁金服的 id 生成策略:

位置 1-8 9 10 11-13 14-16 10-9 8-1
示例 20180101 1 1 001 001 00 12345678
说明 8位日期 数据版本 系统版本 系统标识码 业务标识码 自定义扩展位 用户分片位 sequence空间,可支持每天每个分表1亿笔业务,循环使用

对于超大型服务,MySQL 的主从复制速度不能满足的情况下,可以考虑 OceanBase / PhxSQL,他们用 paxos 算法实现了分布式情况下数据库的快速同步。

消息队列

队列服务器有两种用处:

  1. 把耗时多的服务放在队列里,由另一个服务异步运行
  2. 有些数据对顺序要求很高,放在队列里,把并行转为串行

常见的队列服务有 kafka / RabbitMQ / RocketMQ,新版的 redis 也提供队列服务。

第三方接口

第三方接口由于在异地,经常会出现请求错误。这时如果时间允许的话可以睡眠若干秒后直接重试,否则放入消息队列。

日志收集

Elastic Stack(ELK) 是现在市面上最方便的日志收集和查询的工具。日志收集除了能做产品分析外,还能给新服务上线做蓝绿测试。即先在一台权重比较低的服务器上线新版,一段时间后如果日志没有报错,再在其他服务器上新。报警服务也可以架设在日志收集服务之上。

定时任务

xxl-job

后台

服务器性能指标查看

grafana

接口文档管理

yapi