一. 为什么需要网关
在微服务架构设计中,通常会有若干个服务提供者。例如一个券商系统,会有用户系统、开户系统、资讯系统、交易系统等多个服务,而每个服务数量会最着集群部署会变得越来越庞大和复杂。客户端在调用后端系统API时,可能会从多个微服务接口中聚合数据,每个服务又是集群化部署,增加了客户端的复杂性。存在跨域请求的情况,还需要考虑接口鉴权、防火墙/浏览器不友好的协议等影响。网关的作用这时候就显得比较重要。网关对外暴露聚合API,屏蔽内部微服务的变动,保证整个系统的稳定性。它还可以做统一鉴权,监控监测、协议转换等功能。
二. 网关框架都有哪些
目前比较常见的几种开源的网关框架有以下几种:Nginx、Treafik、Kong、Tyk、Ambassador、Zuul 、spring cloud gateway等。至于它们之间的区别,小伙伴自行搜索。如何进行网关选型,也会因业务复杂度、团队使用成本而异。
三. 博客提纲
本博客介绍如何使用Zuul构建一个简单的网关、介绍路由配置方式。要点内容如下:
客户端通过zuul网关调用微服务接口的的关系图:
1.zuul的相关概念
Zuul是Netflix开源的微服务网关[1],他可以和Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
1) 身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求;
2) 审查与监控;
3) 动态路由:动态将请求路由到不同后端集群;
4) 压力测试:逐渐增加指向集群的流量,以了解性能;
5) 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求;
6) 静态响应处理:边缘位置进行响应,避免转发到内部集群;
7) 多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB(ElasticLoad Balancing)使用多样化。
2.zuul的依赖和配置
1)依赖库
def alibabaCloudVersion = '2.2.3.RELEASE' def spring_boot_version = "2.3.2.RELEASE"
ext { set('springCloudVersion', "Hoxton.SR8") }
在dependencies 中添加: // nacos implementation "com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:${alibabaCloudVersion}" // zuul implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
2)application配置
@SpringBootApplication @EnableDiscoveryClient // 允许注册nacos @EnableZuulProxy // 开启 zuul代理 public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); } }
3)bootstrap.yml配置文件
server: port: 8852 spring: application: name: zuul_gateway main: allow-bean-definition-overriding: true cloud: nacos: discovery: # 注册到nacos server-addr: localhost:8848
启动nacos(如何安装和启动nacos,请看我的博客《如何在Mac下安装nacos》),运行 ZuulApplication,在浏览器输入:http://localhost:8848/nacos/#/login, 输入账号和密码:nacos、nacos,我们看到 zuul已经被注册到nacos了。
3.实现服务提供者
在本博客中,博主定义了crm, user两个微服务提供者,分别对外暴露两个接口。
1) cms提供者的主要实现
@Service public class CmsServcie { public String getContent() { return "Contentn from cms"; } public String saveContent() { return "Save content to cms"; } }
@RestController public class CmsController { public static final String CMS_GET_CONTENT = "cms/getContent"; public static final String CMS_SAVE_CONTENT = "cms/saveContent"; @Autowired private CmsServcie servcie; @GetMapping(path = CMS_GET_CONTENT) @LoadBalanced public String getContent() { return servcie.getContent(); } @GetMapping(path = CMS_SAVE_CONTENT) @LoadBalanced public String saveContent() { return servcie.saveContent(); } }
@SpringBootApplication @EnableDiscoveryClient public class CmsApplication { public static void main(String[] args) { SpringApplication.run(CmsApplication.class, args); } }
bootstrap.yml配置:
server: port: 8851 spring: application: name: cms cloud: nacos: discovery: server-addr: localhost:8848 profiles: active: dev ribbon: #http请求连接建立超时时间(ms) ConnectTimeout: 10000 #http请求处理超时时间(ms) ReadTimeout: 15000 #默认重试次数 MaxAutoRetries: 1 #默认尝试的实例数 MaxAutoRetriesNextServer: 4
gradle依赖同zuul。
运行CmsApplication,cms被注册到 nacos。
2) user提供者的主要实现
@Service public class UserService { public String login() { return "Login successful"; } public String logout() { return "Logout successful"; } }
@RestController public class UserController { public static final String USER_LOGIN = "user/login"; public static final String USER_LOGOUT = "user/logout"; @Autowired private UserService service; @GetMapping(path = USER_LOGIN) @LoadBalanced public String login() { return service.login(); } @GetMapping(path = USER_LOGOUT) @LoadBalanced public String getUserLogout() { return service.logout(); } }
@SpringBootApplication @EnableDiscoveryClient public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); } }
bootstrap.yml配置:
server: port: 8850 spring: application: name: user cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml prefix: user discovery: server-addr: localhost:8848 profiles: active: dev ribbon: #http请求连接建立超时时间(ms) ConnectTimeout: 10000 #http请求处理超时时间(ms) ReadTimeout: 15000 #默认重试次数 MaxAutoRetries: 1 #默认尝试的实例数 MaxAutoRetriesNextServer: 4
gradle依赖同zuul。
运行UserApplication,user被注册到 nacos。
4.zuul调用cms、user的接口实现
1)静态路由设置
在zuul的bootstrap.yml中添加以下路由配置:
zuul: routes: # cms路由 cms: # 微服务的serverID serviceId: cms path: /cms/** stripPrefix: false # 设置为false,表示不增加前缀 # user路由 user: # 微服务的serverID serviceId: user path: /user/** stripPrefix: false # 设置为false,表示不增加前缀
路由说明:
服务提供者的接口被映射成 :http://localhost:8852/serverID/路径,http://localhost:8852是zuul的host和端口。
例如调用user 的login接口,原API是http://localhost:8850/user/logout,被zuul路由映射成API:http://localhost:8852/user/logout。
2)重新运行ZuulApplication。调用在浏览器输入:http://localhost:8852/user/logout,我们看到zuul已经成功调用user的logout接口。同理,user的login接口、cms的其他两个接口也可以这么访问。
四. 总结
通过就是在nacos注册中心中简单实现zuul网关的全部内容。博客的demo代码可以github上下载。感谢您的阅读。