背景及现象
为了保证应用的安全,我们使用了自定义的 SecurityManager
, 在应用需要读取文件的时候进行黑白名单判定,例如读取 /etc/hosts
文件万万不行的, Manager
可以做更多的事,这里不在进行介绍。
一个业务准备引入 Spring Cloud Gateway 做为业务网关,打算缓慢向SpringCloud迁移,在建立GW的过程中,出现了一个读取 /etc/hosts
文件的问题。
查询问题
由于我从未遇到过这个错误,我询问了下边的堆栈是什么情况。
(DefaultHostsFileEntriesResolver.java:37)
at io.netty.resolver.HostsFileEntriesResolver.<clinit>(HostsFileEntriesResolver.java:28)
... 87 common frames omitted
得到的回复是由SpringCloud Gateway加载路由规则时触发的。内容如下所示,该内容从Nacos中加载。
看到堆栈后,我查询了Netty的代码,这个类是用于处理DNS问题的,引用的类如下所示
在一通源代码的梳理之后,我发现是由于在加载lb的时候需要去进行解析,由于没有设置DNS,于是使用了Netty默认的解析器,于是问题从 为什么会出现这个问题
变成了 如何把Netty的DNS解析切换成默认的DNS解析
, 在 reactor-netty
中issue中进行搜索,发现也有同志需要这个特性,查看文档如下
接下来,在GW中自定义了一个 HttpClient
再次,重启发现问题解决了,它不会去读取 /etc/hosts
文件了。如果我们没有 SecurityManager
, 其实是不会有问题的,但是为了安全🔐,我们设置了这个。
小结
由于默认的 HttpClient
没有指定DNS的解析器,所以使用了Netty的DNS解析,解析需要去读取文件。由于设置了 Manager
,所以读取失败了,从而引发了这个问题。
遗留的问题
Git克隆 SpringCloud Gateway
的源代码之后,可以在 GatewayAutoConfiguration
中发现 HttpClient
的自动装配。
自动装配简化了我们的配置,但是由于它的黑盒性质,也带来了一些加载的问题。
如何建设网关的高可用
这一块,我也没有什么经验,主要提出2个问题
- 服务上下线的问题
- 手动上下线【适用于服务少】,稳定性高
- 自动上下线【服务多】,稳定性相对较低,存在一个优雅的上下线问题
- 优雅上线,启动注册上线的时候可能Spring还没有初始化完毕。如果这个时候上线接受流量,就会导致响应慢,甚至由于错误而引发404。
- 优雅下线,停止服务下线的时候使用shutdown.sh或者是kill 15,如果线程长时间执行任务不退出,(我们脚本默认是10s) 会启用kill -9 强制杀掉。由于和注册中心的延时导致带来的502问题
- 实例多的时候的心跳问题
- 如果实例达到一个高的数量级,那么心跳的流量是否会对注册中心造成冲击
额外的发现
在 kubernetes
流行之后,我们就可以利用它本身的服务发现来做这件事,令人惊喜的是SpringCloud团队已经在做这样的事情了==> Spring-cloud-kubernetes
如此一来,就可以解决服务上下线的问题,把问题直接交给K8S来解决,我们只要把控好容器的存活检测和就绪检测即可,但是这个就需要要求团队对于K8S的掌握程度较好,最起码命令行都用的溜一点。