前幾天部署環境的時候,啟動幾個dubbo服務的時候,報了qos端口22222被占用。
貌似以前沒遇到過這個錯呢?
Qos是啥?
qos是dubbo的在線運維命令。
dubbo2.5.8新版本重構了telnet模塊,提供了新的telnet命令支持,新版本的telnet端口與dubbo協議的端口是不同的端口,默認為22222。可以對dubbo服務上/下線。
QoS參數配置
可以通過如下方式進行配置
- JVM系統屬性
- dubbo.properties(在項目的src/main/resources目錄下添加dubbo.properties文件)
- XML方式
- Spring-boot自動裝配方式
其中,上述方式的優先順序為 JVM系統屬性 > dubbo.properties > XML/Spring-boot自動裝配方式。
dubbo 2.5.9 版本
如果要修改qos.port,可以通過如下方式達到目的:【類QosProtocolWrapper】
方法一:在spring-dubbo.xml中配置如下
<dubbo:application name="${project.name}">
<!-- 關閉qos -->
<dubbo:parameter key="qos.enable" value="false"/>
<dubbo:parameter key="qos.port" value="22223"/>
</dubbo:application>
方法二:配置啟動參數
-Ddubbo.application.qos.port=33333 -Ddubbo.application.qos.enable=false
dubbo 2.6.0版本
取qos.port 是 【-Ddubbo.qos.port=33333】, 且無法通過配置關閉。
在com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper中有啟動qos
public class ProtocolListenerWrapper implements Protocol {
static {
try {
Class serverClass = Protocol.class.getClassLoader().loadClass("com.alibaba.dubbo.qos.server.Server");
Method serverGetInstanceMethod = serverClass.getMethod("getInstance");
Object serverInstance = serverGetInstanceMethod.invoke(null);
Method startMethod = serverClass.getMethod("start");
// 這里沒有判斷配置,直接反射調用start了
startMethod.invoke(serverInstance);
}catch (Throwable throwable){
}
}
// ...
}
不過可以在qos-server啟動之后,再關掉它。
// 關閉dubbo qos service
com.alibaba.dubbo.qos.server.Server.getInstance().stop();
在com.alibaba.dubbo.qos.server.Server中,有如下代碼段:
public class Server {
private static final Logger logger = LoggerFactory.getLogger(Server.class);
private static final Server INSTANCE = new Server();
public static final Server getInstance() {
return INSTANCE;
}
// 這里直接取端口號
private int port = Integer.parseInt(ConfigUtils.getProperty(Constants.QOS_PORT, Constants.DEFAULT_PORT + ""));
// ...略部分代碼...
/**
* start server, bind port
*/
public void start() throws Throwable {
if (!hasStarted.compareAndSet(false, true)) {
return;
}
boss = new NioEventLoopGroup(0, new DefaultThreadFactory("qos-boss", true));
worker = new NioEventLoopGroup(0, new DefaultThreadFactory("qos-worker", true));
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(boss, worker);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
serverBootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new QosProcessHandler(welcome));
}
});
try {
serverBootstrap.bind(port).sync();
logger.info("qos-server bind localhost:" + port);
} catch (Throwable throwable) {
// 這里會打印端口沖突錯誤
logger.error("qos-server can not bind localhost:" + port, throwable);
throw throwable;
}
}
}
為什么以前沒遇到22222端口占用問題
之前依賴的是dubbo-2.5.9。在這個版本的QosProtocolWrapper中,可以看到:
private void startQosServer(URL url) {
if (!hasStarted.compareAndSet(false, true)) {
return;
}
try {
boolean qosEnable = Boolean.parseBoolean(url.getParameter(QOS_ENABLE,"true"));
if (!qosEnable) {
return;
}
int port = Integer.parseInt(url.getParameter(QOS_PORT,"22222"));
boolean acceptForeignIp = Boolean.parseBoolean(url.getParameter(ACCEPT_FOREIGN_IP,"true"));
// 如果沒有netty4,下面這行代碼就會報錯
Server server = com.alibaba.dubbo.qos.server.Server.getInstance();
server.setPort(port);
server.setAcceptForeignIp(acceptForeignIp);
server.start();
} catch (Throwable throwable) {
// 這里錯誤直接吃掉了,沒往外部拋出來
//throw new RpcException("fail to start qos server", throwable);
}
}
qos-server 需要netty4版本的支持,默認情況下dubbo不會引用netty4的依賴包。
而最近新加的功能確實間接引入了netty4。
關閉qos
對於2.5.9的版本,可以通過如下方式關閉qos
<dubbo:parameter key="qos.enable" value="false"/>
或者
-Ddubbo.application.qos.enable=false
對於2.6.0的版本,沒辦法通過配置關閉,只能是Server有stop方法了