共计 2263 个字符,预计需要花费 6 分钟才能阅读完成。
生产环境逐渐容器化的过程中遇到了一些坑,特此记录一下:
Docker 默认网络模式带来的 ip 问题
这是初步应用 docker 时遇见最多的问题,在多个组件或中间件上体现,然而实质问题还是因为 docker 默认的网络模式是 bridge,会为以后容器调配格局为 172.17.0.X 的 IP 地址。这个 IP 的特点是在一台宿主机上递增,然而如果同一个服务在多个宿主机上都应用容器部署,很可能会呈现 IP 地址雷同的状况,对于以 IP 来辨认终端的一些组件和中间件来说,会呈现问题。
针对此问题,大部分状况下能够设置网络模式为 host 来解决:
--net=host
然而如此一来,同一宿主机上就不能搁置多个同服务的容器,因为端口雷同(host 模式下不能应用 -p 设置端口),除非批改源码扭转端口,然而这样代价太大。另外对于个别问题还是解决不了。另外也是在初步波及 docker,应用默认模式更保险一些。
RocketMQ 消费者客户端因为 IP 雷同导致反复生产问题
-
问题表象
A,B 两台宿主机都有一个基于 docker 的生产客户端,IP 地址都为 172.17.0.1,在理论生产中呈现了反复生产问题。如下:
当然,在网上搜寻时也发现有的敌人遇到的是不生产的状态,具体为何没有深究。
-
问题剖析
RocketMQ 用一个叫 ClientID 的概念,来惟一标记一个客户端实例,一个客户端实例对于 Broker 而言会开拓一个 Netty 的客户端实例。而 ClientID 是由 ClientIP+InstanceName 形成,如下源码:
public String buildMQClientId() {StringBuilder sb = new StringBuilder(); sb.append(this.getClientIP()); sb.append("@"); sb.append(this.getInstanceName()); if (!UtilAll.isBlank(this.unitName)) {sb.append("@"); sb.append(this.unitName); } return sb.toString();}
而 instanceName 个别咱们时不会设置的,默认的话会取过程号
public void changeInstanceNameToPID() {if (this.instanceName.equals("DEFAULT")) {this.instanceName = String.valueOf(UtilAll.getPid());
}
}
故如果一个过程中多个实例(无论 Producer 还是 Consumer)ClientIP 和 InstanceName 都一样, 他们将专用一个外部实例(同一套网络连接,线程资源等)
此外,此 ClientID 在对于 Consumer 负载平衡的时候起到惟一标识的作用,一旦多个实例(无论不同过程、不通机器、还是同一过程)的多个 Consumer 实例有一样的 ClientID,负载平衡的时候必然 RocketMQ 任然会把两个实例当作一个 client(因为同样一个 clientID)。
故为了防止不必要的问题,ClientIP + instance Name 的组合倡议惟一,这里我采纳自定义 instanceName 的形式,在 springboot 下如下:
@Configuration
@AutoConfigureBefore(RocketMQAutoConfiguration.class)
public class RocketMQCustomFrontConfig {
static {System.setProperty("rocketmq.client.name", String.valueOf(System.currentTimeMillis()));
}
}
到此问题解决。
应用 nacos 作为服务发现导致服务间调用不通问题
同样的起因,导致 nacos 服务节点 ip 截然不同,然而因为是虚构 ip,所以会影响服务间的调用,解决办法也很简略,我是在 docker 启动脚本中增加如下配置:
--spring.cloud.nacos.discovery.ip=$nacos_discovery_id
当然在 springboot 环境下配置文件中也能够设置,不过不同环境下就须要批改源码配置文件,所以不做思考。若应用的是其余服务发现组件,都有各自配置反对。
阿里 Sentinel 下节点状态不对且链路不通问题
Sentinel 下的问题要从 2 个方面思考:ip 和端口。基于 docker 环境,默认状况下:
- 若 ip 为虚构 ip 则链路不通。
- sentinel 的客户端裸露数据的端口默认为 8719,若端口被占用则自增;然而在 docker 环境下,每一个客户端的端口都为 8719,这时候应用 docker - p 映射端口就难以确定或者每个节点都须要不同的脚本,这个切实太麻烦了。
- 若 ip 和端口都统一,则会呈现多个节点在 dashboard 被笼罩的问题
解决办法如下:
## 对于 ip 能够应用一下参数设置
--spring.cloud.sentinel.transport.client-ip=$nacos_discovery_id
## 至于端口,我才用的办法就是设计好端口规定,而后在 springboot 中手动设置 sentinel 的数据端口,最初在 docker 脚本中通过 - p 配置固定端口,这样至多每一个利用只须要一个脚本,另外对于一个利用的不同节点最好放在不同宿主机上
spring:
cloud:
sentinel:
transport:
port: 17019
继续更新。。。