cat客户端上报消息原理解析

CAT客户端上报消息时,是开启了一个sender线程从消息队列里面获取消息后给服务器上报消息。那么当服务器是集群时,CAT客户端是如何选择服务器的呢?本文着重分析一下CAT客户端路由的实现算法。

源码分析

TcpSocketSender

CAT客户端上报消息线程TcpSocketSender#initialize初始化方法,该方法由DefaultTransportManager#initialize调用,是在应用启动中由框架调用的初始化方法。

public void initialize() {
   Integer queueSize = SIZE;
   if (System.getProperty(COMMAND_LINE_QUEUE_CAPACITY) != null){
      try{
         queueSize = Integer.parseInt(System.getProperty(COMMAND_LINE_QUEUE_CAPACITY));@1
      }catch (Exception e){
         m_logger.error(String.format("Command Line Param[%s] is not valid, use default queue size %d !", COMMAND_LINE_QUEUE_CAPACITY, queueSize), e);
      }
   }
   m_queue = new DefaultMessageQueue(queueSize);@2

   Integer atomicQueueSize = queueSize;
   if (System.getProperty(COMMAND_LINE_ATOMIC_QUEUE_CAPACITY) != null){
      try{
         atomicQueueSize = Integer.parseInt(System.getProperty(COMMAND_LINE_ATOMIC_QUEUE_CAPACITY));
      }catch (Exception e){
         m_logger.error(String.format("Command Line Param[%s] is not valid, use default queue size %d !", COMMAND_LINE_ATOMIC_QUEUE_CAPACITY, atomicQueueSize), e);
      }
   }
   m_atomicTrees = new DefaultMessageQueue(atomicQueueSize);@3

   m_manager = new ChannelManager(m_logger, m_serverAddresses, m_queue, m_configManager, m_factory);@4

   Threads.forGroup("cat").start(this);@5
   Threads.forGroup("cat").start(m_manager);@6
   Threads.forGroup("cat").start(new MergeAtomicTask());@7
}

代码@1:获取queue大小。

代码@2:创建MessageQueue,用来存储非原子消息。

代码@3:创建MessageQueue,用来存储原子消息。

代码@4:创建一个ChannelManager,管理跟服务端通信的Channel。

代码@5:开启TcpSocketSender任务线程。

代码@6:开启ChannelManager任务线程。

代码@7:开启合并原子消息任务线程。

TcpSocketSender#run方法会从MessageQueue队列获取上报的消息,然后通过sendInternal方法上报消息。

private void sendInternal(MessageTree tree) {
		ChannelFuture future = m_manager.channel();@1
		ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer(10 * 1024); // 10K

		m_codec.encode(tree, buf);@2

		int size = buf.readableBytes();
		Channel channel = future.channel();

		channel.writeAndFlush(buf);@3
		if (m_statistics != null) {
			m_statistics.onBytes(size);
		}
	}

代码@1:从ChannelManager获取ChannelFuture对象。在ChannelManager构造方法中会初始化一个可用的Channel。

代码@2:编码上报的消息。

代码@3:发送消息。

ChannelManager

构造方法

public ChannelManager(Logger logger, List<InetSocketAddress> serverAddresses, MessageQueue queue,
      ClientConfigManager configManager, MessageIdFactory idFactory) {
   m_logger = logger;
   m_queue = queue;
   m_configManager = configManager;
   m_idfactory = idFactory;

   EventLoopGroup group = new NioEventLoopGroup(1, new ThreadFactory() {
      @Override
      public Thread newThread(Runnable r) {
         Thread t = new Thread(r);
         t.setDaemon(true);
         return t;
      }
   });

   Bootstrap bootstrap = new Bootstrap();
   bootstrap.group(group).channel(NioSocketChannel.class);
   bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
   bootstrap.handler(new ChannelInitializer<Channel>() {
      @Override
      protected void initChannel(Channel ch) throws Exception {
      }
   });
   m_bootstrap = bootstrap;

   String serverConfig = loadServerConfig();@1

   if (StringUtils.isNotEmpty(serverConfig)) {
      List<InetSocketAddress> configedAddresses = parseSocketAddress(serverConfig);
      ChannelHolder holder = initChannel(configedAddresses, serverConfig);@2

      if (holder != null) {
         m_activeChannelHolder = holder; @3
      } else {
         m_activeChannelHolder = new ChannelHolder();
         m_activeChannelHolder.setServerAddresses(configedAddresses);
      }
   } else {
      ChannelHolder holder = initChannel(serverAddresses, null);
      if (holder != null) {
         m_activeChannelHolder = holder;
      } else {
         m_activeChannelHolder = new ChannelHolder();
         m_activeChannelHolder.setServerAddresses(serverAddresses);
         m_logger.error("error when init cat module due to error config xml in /data/appdatas/cat/client.xml");
      }
   }
}

代码@1:从server拉取配置的路由列表。具体实现可见com.dianping.cat.system.page.router.Handler类。

代码@2:如果服务器端配置了路由列表,则用该路由列表初始化Channel。该方法从server返回的路由列表中选择第一个可用的ChannelHolder,然后赋值给m_activeChannelHolder。客户端上报数据时,会从ChannelManager中获取activeChannelHolder对象,然后上报数据。

代码@3:将获取到的有效的ChannelHolder赋值给m_activeChannelHolder,以后可以通过getActiveFuture方法获取ChannelFuture。

客户端设计

在这里插入图片描述

1、Cat客户端生产消息,放入到Message Queue。

2、TcpSocketSender从MessageQueue获取消息,上报给Cat服务器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值