生产环境逐渐容器化的过程中遇到了一些坑,特此记录一下:
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
继续更新。。。
发表回复