高并发消息处理器

来源:

工作需要实现消息路由的中间层模块

测试结果:

 

2W客户, 每客户10 Request -> MQEngine -> 本地tomcat

消息转发并发量: 6.7K 零丢包

设计图



1. MQEngine

package lightmq;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MQEngine<E, P extends MessageHandler<E>> {
	
	/**
     * 消息队列
     * TODO 优化改为 LightQueue(内部实现为queue组)
     */
    final Queue<E> queue = new ConcurrentLinkedQueue<E>();
    //final Queue<E> queue1 = new LightQueue<E>(10);
    
    /**
     * handler class
     */
    private Class<? extends MessageHandler<E>> handlerClass;
    
    /**
     * 消费者线程池
     */
    ExecutorService consumerES;    
    
    /**
     * 消费者数量
     */
    private int consumerSize = 1;
    
    private Runnable[] consumers;
    
    /**
     * 构造函数
     * 
     * @param c 处理器类
     */
    public MQEngine(Class<? extends MessageHandler<E>> c){
        this(1, 1, c);
    }
    
    /**
     * 构�?函数 
     * 
     * @param threadPoolSize 线程池大�?
     * @param consumerSize 消息者数�?
     * @param c 处理器类�?
     */
    public MQEngine(int threadPoolSize, int consumerSize, Class<? extends MessageHandler<E>> c){
        consumerES = Executors.newFixedThreadPool(threadPoolSize);
        this.handlerClass = c;
        this.consumerSize = consumerSize;        
    }
    
    /**
     * 启动消费者线�?
     * @param consumerSize
     * @param c
     */
    public void start() {
        final Class<? extends MessageHandler<E>> c = this.handlerClass;
        
        class ConsumerTask implements Runnable{            
            
            @Override
            public void run() {
                MessageHandler<E> p = null;
                try {
                    p = c.newInstance();
                } catch (InstantiationException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (IllegalAccessException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                // 
                int i = 0;
                while(true){
                    try {
                        if (!queue.isEmpty()) {
                            p.consume(queue.poll());
                        }
                        i++;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // 每执行100次
                    if(10==i){
                        synchronized (this) {
                            try {
                                i = 0;
                                wait(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }                            
                    }
                }
            }
        }
        
        this.consumers = new Runnable[this.consumerSize];
        for (int i = 0; i < this.consumers.length; i++) {
            consumers[i] = new ConsumerTask();
        }
        
        for (int i = 0; i < consumers.length; i++) {
            consumerES.execute(consumers[i]);
        }
    }

    /**
     * 
     * @param e
     */
    public void push(E e){
        queue.add(e);
        for (int i = 0; i < this.consumers.length; i++) {
            synchronized (consumers[i]) {
                consumers[i].notify();
            }            
        }        
    }
    
    /**
     * 
     */
    public void destory(){
        this.queue.clear();
        this.consumerES.shutdown();
    }
	
}

2. MessageHandler

package lightmq;

/**
 * 消息处理器
 * 由子类派生
 * @author kevin
 *
 * @param <E>
 */
public abstract class MessageHandler<E> {
	
	public abstract void consume(E e);

}

3.MyMessageHandler

package lightmq;

import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.nio.conn.NHttpClientConnectionManager;

/**
 * 业务相关消息处理器
 * @author kevin
 *
 */
public class MyMessageHandler extends MessageHandler<String>{
	
	static AtomicLong sentCount = new AtomicLong(0);
    
    static NHttpClientConnectionManager connMgr;
    
    @Override
    public void consume(String e) {
        sendToTomcat(e);
    }
    
    private CloseableHttpAsyncClient httpclient = null;
    
    public MyMessageHandler(){
        
        try {
            connMgr = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor());
            httpclient = HttpAsyncClients.createMinimal(connMgr);
            httpclient.start();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    /**
     * 发给sc
     * @param message
     */
    private void sendToTomcat(String message){
        long startTime = System.currentTimeMillis();        
        
        try {
            
            
            // http[GET]请求, 
            final HttpGet request1 = new HttpGet("http://localhost");
            Future<HttpResponse> future = httpclient.execute(request1, null);
            
            // and wait until a response is received
            HttpResponse response1;
            response1 = future.get();
            System.out.println("message " + message + ":" + request1.getRequestLine() + "->" + response1.getStatusLine());
            System.out.println(message + " Sent; Cost:" + (System.currentTimeMillis() - startTime) + "; Succeed  Sent: " + sentCount.incrementAndGet());
        } catch (Exception e1) {
            System.err.println(e1.getMessage());
        } finally{
            // 关闭链接
            if(null!=httpclient){
                try {
                    //httpclient.close();
                } catch (Exception e1) {
                    //e1.printStackTrace();
                    System.err.println(e1.getMessage());
                }
            }
        }
    }
}

 4.M2Queue

package lightmq;

import java.util.Collection;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * 
 * @author kevin.xu
 *
 * @param <V>
 */
public class M2Queue<V> implements Queue<V>{
	/**
     * 队列数组
     */
    private Queue<V> queues[];
    
    /**
     * 
     * @param initQueueSize
     */
    public M2Queue(int initQueueSize) {
        queues = new Queue[initQueueSize];
        for (int i = 0; i < queues.length; i++) {
            queues[i] = new ConcurrentLinkedQueue<V>();
        }
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean contains(Object o) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public Iterator<V> iterator() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Object[] toArray() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public <T> T[] toArray(T[] a) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean remove(Object o) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends V> c) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void clear() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public boolean add(V e) {
        return offer(e);
    }

    /**
     * 添加到元素最少的队列中
     */
    @Override
    public boolean offer(V e) {
        return queues[getSmallestQueueIndex()].offer(e);
    }

    /**
     * 从元素最大的队列中remove
     */
    @Override
    public V remove() {
        return queues[getLargestQueueIndex()].remove();
    }

    /**
     * 从元素最大的队列中poll
     */
    @Override
    public V poll() {
        return queues[getLargestQueueIndex()].poll();
    }

    /**
     * 从元素最大的队列中element
     */
    @Override
    public V element() {
        return queues[getLargestQueueIndex()].element();
    }

    /**
     * 先从记录数最多的queue里peek
     */
    @Override
    public V peek() {
        return queues[getLargestQueueIndex()].peek();
    }
    
    /**
     * 返回最少记录数的queue
     * 
     * @return
     */
    private int getSmallestQueueIndex(){
        int index = 0;
        if (queues.length > 1) {
            for (int i = index; i < queues.length; i++) {
                if(queues[i].size() > queues[i+1].size()){
                    index = i+1;
                }
            }
        }
        return index;
    }
    
    /**
     * 返回最多记录数的queue
     * 
     * @return
     */
    private int getLargestQueueIndex(){
        int index = 0;
        if (queues.length > 1) {
            for (int i = index; i < queues.length; i++) {
                if(queues[i].size() < queues[i+1].size()){
                    index = i+1;
                }
            }
        }
        return index;
    }
}

 5.TestMQ

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

import lightmq.MQEngine;
import lightmq.MyMessageHandler;

/**
 * MQEngine测试类
 * @author kevin
 *
 */
public class TestMQ {
	public static void main(String[] args) {	
		final AtomicLong l = new AtomicLong(0);
		// 
		final MQEngine<String, MyMessageHandler> mq = new MQEngine<String, MyMessageHandler>(10, 50, MyMessageHandler.class);		
		mq.start();
		// 模拟客户并发数
		final int PRODUCER_SIZE = 200000;
		// 模拟每个客户平均请求次数
		final int REQUEST_TIME = 10;
		
		ExecutorService es = Executors.newFixedThreadPool(10);
		for (int i = 0; i < PRODUCER_SIZE; i++) {
			es.execute(new Runnable() {
				@Override
				public void run() {
					for (int i = 0; i < REQUEST_TIME; i++) {						
						mq.push(String.valueOf(l.incrementAndGet()));
					}
				}
			});
		}
		
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(mq.size());
		
	}
}

猜你喜欢

转载自code-artisan.iteye.com/blog/1997239
今日推荐