一、业务背景分析
前一段时间,需要开发一套业务系统,此系统需要对外统一提供api服务,但这些服务在内部是由多个业务子系统分别提供。
经过分析,此业务系统需要具有以下这么几个特性

1、不同的api服务由不同的子系统负责
2、每一个服务之间是相互独立的
3、每一个服务都需要支持横向扩展和负载均衡
4、每一个服务都需要高可用

这么一分析,我们发现这里需要一个api网关,这个api网关需要具有以下几个特点:
1、api服务器自注册,需要满足以下两个特点(当然也可以由运维在api网关管理平台上进行管理,此部分不影响本文的技术探讨,这里不进行详细的描述)
   1)新增一个服务时,api服务器可以将相应的服务自注册到api网关上
   2)某服务新增一个服务器或删除一个服务器时,api服务器可以在进行自注销或自注册
2、api网关需要支持对同一个服务子系统的多个服务器进行负载均衡
3、api网关需要支持对同一个服务子系统的多个服务器中的故障服务器进行检测和切换,也就是高可用
4、api网关系统本身需要支持横向扩展

二、方案的选择
对于任何团队来讲,方案不一定是自己开发的就是最好的(牛A和牛C之间的技术团队除外),需要综合考虑各种因素,这个API网关也不例外,中间经历了一点曲折,过程如下:

1、系统是部署在云上面的(具体的云这里就不透露了),原本想着看这个云服务端是否有提供此功能服务,不过遗憾的是此云未提供此服务(好像亚马逊云有提供,没有用过不知道怎么样)
2、使用开源的方案,在开源方案上找到了一个叫kong的方案,此方案是基于nginx的反向代理开发的一套方案,经过调研,此套方案不支持负载均衡和高可用方案(当然不是很深入的调研),此方案本身是基于nginx的lua扩展模块进行开发的,对于api网关的配置是使用cassandra数据库进行存储,对于团队的技术背景来说,这个不是那么合适。(ps:团队本身还不是很强大,业务工作量比较多,整个团队对lua和cassandra没什么积累,在这个场合下除非此方案能直接用,并且有较多的资料,否则只能舍弃掉)

3、自主开发一套,经过对各服务子系统的接口分析,发现直接使用nginx的反向代理和负载均衡来实现也不是那么复杂,所以这个方案这么诞生了

三、使用nginx作为api网关的调研
对于nginx的反向代理和负载均衡的资料网上已经有很多,这里就不废话了,直接看调研过程
这里假设nginx的配置文件目录为/etc/nginx/
1、配置的考虑
  考虑到nginx的配置文件大小有要求,所以在这里不把配置直接写入到nginx.conf,而是在nginx.conf里面去include其他目录,比如
  在/etc/nginx/目录下新建api_servers.d目录和api_rules.d目录,分别用来存放api服务器的相关配置和api服务代理规则的相关配置,在http配置项中增加一行配置include /etc/nginx/api_servers.d/*.conf;
  在提供网关服务的server中增加一行include /etc/nginx/api_rules.d/*.conf;

2、配置负载均衡和反向代理
   在/etc/nginx/api_servers.d/目录下新增一个文件api_test_servers.conf,内容如下

   upstream api_testa_server {
       server 192.168.1.101:80 weight=1 max_fails=3 fail_timeout=20;
       server 192.168.1.102:80 weight=1 max_fails=3 fail_timeout=20;
       server 192.168.1.103:80 weight=2 max_fails=3 fail_timeout=20;
   }

   upstream api_testb_server {
       server 192.168.1.104:80 weight=1 max_fails=3 fail_timeout=20;
       server 192.168.1.105:80 weight=1 max_fails=3 fail_timeout=20;
   }

  在/etc/nginx/api_rules.d/目录下新增一个文件api_test_rule.conf(这里以简单的url匹配来举例)

   location ~(^\/ws\/apitesta)(.*) {
       proxy_set_header Host $host:$server_port;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_buffering off;#缓存在其他文章中会讨论,在这里暂只讨论基本的功能,所以直接使用off
       proxy_pass http://api_testa_server;
   }
   
   location ~(^\/ws\/apitestb)(.*) {
       proxy_set_header Host $host:$server_port;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_buffering off;
       proxy_pass http://api_testb_server;
   }

   nginx服务reload使配置生效

3、测试过程
 nginx服务器的地址是192.168.1.100,服务的端口为80端口,测试过程如下
1)、 执行wget http://192.168.1.100/ws/apitesta/phpinfo和wget http://192.168.1.100/ws/apitestb/phpinfo
分别重复执行此命令20次,查看192.168.1.101-105这5台web服务器的web访问日志,发现101-103的/ws/apitesta/phpinfo访问量分别为5、5、10,104和105的web访问日志里面对/ws/apitestb/phpinfo的访问量都是10次
2)、 关闭192.168.1.102和192.168.1.104,重复上述测试过程,发现两个url均可正常访问

四、网关的搭建
从上述的调研结果来看,使用nginx的反向代理和负载均衡可实现对api服务器的负载均衡及高可用,那么我们需要解决的就是自注册的问题和网关本身的扩展性。
对于自注册和自注销这个问题,对于我们的业务系统来说,业务的上线与下线本身不是一个特别频繁的事情,所以直接在api网关上搭建一个简单的web服务即可,我们称之为api网关系统,api网关系统基本功能如下:
1、注册或注销时需要重新生成nginx的反向代理和负载均衡配置文件(也就是上述的api_rules.d和api_servers.d目录下的文件),并且网关服务器需要对nginx执行reload操作
2、需要对api服务的相关信息做持久化存储
除了上述两个基本功能还需要网关本身支持横向扩展,这个仔细分析一下无非就是需要以下两个问题
1、在任一个网关服务器上注册或注销一个api服务或一个api服务的一个服务器时都需要通知到所有的网关服务器,所有的网关服务器都需要重新生成配置并且reload各自的nginx服务,显然的我们想到了消息队列里面的topic消息(消息队列的高可用等特性在这里不进行特别延伸),所有的api网关服务器共用同一个消息队列即可满足此要求
2、所有的网关服务器需要共同同一个网关配置信息,这个无非是共用一个数据库(数据库的高可用等特性在这里不进行特别延伸)

api服务器自注册至生效主要流程如下:

所有的网关服务器共用一个消息队列,共用同一个存储数据库,各网关服务器上的网关信号处理进程向消息队列订阅相关的消息,当api服务器向网关服务器集群中的某一台服务器进行注册时,所有的网关服务器都会收到reload消息,会从同一个数据库中读取同一个配置,然后重新生成nginx反向代理和负载均衡的相关配置文件,接着reload各自的nginx服务,当然这里面的网关信号处理进程启动时也会重新生成相关的配置。

至此一个基于nginx的API网关完成了,
 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