前言
我们通常谈qps只谈消息数量, 而忽略了每一条消息的大小, 我们知道每一个队列也是一个erlang的进程, 向一个队列里推送消息时, 往往会在队列进程中产生性能瓶颈. 在向一个队列快速发送消息的时候, connection和channel都会处于flow状态, 而队列处于running状态, 在一台CPU主频为2.6hz, 4内核, 8g的内存虚拟机中测试, 发送非持久化大小为10b左右的消息, 发送的qps平均为18k. 如果开启了publisher confirm机制, 持久化消息及增大payload都会降低这个qps的数值.
引入
这里就有了相应的处理办法, 利用多个队列来分流, 画一个流程图:
代码
基础mq工具类:
@Configuration
@EnableApolloConfig
public class MqUtil {
private final List<Connection> connections = new ArrayList<>();
private final int maxConnection = 20;
@Value("${mq.calltopay.rabbit.host}")
private String host;
@Value("${mq.calltopay.rabbit.port}")
private int port;
@Value("${mq.calltopay.rabbit.username}")
private String username;
@Value("${mq.calltopay.rabbit.password}")
private String password;
@Autowired
@Qualifier("mqConnectionFactory")
public ConnectionFactory factory;
@Bean(name = "mqConnectionFactory")
public ConnectionFactory getRabbitMqConnection() {
return getFactory();
}
public ConnectionFactory getFactory() {
initFactory();
return factory;
}
private void initFactory() {
try {
if (factory == null) {
factory = new ConnectionFactory();
factory.setHost(host);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void sendMsg(String message, String queue) throws Exception {
Connection connection = getConnection();
Channel channel = connection.createChannel();
channel.basicPublish("", queue, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("utf-8"));
channel.close();
setConnection(connection);
}
public void sendMsg(String message, String exchange, String route) throws Exception {
Connection connection = getConnection();
Channel channel = connection.createChannel();
channel.basicPublish(exchange, route, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("utf-8"));
channel.close();
setConnection(connection);
}
public GetResponse basicGet(String queue, boolean autoAck) throws Exception {
GetResponse getResponse = null;
Connection connection = getConnection();
Channel channel = connection.createChannel();
getResponse = channel.basicGet(queue, autoAck);
channel.close();
setConnection(connection);
return getResponse;
}
public Connection getConnection() throws Exception {
return getAndSetConnection(true, null);
}
public void setConnection(Connection connection) throws Exception {
getAndSetConnection(false, connection);
}
private synchronized Connection getAndSetConnection(boolean isGet, Connection connection) throws Exception {
if (isGet) {
if (connections.isEmpty()) {
return factory.newConnection();
}
Connection newConnection = connections.get(0);
connections.remove(0);
if (newConnection.isOpen()) {
return newConnection;
} else {
return factory.newConnection();
}
} else {
if (connections.size() < maxConnection) {
connections.add(connection);
}
return null;
}
}
}
bean:
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private Long msgSeq;
private String msgBody;
private Long deliveryTag;
public Message() {
}
public Message(Long msgSeq, String msgBody, long deliveryTag) {
this.msgSeq = msgSeq;
this.msgBody = msgBody;
this.deliveryTag = deliveryTag;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Long getMsgSeq() {
return msgSeq;
}
public void setMsgSeq(Long msgSeq) {
this.msgSeq = msgSeq;
}
public String getMsgBody() {
return msgBody;
}
public void setMsgBody(String msgBody) {
this.msgBody