All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.javaclub.mq.client.producer.Producer Maven / Gradle / Ivy
package com.github.javaclub.mq.client.producer;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import com.github.javaclub.monitor.Monitors;
import com.github.javaclub.mq.client.config.AuthIndentity;
import com.github.javaclub.mq.client.config.AuthIndentityImpl;
import com.github.javaclub.mq.client.config.BrokerListListener;
import com.github.javaclub.mq.client.config.ConfigManager;
import com.github.javaclub.mq.client.config.ConfigManagerImpl;
import com.github.javaclub.mq.client.producer.codec.Decoder;
import com.github.javaclub.mq.client.producer.codec.Encoder;
import com.github.javaclub.mq.client.producer.codec.Handler;
import com.github.javaclub.mq.client.producer.manager.HalfMsgManager;
import com.github.javaclub.mq.client.producer.manager.HalfMsgManagerImpl;
import com.github.javaclub.mq.client.producer.manager.LocalFileManager;
import com.github.javaclub.mq.client.producer.manager.LocalFileManagerImpl;
import com.github.javaclub.mq.client.producer.message.PubMessage;
import com.github.javaclub.mq.client.producer.processer.AckPubMsgProcesser;
import com.github.javaclub.mq.client.producer.processer.CheckMsgProcesser;
import com.github.javaclub.mq.client.producer.transaction.LocalTransactionChecker;
import com.github.javaclub.mq.client.producer.transaction.LocalTranscationExector;
import com.github.javaclub.mq.client.producer.transaction.TransactionStatus;
import com.github.javaclub.mq.client.remote.ChannelManager;
import com.github.javaclub.mq.client.remote.ChannelManagerImpl;
import com.github.javaclub.mq.client.remote.ChannelPool;
import com.github.javaclub.mq.client.remote.ChannelPoolFactory;
import com.github.javaclub.mq.client.remote.ResponseManager;
import com.github.javaclub.mq.client.remote.ResponseManagerImpl;
import com.github.javaclub.mq.client.remote.SendPacket;
import com.github.javaclub.mq.client.remote.SendPacketImpl;
import com.github.javaclub.mq.client.remote.ChannelManagerImpl.ChannelType;
import com.github.javaclub.mq.common.domain.MsgHeader;
import com.github.javaclub.mq.common.netty.ChannelPipelineFactory;
import com.github.javaclub.mq.common.netty.protocol.PubMsgProtocol;
import com.github.javaclub.mq.common.util.UUID;
import com.github.javaclub.mq.common.util.Utils;
import io.netty.channel.ChannelPipeline;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
public class Producer implements BrokerListListener {
private static Logger logger = LoggerFactory.getLogger(Producer.class);
private int pubId;
private String pubKey;
private String env; // dev、daily、gray、online
private volatile List brokerList;
private static int port = 8085;
private Map channelMap = new ConcurrentHashMap();
private ConfigManager configManager;
private ChannelManager channelManager;
private LocalFileManager localFileManager;
private HalfMsgManager halfMsgManager;
private ResponseManager responseManager;
private SendPacket sendPacket;
private AuthIndentity authIndentity;
private AckPubMsgProcesser ackPubMsgProcesser;
private CheckMsgProcesser checkMsgProcesser;
private ChannelPoolFactory channelPoolFactory;
private static String localIp;
private static ThreadLocal sf;
private AtomicBoolean inited = new AtomicBoolean(false);
private static ConcurrentMap pubers = new ConcurrentHashMap(); // 防止重复创建相同的producer
private EventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(16);
private static final String tpsKey = "TMQ_Producer";
static {
try {
Monitors.setMaxTps(tpsKey, 500);
sf = new ThreadLocal() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
localIp = Utils.getLocalIp();
} catch (Exception e) {
logger.error("", e);
}
}
public Producer(int pubId, String pubKey, String env) {
if(null != pubers.putIfAbsent(pubId, true)){
throw new RuntimeException("Producer[" + pubId + "] already existed");
}
this.pubId = pubId;
this.pubKey = pubKey;
this.env = env;
configManager = new ConfigManagerImpl();
configManager.setEnv(this.env);
channelManager = new ChannelManagerImpl();
channelManager.registeChannel(ChannelType.PUB, pubId, pubKey, channelMap);
localFileManager = new LocalFileManagerImpl();
localFileManager.setPubId(pubId);
localFileManager.setProducer(this);
responseManager = new ResponseManagerImpl();
responseManager.setAppId(pubId);
sendPacket = new SendPacketImpl();
sendPacket.setResponseManager(responseManager);
sendPacket.setChannelManager(channelManager);
halfMsgManager = new HalfMsgManagerImpl();
halfMsgManager.setPubId(pubId);
halfMsgManager.setSendPacket(sendPacket);
authIndentity = new AuthIndentityImpl();
ackPubMsgProcesser = new AckPubMsgProcesser();
ackPubMsgProcesser.setResponseManager(responseManager);
checkMsgProcesser = new CheckMsgProcesser();
checkMsgProcesser.setHalfMsgManager(halfMsgManager);
channelPoolFactory = new ChannelPoolFactory();
}
/**
* 与broker建立连接池
*
* @throws IOException
*/
public void init() throws IOException {
if (inited.compareAndSet(false, true)) {
configManager.init();
this.brokerList = configManager.getBrokerList(this);
authIndentity.setBrokerList(this.brokerList);
connectBrokers(this.brokerList);
channelManager.init();
localFileManager.init();
responseManager.init();
try {
// 等待初始化就绪
Thread.sleep(5000l);
} catch (InterruptedException e) {
}
}
}
/**
* 发送普通消息
*
* @param message
* @return
*/
public SendResult sendMessage(PubMessage message) {
boolean result = false;
try {
if(!Monitors.entry(tpsKey)){
try {
logger.warn("tps over 500 ...");
Thread.sleep(1000l);
} catch (InterruptedException e) {
}
}
SendResult sendResult = send(message, false, true);
if (sendResult.isSuccess()) {
result = true;
}
return sendResult;
} finally {
Monitors.exit(tpsKey, result);
}
}
/**
* 发送事务消息
*
* @param message
* @param arg
* 应用自己的参数
* @param localTranscationExector
* @see LocalTranscationExector
* @return
*/
public SendResult sendMessage(PubMessage message, Object arg, LocalTranscationExector localTranscationExector) {
boolean result = false;
try {
if(!Monitors.entry(tpsKey)){
try {
logger.warn("tps over 500 ...");
Thread.sleep(1000l);
} catch (InterruptedException e) {
}
}
SendResult sendResult = send(message, true, true);
if (sendResult.isSuccess()) {
TransactionStatus transactionStatus = localTranscationExector.execute(message, arg); // 执行本地事务
endLocalTranscation(sendResult.getMsgid(), transactionStatus);
if (TransactionStatus.RollbackTransaction.equals(transactionStatus)) {
sendResult.setSuccess(false);
sendResult.setInfo("local transcation rollback");
}
result = true;
}
return sendResult;
} finally {
Monitors.exit(tpsKey, result);
}
}
public SendResult send(PubMessage message, boolean isHalf, boolean backup) {
if (message == null || message.getBody() == null) {
throw new RuntimeException("消息不能为空");
}
if (message.getBody().length > 1024 * 10) {
throw new RuntimeException("消息体不能超过10K字节");
}
if (message.getKey() != null && message.getKey().length() > 100) {
throw new RuntimeException("key的长度不能超过100");
}
if (!authIndentity.authPubMsg(pubId, pubKey, message.getTopic())) {
throw new RuntimeException("请检查pubId, pubKey, topic !");
}
SendResult result = new SendResult();
MsgHeader header = new MsgHeader();
header.setKey(message.getKey());
header.setPubId(pubId);
header.setPubIp(localIp);
header.setTags(message.getTags());
if (message.getTicker() != null) {
header.setTicker(sf.get().format(message.getTicker()));
}
header.setTopic(message.getTopic());
header.setSubTopic(message.getSubTopic());
header.setType(isHalf ? 2 : 1);
PubMsgProtocol pubMsgProtocol = new PubMsgProtocol();
try {
byte[] headerBuf = JSONObject.toJSONString(header).getBytes("UTF-8");
pubMsgProtocol.setBody(message.getBody());
pubMsgProtocol.setHeader(headerBuf);
pubMsgProtocol.setHeaderLength(headerBuf.length);
pubMsgProtocol.setLength(headerBuf.length + message.getBody().length);
pubMsgProtocol.setPacketId(UUID.getPacketId());
Object resp = sendPacket.invokeSync(pubMsgProtocol, 2, ChannelType.PUB);
if (resp == null) {
if (backup && localFileManager.addFailedMsg(message, isHalf)) { // 本地文件容灾
result.setSuccess(true);
result.setInfo("failed to send msg, but save to local log, which will be retry");
return result;
}
result.setSuccess(false);
result.setInfo("failed to send msg");
return result;
} else {
String msgid = (String) resp;
result.setSuccess(true);
result.setInfo("success to send msg");
result.setMsgid(msgid);
return result;
}
} catch (Exception e) {
result.setSuccess(false);
result.setInfo(e.getMessage());
logger.error("", e);
}
return result;
}
/**
* 本地事务结束,通知broker处理之前的half消息
*
* @param msgid
* @param transactionStatus
*/
private void endLocalTranscation(String msgid, TransactionStatus transactionStatus) {
if(msgid != null){
halfMsgManager.ackTransactionStatus(transactionStatus, msgid);
}
}
/**
* 添加一个本地事务执行结果check接口实现
*
* @param localTransactionChecker
*/
public void addLocalTransactionChecker(LocalTransactionChecker localTransactionChecker) {
halfMsgManager.addLocalTransactionChecker(localTransactionChecker);
}
/**
* broker列表变更回调
*
* @param brokerList
*/
@Override
public void updateBrokerList(List brokerList) {
this.brokerList = brokerList;
authIndentity.setBrokerList(brokerList);
connectBrokers(brokerList);
}
private void connectBrokers(List brokerList) {
if (brokerList != null) {
try{ // 删除无效节点
if(channelMap != null && !channelMap.isEmpty()){
Iterator> iter = channelMap.entrySet().iterator();
while(iter.hasNext()){
Entry ipAndChannelPool = iter.next();
if(!brokerList.contains(ipAndChannelPool.getKey())){
ipAndChannelPool.getValue().destory();
iter.remove();
}
}
}
}catch(Exception e){
logger.error("",e);
}
for (String ip : brokerList) {
if(channelMap.containsKey(ip)){
continue;
}
ChannelPool channelPool = channelPoolFactory.getChannelPool(ip, port);
channelPool.setChannelPipelineFactory(new ChannelPipelineFactory() {
@Override
public void initChannelPipeline(ChannelPipeline channelPipeline) {
channelPipeline.addLast(new Decoder());
// channelPipeline.addLast(new Handler());
channelPipeline.addLast(eventExecutorGroup, new Handler(ackPubMsgProcesser, checkMsgProcesser));
channelPipeline.addLast(new Encoder());
}
});
channelPool.init();
channelMap.put(ip, channelPool);
}
}
}
}