【9】JMicro微服务-发布订阅消息服
【9】JMicro微服务-发布订阅消息服
1. JMicro消息服务目前实现特性
a. JMicro只支持发布订阅消息服务,不支持队列式消息服务;
b. 不支持消息持久化,所以不能保证消息一定能被消费者消费;
c. 发布消息时如果没有消费者,消息直接丢弃;
d. 如果消息按配置的重发时间间隔重复发送多次(可配置)失败,消息直接丢弃;
e. 如果消息失败重发队列超过预先配置的数量,最先失败的消息会被直接丢弃,而新失败消息直接入失败队列排队等待重发;
f. 基于以上几点,如果要求绝对可靠的消息系统,而不是高性能的消息系统,不建议使用JMicro消息服务;
JMicro追求的是简单并且高性能,如果消费者服务是正常等待消息状态,那么消息肯定能高效从消息发送者直达消费者服务,如果消费者不在线,或出了问题无法消费消息,直接失败告诉使用者系统出了问题才应该是最佳的避免问题的方法。
一味地为了解决或支持次要的需求而增加系统的复杂度本身也会增加系统出问题的隐患,特别是复杂度达到一定程度后,很可能意味着软件的失败。
Do one thing and do it well! 微服务口号。
2. 启动消息服务
新打开一个新的CMD窗口,CD进入/jmicro.pubsub,运行
mvn clean install -Pbuild-main (只需构建一次,以后可以重复运行)
运行pubsub服务
java -jar target/jmicro.pubsub-0.0.1-SNAPSHOT-jar-with-dependencies.jar
如果启动时最后出现如下信息,说明pubsub没有启动,需要将/PubSubManager/enableServer的值从false,改为true
通过ZKUI修改方式如下图:
将enableServer的值从false改为true,然后重启服务即可,因为这个值是启动时就检测,只使用一次,即时生效是指:修改值后,之后的使用会使用新的值。
3. 开发消费者
/jmicro.example.provider/src/main/java/org/jmicro/example/pubsub/impl/SimplePubsubImpl.java
1 @Service(maxSpeed=-1,baseTimeUnit=Constants.TIME_SECONDS) 2 @Component 3 public class SimplePubsubImpl implements ISimplePubsub { 4 5 private final static Logger logger = LoggerFactory.getLogger(SimplePubsubImpl.class); 6 7 @Subscribe(topic="/jmicro/test/topic01") 8 public void helloTopic(PSData data) { 9 System.out.println("helloTopic: "+data.getTopic()+", data: "+ data.getData().toString()); 10 } 11 12 @Subscribe(topic="/jmicro/test/topic01") 13 public void testTopic(PSData data) { 14 System.out.println("testTopic: "+data.getTopic()+", data: "+ data.getData().toString()); 15 } 16 17 @Subscribe(topic=MonitorConstant.TEST_SERVICE_METHOD_TOPIC) 18 public void statis(PSData data) { 19 20 Map<Integer,Double> ps = (Map<Integer,Double>)data.getData(); 21 22 logger.info("总请求:{}, 总响应:{}, TO:{}, TOF:{}, QPS:{}" 23 ,ps.get(MonitorConstant.CLIENT_REQ_BEGIN) 24 ,ps.get(MonitorConstant.STATIS_TOTAL_RESP) 25 ,ps.get(MonitorConstant.CLIENT_REQ_TIMEOUT) 26 ,ps.get(MonitorConstant.CLIENT_REQ_TIMEOUT_FAIL) 27 ,ps.get(MonitorConstant.STATIS_QPS) 28 ); 29 30 //System.out.println("Topic: "+data.getTopic()+", data: "+ data.getData().toString()); 31 } 32 33 }
消息消费者也是一个RPC服务,由Component和Service注解实现类,不同点是方法不再由SMethod注解,而是由Subcribe注解,并增加topic属性,值是消息的主题。
方法唯一参数是org.jmicro.api.pubsub.PSData,代码如下
public final class PSData implements Serializable{ private static final long serialVersionUID = 389875668374730999L; private Map<String,Object> context = new HashMap<>(); private byte flag = 0; private String topic; private Object data; public byte getFlag() { return flag; } public void setFlag(byte flag) { this.flag = flag; } public String getTopic() { return topic; } public void setTopic(String topic) { this.topic = topic; } public Map<String, Object> getContext() { return context; } public void setContext(Map<String, Object> context) { this.context = context; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public void put(String key,Object v) { this.context.put(key, v); } @SuppressWarnings("unchecked") public <T> T get(String key) { return (T) this.context.get(key); } }
data即是消息主体内容,可以是任意JMicro支持的参数类型,支持的参数类型后面会有专题小节详细说明,目前只需要知道:
a. Java 8种基本字据类型,字符串,java.util.Date,java.nio.ByteBuffer;
b. 由a组成的任意POJO类型;
c. 由a,b,c,d组成的任意数组类型,集合类型(LIST,SET);
d. Key为String类型,值为a,b,c,d组成的任意Map类型;
运行消费者
java -jar target/jmicro.example.provider-0.0.1-SNAPSHOT-jar-with-dependencies.jar
4. 消息生产者
public class TestPubSubServer extends JMicroBaseTestCase{ @Test public void testPresurePublish() { final Random ran = new Random(); PubSubManager psm = of.get(PubSubManager.class); AtomicInteger id = new AtomicInteger(0); Runnable r = ()->{ while(true) { try { //Thread.sleep(2000); Thread.sleep(ran.nextInt(100)); psm.publish(new HashMap<String,Object>(), TOPIC, "test pubsub server id: "+id.getAndIncrement()); } catch (Throwable e) { System.out.println(e.getMessage());; } } }; new Thread(r).start(); new Thread(r).start(); /*new Thread(r).start(); new Thread(r).start(); new Thread(r).start();*/ JMicro.waitForShutdown(); } @Test public void testPublishStringMessage() { PubSubManager psm = of.get(PubSubManager.class); psm.publish(new HashMap<String,Object>(), TOPIC, "test pubsub server"); JMicro.waitForShutdown(); } }
这是一个基于JUnit4的单元测试类,继承自org.jmicro.test.JMicroBaseTestCase,消息发布通过org.jmicro.api.pubsub.PubSubManager的三个publish重载方法实现
PubSubManager psm = of.get(PubSubManager.class); psm.publish(new HashMap<String,Object>(), TOPIC, “test pubsub server”);
of是JMicroBaseTestCase成员变量,IObjectFactory类型,系统启动就可使用,类似Spring容器,目前知道点就行。
PubSubManager也是系统预实例化的消息发送接口,从of拿来即用。
Eclipse或IDEA分别运行上面3个单元测试方法,查看消费者终端输出,消费端输出代码如下图:
testPublishStringMessage:发送一个简单字符串消息,消费端输出如下图:
testPresurePublish开启多个线程重复发送消息,用于消息服务系统做压力测试 ,消费端输出如下图: