netty中用到redis做消息中间件

由于现在做的项目的业务需要,需要后台服务器,主动给移动端推送,任务,数据库是mysql,刚开始是轮询,后来想高大上,弄个主动推送,用netty做。

检测数据变化,实现推送,用心跳频率,来检测任务状态变化,然后推送,遭到否决,不及时。

轮询,对服务器性能消耗大,之前为了解决这个问题,ios和android通一套代码整了两个tcp服务端口,改进方法,用redis在其他系统中记录有变化的任务,生成,其他的对任务的修改,然后在tcp第一次连接的时候查询客户的任务记录记录有连接channel的message中

Redis队列功能介绍

List


常用命令:

Blpop删除,并获得该列表中的第一元素,或阻塞,直到有一个可用

Brpop删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用

Brpoplpush

Lindex获取一个元素,通过其索引列表

Linsert在列表中的另一个元素之前或之后插入一个元素

Llen获得队列(List)的长度

Lpop从队列的左边出队一个元素

Lpush从队列的左边入队一个或多个元素

Lpushx当队列存在时,从队到左边入队一个元素

Lrange从列表中获取指定返回的元素

Lrem从列表中删除元素

Lset设置队列里面一个元素的值

Ltrim修剪到指定范围内的清单

Rpop从队列的右边出队一个元素

Rpoplpush删除列表中的最后一个元素,将其追加到另一个列表

Rpush从队列的右边入队一个元素

Rpushx从队列的右边入队一个元素,仅队列存在时有效



代码:

public class TaskPush implements Runnable {
    private final static Logger logger = LoggerFactory.getLogger(TaskPush.class);

    //业务线程处理数据库业务
    ExecutorService threadPool = Executors.newCachedThreadPool();

   

    private static TaskMapper taskMapper;

    

    static {
        // 获取spring上下文,使用静态代码块初始化
        appContext = new ClassPathXmlApplicationContext(new String[]{"classpath:spring-ios.xml"});
        
    }

    public TaskPush() {
    }

