服务框架学习(Extra-1):服务型消息队列

面向服务的消息队列

1. 遇到问题

在团队开发时,为了让团队合作更愉快,于是有了RPC(远程方法调用),可以让两个项目相互使用API时更加友好,因为RPC调用非本地API机制和本地调用一样,无需考虑具体实现。

RPC与MQ适合的场景

RPC适合使用在需要立即得到(远程方法)结果,在开发中和十分方便
但是在调用之后就要等待返回结果(当然也有异步RPC)是很费时间的
且访问量过高时RPC性能会拖慢服务器
RPC
什么时候适合使用MQ呢?

  1. 不希望发送端(消费者)受限于处理端(生产者)的速度时
  2. 可以很好处理服务器峰值访问量高的情况(请求会被一个一个的放进队列,而服务器会一个一个的完成,不会因为峰值过高而宕机)

MQ

2. 实现

(我的上一篇文章实现了简单的消息队列:传送门
在整合网络服务上参考了RPC的实现,不过更简单
发送者只需要给服务器输出流写入消息
接收者只需要从服务器输出流得到消息
注意几点:1.处理访问空队列的情况,2.为队列上同步锁

  1. 发布服务端
    Publisher.java:
    /**
     * 一个端口对应一个队列
     * @param port
     */
    public void publishQueue(int port)
    {
    	MyMessageQueue queue = new MyMessageQueue(); // 创建一个新队列
    	System.out.println("Queue Published on " + port);
    	try
    	{
    		ServerSocket ss = new ServerSocket(port);
    		while (true)
    		{
    			Socket socket = ss.accept(); // 等待连接
    			ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
    			String methodName = ois.readUTF(); // 读取请求的方法名
    			Class[] types = (Class[]) ois.readObject(); // 读取类型
    			Object[] args = (Object[]) ois.readObject(); // 读取参数
    			Class clazz = MyMessageQueue.class;
    			
    			Method method = clazz.getMethod(methodName, types);
    			Object ret = method.invoke(queue, args); // 执行方法
    			ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
    			oos.writeObject(ret); // 写入输出流
    			oos.flush();
    			
    			ois.close();
    			oos.close();
    			socket.close();
    		}
    	}
    	catch(Exception e)
    	{
    		e.printStackTrace();
    	}
    }
    
  2. 客户端(发布消息或接收消息)
    使用方要有接口,用于传递方法名等参数,来执行远端方法
    Client.java:
    /**
     * 
     * @param clazz 队列的接口
     * @return
     */
    public Object queueProxy(Class clazz) {
    	return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, new InvocationHandler() {
    
    				@Override
    				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    					Socket socket = new Socket(address, port);
    					ObjectOutputStream oos = new ObjectOutputStream(socket
    							.getOutputStream());
    					String methodName = method.getName();
    					
    					Class[] types = method.getParameterTypes();
    					oos.writeUTF(methodName); // 写入方法名
    					oos.writeObject(types); // 写入参数类型
    					oos.writeObject(args); // 写入参数
    					
    					oos.flush();
    
    					ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
    					Object ret = ois.readObject(); // 得到响应
    					
    					oos.close();
    					ois.close();
    					socket.close();
    					return ret;
    				}
    			});
    }
    

这里的过程类似RPC,这篇就不多赘述。

3. 测试

PublisherTest.java:

public void publishTest()
{
	Publisher publisher = new Publisher();
	publisher.publishQueue(9092); // 在9092端口发布队列服务
}

ClientTest.java:

static String address = "localhost";
static int port = 9092;
public void clientTest()
{
	MessageQueue queue = (MessageQueue) queueProxy(MessageQueue.class);
	String result = queue.post("drake 1");
	String result1 = queue.post("drake 2");
	System.out.println(result + " " + result1);
	System.out.println(queue.size());
	String msg = queue.nextMessage();
	System.out.println("get: " + msg);
	String msg1 = queue.nextMessage();
	System.out.println("get: " + msg1);
	String msg2 = queue.nextMessage();
	System.out.println("get: " + msg2);
}

输出:

Queue Published on 9092
added:drake-1[strategy: None]
added:drake-2[strategy: None]
size: 2
get: drake-1
get: drake-2
get: null

这样就部署了一个消息队列服务的基本功能,接下来还有很多需要解决,比如:

  1. 服务器在高并发情况下的负载均衡(目前是单线程和悲观锁,在高并发下性能不好)
  2. 队列策略(比如按权值的优先队列)
  3. 延迟队列

这些是我暂时能想到的,所以架构之路还很长~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值