Dubbo服务集群容错实践
手机应用是以聊天室为基础的,我们需要收集用户的操作行为,然后计算聊天室中在线人数,并实时在手机应用端显示人数,整个系统的架构如图所示:
上图中,主要包括了两大主要流程:日志收集并实时处理流程、调用读取实时计算结果流程,我们使用基于Dubbo框架开发的服务来提供实时计算结果读取聊天人数的功能。上图中,实际上业务接口服务器集群也可以基于Dubbo框架构建服务,就看我们想要构建什么样的系统来满足我们的需要。
如果不使用注册中心,服务消费方也能够直接调用服务提供方发布的服务,这样需要服务提供方将服务地址暴露给服务消费方,而且也无法使用监控中心的功能,这种方式成为直连。
如果我们使用注册中心,服务提供方将服务发布到注册中心,而服务消费方可以通过注册中心订阅服务,接收服务提供方服务变更通知,这种方式可以隐藏服务提供方的细节,包括服务器地址等敏感信息,而服务消费方只能通过注册中心来获取到已注册的提供方服务,而不能直接跨过注册中心与服务提供方直接连接。这种方式的好处是还可以使用监控中心服务,能够对服务的调用情况进行监控分析,还能使用Dubbo服务管理中心,方便管理服务,我们在这里使用的是这种方式,也推荐使用这种方式。使用注册中心的Dubbo分布式服务相关组件结构,如下图所示:
下面,开发部署我们的应用,通过如下4个步骤来完成:
服务接口将服务提供方(Provider)和服务消费方(Consumer)连接起来,服务提供方实现接口中定义的服务,即给出服务的实现,而服务消费方负责调用服务。我们接口中给出了2个方法,一个是实时查询获取当前聊天室内人数,另一个是查询一天中某个/某些聊天室中在线人数峰值,接口定义如下所示:
[url=][/url]
package org.shirdrn.dubbo.api;import java.util.List;public interface ChatRoomOnlineUserCounterService { String queryRoomUserCount(String rooms); List<String> getMaxOnlineUserCount(List<String> rooms, String date, String dateFormat);}[url=][/url]
接口是服务提供方和服务消费方公共遵守的协议,一般情况下是服务提供方将接口定义好后提供给服务消费方。
服务提供方实现接口中定义的服务,其实现和普通的服务没什么区别,我们的实现类为ChatRoomOnlineUserCounterServiceImpl,代码如下所示:
[url=][/url]
package org.shirdrn.dubbo.provider.service;import java.util.List;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.shirdrn.dubbo.api.ChatRoomOnlineUserCounterService;import org.shirdrn.dubbo.common.utils.DateTimeUtils;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import com.alibaba.dubbo.common.utils.StringUtils;import com.google.common.base.Strings;import com.google.common.collect.Lists;public class ChatRoomOnlineUserCounterServiceImpl implements ChatRoomOnlineUserCounterService { private static final Log LOG = LogFactory.getLog(ChatRoomOnlineUserCounterServiceImpl.class); private JedisPool jedisPool; private static final String KEY_USER_COUNT = "chat::room::play::user::cnt"; private static final String KEY_MAX_USER_COUNT_PREFIX = "chat::room::max::user::cnt::"; private static final String DF_YYYYMMDD = "yyyyMMdd"; public String queryRoomUserCount(String rooms) { LOG.info("Params[Server|Recv|REQ] rooms=" + rooms); StringBuffer builder = new StringBuffer(); if(!Strings.isNullOrEmpty(rooms)) { Jedis jedis = null; try { jedis = jedisPool.getResource(); String[] fields = rooms.split(","); List<String> results = jedis.hmget(KEY_USER_COUNT, fields); builder.append(StringUtils.join(results, ",")); } catch (Exception e) { LOG.error("", e); } finally { if(jedis != null) { jedis.close(); } } } LOG.info("Result[Server|Recv|RES] " + builder.toString()); return builder.toString(); } @Override public List<String> getMaxOnlineUserCount(List<String> rooms, String date, String dateFormat) { // HGETALL chat::room::max::user::cnt::20150326 LOG.info("Params[Server|Recv|REQ] rooms=" + rooms + ",date=" + date + ",dateFormat=" + dateFormat); String whichDate = DateTimeUtils.format(date, dateFormat, DF_YYYYMMDD); String key = KEY_MAX_USER_COUNT_PREFIX + whichDate; StringBuffer builder = new StringBuffer(); if(rooms != null && !rooms.isEmpty()) { Jedis jedis = null; try { jedis = jedisPool.getResource(); return jedis.hmget(key, rooms.toArray(new String[rooms.size()])); } catch (Exception e) { LOG.error("", e); } finally { if(jedis != null) { jedis.close(); } } } LOG.info("Result[Server|Recv|RES] " + builder.toString()); return Lists.newArrayList(); } public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; }}[url=][/url]
代码中通过读取Redis中数据来完成调用,逻辑比较简单。对应的Maven POM依赖配置,如下所示:View Code
有关对Dubbo框架的一些依赖,我们单独放到一个通用的Maven Module中(详见后面“附录:Dubbo使用Maven构建依赖配置”),这里不再多说。服务提供方实现,最关键的就是服务的配置,因为Dubbo基于Spring来管理配置和实例,所以通过配置可以指定服务是否是分布式服务,以及通过配置增加很多其它特性。我们的配置文件为provider-cluster.xml,内容如下所示:
[url=][/url]
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> |