    @Override
    public void run() {
        //用线程处理业务 
        while (true){
            //遍历所有的会话
            try{
                Map<String, TcpMessage> userList= ChannelManager.userList;
                //判断是否为空
                if(userList.isEmpty()){
                    //System.out.println("now is empty");
                    //如果现在还没有客户端连接服务器 线程沉睡500
                    //Thread.sleep(500);
                }else {
                    for(String s: userList.keySet()){
                       
                        TcpMessage message= ChannelManager.userList.get(s);

                        //做一次自我清理
                        if(!message.getCtx().channel().isActive()){
                            ChannelManager.userList.remove(s);
                            continue;
                        }

                        
                        if(s.indexOf(ClientType.SS.name()) >-1){
                            //查询缓存中的任务做判断
                            TaskDO rd=constantRedisDao.queryTcpTask(s);
                            //查询原来任务
                            TaskDO ld=(TaskDO)message.getObject();
                            if(rd != null){

                                if(ld == null){//司机接受任务
                                    //加入线程池,推送缓存中的任务
                                    if(rd.isActive())
                                        threadPool.submit(new MyTask(message,rd));
                                }else {
                                    //与原来的任务做比较,任务id和任务状态
                                    long rdid=rd.getId();
                                    long ldid=ld.getId();
                                    int rds=rd.getStatus();
                                    int lds=ld.getStatus();
                                    int rv= rd.getVersion();
                                    int lv=ld.getVersion();

                                    if(rdid==ldid && rds==lds && rv==lv){
                                        //只有通一个任务,并且状态一样才不会推送
                                        //System.out.println("do nothing !!!");
                                    }else {
                                        //加入线程池,推送缓存中的任务
                                        //第一种,不是同一个任务,说明刚连接tcp而且有任务.推送新任务
                                        if(rdid == ldid){
                                            threadPool.submit(new MyTask(message,rd));
                                        }else {
                                            threadPool.submit(new MyTask(message,ld));
                                        }
                                        //threadPool.submit(new MyTask(message,rd));
                                    }
                                }
                                //更新任务
                                message.setObject(rd);
                                ChannelManager.userList.put(s,message);
                            }
                        }
                    }
                }
                //Thread.sleep(50);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {


    }


    class MyTask implements Runnable{
        private TcpMessage message;

        private TaskDO taskDO;

        public MyTask(TcpMessage message, TaskDO taskDO) {
            this.message = message;
            this.taskDO = taskDO;
        }

        @Override
        public void run() {
            synchronized (Object.class){
                try{
                   //推送消息生成省略
                    message.getCtx().writeAndFlush(tcpResponseBuilder.build());

                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}




public class TcpMessage {
    //逻辑code
    private int code;

    //信息分类
    private String useType;

    //id
    private long id;

    //ctx -->socketchannel
    private ChannelHandlerContext ctx;

    //用到的信息比如任务,或者用户订单
    private Object object;

    public TcpMessage() {
    }

    public TcpMessage(String useType, long id, ChannelHandlerContext ctx, Object object) {
        this.useType = useType;
        this.id = id;
        this.ctx = ctx;
        this.object = object;
    }

    public TcpMessage(int code, String useType, long id, ChannelHandlerContext ctx, Object object) {
        this.code = code;
        this.useType = useType;
        this.id = id;
        this.ctx = ctx;
        this.object = object;
    }

    public Object getObject() {
        return object;
    }

    public TcpMessage setObject(Object object) {
        this.object = object;
        return this;
    }

    public int getCode() {
        return code;
    }

    public TcpMessage setCode(int code) {
        this.code = code;
        return this;
    }

    public String getUseType() {
        return useType;
    }

    public TcpMessage setUseType(String useType) {
        this.useType = useType;
        return this;
    }

    public long getId() {
        return id;
    }

    public TcpMessage setId(long id) {
        this.id = id;
        return this;
    }

    public ChannelHandlerContext getCtx() {
        return ctx;
    }

    public TcpMessage setCtx(ChannelHandlerContext ctx) {
        this.ctx = ctx;
        return this;
    }
}



这样只是 简单的实现了,信息推送。下面要解决,信息发送后没接收到,多端改变任务的时候,因推送不及时,就会在rendis中被新修改的任务覆盖掉,造成漏发,考虑用队列来做,不能只是简单的存入redis一个任务,再拿出来做比较

改进用redis做队列,多对一,制造和消费,多制造,单消费,符合

借鉴例子


redis 命令:来自http://www.cnblogs.com/ztteng/p/4073211.html


import java.util.ArrayList;  
import java.util.List;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  
   
public class RedisCur {  
  public static void main(String[] args) {  
    List<Future> futures = new ArrayList<Future>();  
    ExecutorService executorService = Executors.newCachedThreadPool();  
    for (int i = 0; i < 100; i++) {  
      futures.add(executorService.submit(new WriteRedis(String.valueOf(i))));  
    }  
  }  
   
}  
   
   
   
public class WriteRedis implements Runnable {  
  private String value;  
  /** 
   * @param value 
   */  
  public WriteRedis(String value) {  
    super();  
    this.value = value;  
  }  
    
  public void run(){  
    Jedis jedisClient = new Jedis("127.0.0.1", 6379);  
    try {  
      String threadName = Thread.currentThread().getName();  
      jedisClient.lpush("LOCK", value);  
      System.err.println(threadName + "-" + value);  
    } catch (Exception e) {  
      e.printStackTrace();  
    }  
     
  }  
   
}  

public class RedisListener {  
    
  public static void main(String[] args) {  
    Listener thread1 = new Listener();  
    thread1.start();  
  }  
   
   
}  
   
   
import redis.clients.jedis.Jedis;  
public class Listener extends Thread {  
   
  @Override  
  public void run() {  
    Jedis jedisClient = new Jedis("127.0.0.1", 6379);  
    while (true) {  
      String value = jedisClient.lpop("LOCK");  
        
      System.err.println(value);  
      if (value == null) {  
        try {  
          System.err.println("================移除完成");  
          Thread.sleep(1000);  
          System.err.println("================继续监控");  
        } catch (InterruptedException e) {  
          e.printStackTrace();  
        }  
      }  
    }  
     
  }  
  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值