背景:
我们当前的微服务架构采用的是 SpringCloud 全家桶 + dubbo + druid + apllo 等技术集成的。
1、多服务实例相同端口冲突问题
目前线上服务器内容动辄 128 ~ 256GB,我们一个服务最大内存设置不超过 32GB,那么为了有效利用服务器资源,我们都会在一台服务器上启动多个服务实例。那此时如果配置文件中配置写死了一个固定的 port 就会发生 dubbo 服务端口冲突。需要将 dubbo 的端口设置为 随机端口,具体如下所示:
dubbo: scan: base-packages: com.search.bs protocol: name: dubbo port: -1 #20881,将原来写死的 20881 改为随机,默认端口为 20880 serialization: hessian2
2、mysql 加载超时问题
链接 mysql 我们使用的是 druid 的数据库连接池,我们当前业务涉及到正排加载,而有的业务线数据量较大,且得到对应需要的正排内容加载查询的时候会很慢,导致前一个加载完成后紧接着加载第二个内容的时候,此时 mysql 链接不可用,或者当前的链接耗时太长也导致不可用状态:
druid: #初始化大小,最小,最大 initial-size: 10 max-active: 300 min-idle: 5 #配置获取连接等待超时的时间 max-wait: 300000 #检测连接是否有效的sql validation-query: "select '1'" validation-query-timeout: 2000 #从连接池里面获取连接时都会测试连接的有效性。这个是获取一个稳定连接最简单有效的手段,前提是如果你的性能要求不是非常高 test-on-borrow: true test-on-return: false #对已经取到的connection进行连接有效性的检测 test-while-idle: true #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 time-between-eviction-runs-millis: 60000 #配置一个连接在池中最小生存的时间,单位是毫秒 min-evictable-idle-time-millis: 300000 remove-abandoned: true
其中最重要的是将:test-on-borrow 设置为 true,因为我们只是在初始化的时候加载正排,所以无所谓性能要求。
3、服务注册回调异常
有一同事的 mac 升级为最新版本,导致最近的整个微服务架构启动不起来了,一直卡在某个错误上,先来看一段警告信息:
[2020-04-14 18:19:49,391][dev][WARN][main][] o.a.d.c.AbstractConfig - [DUBBO] Connection refused (Connection refused), dubbo version: 2.7.3, current host: 172.18.18.95 java.net.ConnectException: Connection refused (Connection refused) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at org.apache.dubbo.config.ServiceConfig.findConfigedHosts(ServiceConfig.java:698) at org.apache.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol(ServiceConfig.java:560) at org.apache.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:457) at org.apache.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:415) at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:378) at org.apache.dubbo.config.spring.ServiceBean.export(ServiceBean.java:336) at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:114) at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:60) at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391) at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:140) at com.mfw.search.bs.SearchBsBootstrap.main(SearchBsBootstrap.java:23)
此时该服务在 nacos 注册中心是已经注册成功的,但是对应的服务 ip 为:127.0.0.1,而从日志中报出来的信息当前 ip 为:172.18.18.95,从异常信息中直观的可以看到是 socke 拒绝连接,也就是说:
在本地启动dubbo时,服务注册在 nacos 上,但是注册IP却不是本地的iP。产生问题,导致consumer 找不到provider ,访问不了服务。
- 例如 本地IP为 172.18.18.95 ,但是 nacos 上的注册 ip 可能是 127.0.0.1
从网上查了好多说修改 /etc/hosts,但是并没有解决这个问题,而且明明之前是好使的,周边没有升级的小伙伴使用他当前 git 分支代码启动也是一点问题都没有,这就奇怪了,难道真的是mac 电脑升级导致的吗?
但是不管是不是升级导致的,这个问题还是需要解决的。首先我们需要明确问题的原因:
1. 客户端向 nacos 发起请求注册成功
2. 通过服务端回调的时候通过 127.0.0.1 无法回调回去(因为你的真实 ip 为 172.18.18.95),导致 socket 拒绝连接
debug dubbo 代码发现,在 NetUtils
中的 getLocalAddress0
这个方法,获取到的 ip 为 localhost/127.0.0.1,而且设置完对应的 hosts 也不受影响,所以我们的想法也很简单,需要改动 dubbo 的相关配置来约束相应的 ip 地址:(只有本地环境可能会发生这种问题,线上不会存在,所以在一定程度上可以这么做)
dubbo: scan: base-packages: com.mfw.search.bs protocol: name: dubbo port: -1 serialization: hessian2 host: 172.18.18.95 #指定好当前本机 ip 地址
相应的 spring相关配置也需要指定当前注册的服务的 ip 地址为某个段内的,可以将 127.0.0.1 屏蔽掉:
spring: autoconfigure: exclude: - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration application: name: search-bs-lyx #应用名。很重要!是注册中心的主键,gateway路由也需要靠它 main: allow-bean-definition-overriding: true cloud: nacos: #采用nacos注册中心 discovery: enabled: true register-enabled: true namespace: 6947fa15-b976-45f4-b121-4c05e802e8xx endpoint: 'nacosendpoint.mtech.svc.ab:8098' inetutils: preferred-networks: 172 #限定选择前缀为 172 的 ip
这样就能解决以上问题,一般情况下 dubbo 是不需要指定 ip 的,但是如果不指定解决不了再指定一定会解决掉问题,这个主要就是绑定 nacos 注册的时候使用的 ip 地址
而 spring 规范的前缀 ip,这个主要是指定 nacos 注册的服务分配的 ip,具体如下图的一个服务启动在 nacos 中的服务注册情况,可以对照 dubbo 和 spring 配置的 ip 来区分对待: