正在显示
10 个修改的文件
包含
81 行增加
和
12 行删除
| @@ -6,6 +6,7 @@ import com.crossoverjie.cim.client.service.EchoService; | @@ -6,6 +6,7 @@ import com.crossoverjie.cim.client.service.EchoService; | ||
| 6 | import com.crossoverjie.cim.client.service.MsgHandle; | 6 | import com.crossoverjie.cim.client.service.MsgHandle; |
| 7 | import com.crossoverjie.cim.client.service.RouteRequest; | 7 | import com.crossoverjie.cim.client.service.RouteRequest; |
| 8 | import com.crossoverjie.cim.client.service.impl.ClientInfo; | 8 | import com.crossoverjie.cim.client.service.impl.ClientInfo; |
| 9 | +import com.crossoverjie.cim.client.thread.ContextHolder; | ||
| 9 | import com.crossoverjie.cim.client.vo.req.GoogleProtocolVO; | 10 | import com.crossoverjie.cim.client.vo.req.GoogleProtocolVO; |
| 10 | import com.crossoverjie.cim.client.vo.req.LoginReqVO; | 11 | import com.crossoverjie.cim.client.vo.req.LoginReqVO; |
| 11 | import com.crossoverjie.cim.client.vo.res.CIMServerResVO; | 12 | import com.crossoverjie.cim.client.vo.res.CIMServerResVO; |
| @@ -90,7 +91,7 @@ public class CIMClient { | @@ -90,7 +91,7 @@ public class CIMClient { | ||
| 90 | * 启动客户端 | 91 | * 启动客户端 |
| 91 | * | 92 | * |
| 92 | * @param cimServer | 93 | * @param cimServer |
| 93 | - * @throws InterruptedException | 94 | + * @throws Exception |
| 94 | */ | 95 | */ |
| 95 | private void startClient(CIMServerResVO.ServerInfo cimServer) { | 96 | private void startClient(CIMServerResVO.ServerInfo cimServer) { |
| 96 | Bootstrap bootstrap = new Bootstrap(); | 97 | Bootstrap bootstrap = new Bootstrap(); |
| @@ -102,7 +103,7 @@ public class CIMClient { | @@ -102,7 +103,7 @@ public class CIMClient { | ||
| 102 | ChannelFuture future = null; | 103 | ChannelFuture future = null; |
| 103 | try { | 104 | try { |
| 104 | future = bootstrap.connect(cimServer.getIp(), cimServer.getCimServerPort()).sync(); | 105 | future = bootstrap.connect(cimServer.getIp(), cimServer.getCimServerPort()).sync(); |
| 105 | - } catch (InterruptedException e) { | 106 | + } catch (Exception e) { |
| 106 | errorCount++; | 107 | errorCount++; |
| 107 | 108 | ||
| 108 | if (errorCount >= configuration.getErrorCount()) { | 109 | if (errorCount >= configuration.getErrorCount()) { |
| @@ -204,9 +205,10 @@ public class CIMClient { | @@ -204,9 +205,10 @@ public class CIMClient { | ||
| 204 | //首先清除路由信息,下线 | 205 | //首先清除路由信息,下线 |
| 205 | routeRequest.offLine(); | 206 | routeRequest.offLine(); |
| 206 | 207 | ||
| 207 | - LOGGER.info("reconnect...."); | 208 | + echoService.echo("cim server shutdown, reconnecting...."); |
| 208 | start(); | 209 | start(); |
| 209 | - LOGGER.info("reconnect success"); | 210 | + echoService.echo("Great! reconnect success!!!"); |
| 211 | + ContextHolder.clear(); | ||
| 210 | } | 212 | } |
| 211 | 213 | ||
| 212 | /** | 214 | /** |
| @@ -87,7 +87,7 @@ public class BeanConfig { | @@ -87,7 +87,7 @@ public class BeanConfig { | ||
| 87 | @Bean("scheduledTask") | 87 | @Bean("scheduledTask") |
| 88 | public ScheduledExecutorService buildSchedule(){ | 88 | public ScheduledExecutorService buildSchedule(){ |
| 89 | ThreadFactory sche = new ThreadFactoryBuilder() | 89 | ThreadFactory sche = new ThreadFactoryBuilder() |
| 90 | - .setNameFormat("scheduled-%d") | 90 | + .setNameFormat("reconnect-job-%d") |
| 91 | .setDaemon(true) | 91 | .setDaemon(true) |
| 92 | .build(); | 92 | .build(); |
| 93 | ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1,sche) ; | 93 | ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1,sche) ; |
| 1 | package com.crossoverjie.cim.client.service.impl; | 1 | package com.crossoverjie.cim.client.service.impl; |
| 2 | 2 | ||
| 3 | import com.crossoverjie.cim.client.client.CIMClient; | 3 | import com.crossoverjie.cim.client.client.CIMClient; |
| 4 | +import com.crossoverjie.cim.client.thread.ContextHolder; | ||
| 4 | import com.crossoverjie.cim.common.kit.HeartBeatHandler; | 5 | import com.crossoverjie.cim.common.kit.HeartBeatHandler; |
| 5 | import io.netty.channel.ChannelHandlerContext; | 6 | import io.netty.channel.ChannelHandlerContext; |
| 6 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
| @@ -28,6 +29,7 @@ public class ClientHeartBeatHandlerImpl implements HeartBeatHandler { | @@ -28,6 +29,7 @@ public class ClientHeartBeatHandlerImpl implements HeartBeatHandler { | ||
| 28 | public void process(ChannelHandlerContext ctx) throws Exception { | 29 | public void process(ChannelHandlerContext ctx) throws Exception { |
| 29 | 30 | ||
| 30 | //重连 | 31 | //重连 |
| 32 | + ContextHolder.setReconnect(true); | ||
| 31 | cimClient.reconnect(); | 33 | cimClient.reconnect(); |
| 32 | 34 | ||
| 33 | } | 35 | } |
| @@ -5,12 +5,14 @@ import com.alibaba.fastjson.JSONObject; | @@ -5,12 +5,14 @@ import com.alibaba.fastjson.JSONObject; | ||
| 5 | import com.crossoverjie.cim.client.config.AppConfiguration; | 5 | import com.crossoverjie.cim.client.config.AppConfiguration; |
| 6 | import com.crossoverjie.cim.client.service.EchoService; | 6 | import com.crossoverjie.cim.client.service.EchoService; |
| 7 | import com.crossoverjie.cim.client.service.RouteRequest; | 7 | import com.crossoverjie.cim.client.service.RouteRequest; |
| 8 | +import com.crossoverjie.cim.client.thread.ContextHolder; | ||
| 8 | import com.crossoverjie.cim.client.vo.req.GroupReqVO; | 9 | import com.crossoverjie.cim.client.vo.req.GroupReqVO; |
| 9 | import com.crossoverjie.cim.client.vo.req.LoginReqVO; | 10 | import com.crossoverjie.cim.client.vo.req.LoginReqVO; |
| 10 | import com.crossoverjie.cim.client.vo.req.P2PReqVO; | 11 | import com.crossoverjie.cim.client.vo.req.P2PReqVO; |
| 11 | import com.crossoverjie.cim.client.vo.res.CIMServerResVO; | 12 | import com.crossoverjie.cim.client.vo.res.CIMServerResVO; |
| 12 | import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO; | 13 | import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO; |
| 13 | import com.crossoverjie.cim.common.enums.StatusEnum; | 14 | import com.crossoverjie.cim.common.enums.StatusEnum; |
| 15 | +import com.crossoverjie.cim.common.exception.CIMException; | ||
| 14 | import com.crossoverjie.cim.common.res.BaseResponse; | 16 | import com.crossoverjie.cim.common.res.BaseResponse; |
| 15 | import okhttp3.*; | 17 | import okhttp3.*; |
| 16 | import org.slf4j.Logger; | 18 | import org.slf4j.Logger; |
| @@ -140,6 +142,13 @@ public class RouteRequestImpl implements RouteRequest { | @@ -140,6 +142,13 @@ public class RouteRequestImpl implements RouteRequest { | ||
| 140 | //重复失败 | 142 | //重复失败 |
| 141 | if (!cimServerResVO.getCode().equals(StatusEnum.SUCCESS.getCode())){ | 143 | if (!cimServerResVO.getCode().equals(StatusEnum.SUCCESS.getCode())){ |
| 142 | echoService.echo(cimServerResVO.getMessage()); | 144 | echoService.echo(cimServerResVO.getMessage()); |
| 145 | + | ||
| 146 | + // when client in reconnect state, could not exit. | ||
| 147 | + if (ContextHolder.getReconnect()){ | ||
| 148 | + echoService.echo("###{}###", StatusEnum.RECONNECT_FAIL.getMessage()); | ||
| 149 | + throw new CIMException(StatusEnum.RECONNECT_FAIL); | ||
| 150 | + } | ||
| 151 | + | ||
| 143 | System.exit(-1); | 152 | System.exit(-1); |
| 144 | } | 153 | } |
| 145 | 154 |
| 1 | +package com.crossoverjie.cim.client.thread; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * Function: Something about of client runtime sign. | ||
| 5 | + * | ||
| 6 | + * @author crossoverJie | ||
| 7 | + * Date: 2020-04-13 02:10 | ||
| 8 | + * @since JDK 1.8 | ||
| 9 | + */ | ||
| 10 | +public class ContextHolder { | ||
| 11 | + private static final ThreadLocal<Boolean> IS_RECONNECT = new ThreadLocal<>() ; | ||
| 12 | + | ||
| 13 | + public static void setReconnect(boolean reconnect){ | ||
| 14 | + IS_RECONNECT.set(reconnect); | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + public static Boolean getReconnect(){ | ||
| 18 | + return IS_RECONNECT.get() ; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public static void clear(){ | ||
| 22 | + IS_RECONNECT.remove(); | ||
| 23 | + } | ||
| 24 | +} |
| @@ -27,7 +27,9 @@ public enum StatusEnum { | @@ -27,7 +27,9 @@ public enum StatusEnum { | ||
| 27 | /** 账号不在线 */ | 27 | /** 账号不在线 */ |
| 28 | OFF_LINE("7000", "你选择的账号不在线,请重新选择!"), | 28 | OFF_LINE("7000", "你选择的账号不在线,请重新选择!"), |
| 29 | 29 | ||
| 30 | - SERVER_NOT_AVAILABLE("7100", "CIM server is not available, please try again later!"), | 30 | + SERVER_NOT_AVAILABLE("7100", "cim server is not available, please try again later!"), |
| 31 | + | ||
| 32 | + RECONNECT_FAIL("7200", "reconnect fail, continue to retry!"), | ||
| 31 | 33 | ||
| 32 | /** 登录信息不匹配 */ | 34 | /** 登录信息不匹配 */ |
| 33 | ACCOUNT_NOT_MATCH("9100", "The User information you have used is incorrect!"), | 35 | ACCOUNT_NOT_MATCH("9100", "The User information you have used is incorrect!"), |
| @@ -2,6 +2,8 @@ package com.crossoverjie.cim.route.cache; | @@ -2,6 +2,8 @@ package com.crossoverjie.cim.route.cache; | ||
| 2 | 2 | ||
| 3 | import com.crossoverjie.cim.route.kit.ZKit; | 3 | import com.crossoverjie.cim.route.kit.ZKit; |
| 4 | import com.google.common.cache.LoadingCache; | 4 | import com.google.common.cache.LoadingCache; |
| 5 | +import org.slf4j.Logger; | ||
| 6 | +import org.slf4j.LoggerFactory; | ||
| 5 | import org.springframework.beans.factory.annotation.Autowired; | 7 | import org.springframework.beans.factory.annotation.Autowired; |
| 6 | import org.springframework.stereotype.Component; | 8 | import org.springframework.stereotype.Component; |
| 7 | 9 | ||
| @@ -20,6 +22,7 @@ import java.util.concurrent.atomic.AtomicLong; | @@ -20,6 +22,7 @@ import java.util.concurrent.atomic.AtomicLong; | ||
| 20 | @Component | 22 | @Component |
| 21 | public class ServerCache { | 23 | public class ServerCache { |
| 22 | 24 | ||
| 25 | + private static Logger logger = LoggerFactory.getLogger(ServerCache.class) ; | ||
| 23 | 26 | ||
| 24 | @Autowired | 27 | @Autowired |
| 25 | private LoadingCache<String, String> cache; | 28 | private LoadingCache<String, String> cache; |
| @@ -43,7 +46,13 @@ public class ServerCache { | @@ -43,7 +46,13 @@ public class ServerCache { | ||
| 43 | public void updateCache(List<String> currentChilds) { | 46 | public void updateCache(List<String> currentChilds) { |
| 44 | cache.invalidateAll(); | 47 | cache.invalidateAll(); |
| 45 | for (String currentChild : currentChilds) { | 48 | for (String currentChild : currentChilds) { |
| 46 | - String key = currentChild.split("-")[1]; | 49 | + // currentChild=ip-127.0.0.1:11212:9082 or 127.0.0.1:11212:9082 |
| 50 | + String key ; | ||
| 51 | + if (currentChild.split("-").length == 2){ | ||
| 52 | + key = currentChild.split("-")[1]; | ||
| 53 | + }else { | ||
| 54 | + key = currentChild ; | ||
| 55 | + } | ||
| 47 | addCache(key); | 56 | addCache(key); |
| 48 | } | 57 | } |
| 49 | } | 58 | } |
| @@ -54,7 +63,7 @@ public class ServerCache { | @@ -54,7 +63,7 @@ public class ServerCache { | ||
| 54 | * | 63 | * |
| 55 | * @return | 64 | * @return |
| 56 | */ | 65 | */ |
| 57 | - public List<String> getAll() { | 66 | + public List<String> getServerList() { |
| 58 | 67 | ||
| 59 | List<String> list = new ArrayList<>(); | 68 | List<String> list = new ArrayList<>(); |
| 60 | 69 | ||
| @@ -72,4 +81,11 @@ public class ServerCache { | @@ -72,4 +81,11 @@ public class ServerCache { | ||
| 72 | 81 | ||
| 73 | } | 82 | } |
| 74 | 83 | ||
| 84 | + /** | ||
| 85 | + * rebuild cache list | ||
| 86 | + */ | ||
| 87 | + public void rebuildCacheList(){ | ||
| 88 | + updateCache(getServerList()) ; | ||
| 89 | + } | ||
| 90 | + | ||
| 75 | } | 91 | } |
| @@ -153,7 +153,7 @@ public class RouteController { | @@ -153,7 +153,7 @@ public class RouteController { | ||
| 153 | BaseResponse<CIMServerResVO> res = new BaseResponse(); | 153 | BaseResponse<CIMServerResVO> res = new BaseResponse(); |
| 154 | 154 | ||
| 155 | // check server available | 155 | // check server available |
| 156 | - String server = routeHandle.routeServer(serverCache.getAll(),String.valueOf(loginReqVO.getUserId())); | 156 | + String server = routeHandle.routeServer(serverCache.getServerList(),String.valueOf(loginReqVO.getUserId())); |
| 157 | RouteInfo routeInfo = RouteInfoParseUtil.parse(server); | 157 | RouteInfo routeInfo = RouteInfoParseUtil.parse(server); |
| 158 | commonBizService.checkServerAvailable(routeInfo); | 158 | commonBizService.checkServerAvailable(routeInfo); |
| 159 | 159 |
| @@ -3,7 +3,11 @@ package com.crossoverjie.cim.route.service; | @@ -3,7 +3,11 @@ package com.crossoverjie.cim.route.service; | ||
| 3 | import com.crossoverjie.cim.common.enums.StatusEnum; | 3 | import com.crossoverjie.cim.common.enums.StatusEnum; |
| 4 | import com.crossoverjie.cim.common.exception.CIMException; | 4 | import com.crossoverjie.cim.common.exception.CIMException; |
| 5 | import com.crossoverjie.cim.common.pojo.RouteInfo; | 5 | import com.crossoverjie.cim.common.pojo.RouteInfo; |
| 6 | +import com.crossoverjie.cim.route.cache.ServerCache; | ||
| 6 | import com.crossoverjie.cim.route.kit.NetAddressIsReachable; | 7 | import com.crossoverjie.cim.route.kit.NetAddressIsReachable; |
| 8 | +import org.slf4j.Logger; | ||
| 9 | +import org.slf4j.LoggerFactory; | ||
| 10 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 7 | import org.springframework.stereotype.Component; | 11 | import org.springframework.stereotype.Component; |
| 8 | 12 | ||
| 9 | /** | 13 | /** |
| @@ -15,6 +19,11 @@ import org.springframework.stereotype.Component; | @@ -15,6 +19,11 @@ import org.springframework.stereotype.Component; | ||
| 15 | */ | 19 | */ |
| 16 | @Component | 20 | @Component |
| 17 | public class CommonBizService { | 21 | public class CommonBizService { |
| 22 | + private static Logger logger = LoggerFactory.getLogger(CommonBizService.class) ; | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + @Autowired | ||
| 26 | + private ServerCache serverCache ; | ||
| 18 | 27 | ||
| 19 | /** | 28 | /** |
| 20 | * check ip and port | 29 | * check ip and port |
| @@ -23,6 +32,11 @@ public class CommonBizService { | @@ -23,6 +32,11 @@ public class CommonBizService { | ||
| 23 | public void checkServerAvailable(RouteInfo routeInfo){ | 32 | public void checkServerAvailable(RouteInfo routeInfo){ |
| 24 | boolean reachable = NetAddressIsReachable.checkAddressReachable(routeInfo.getIp(), routeInfo.getCimServerPort(), 1000); | 33 | boolean reachable = NetAddressIsReachable.checkAddressReachable(routeInfo.getIp(), routeInfo.getCimServerPort(), 1000); |
| 25 | if (!reachable) { | 34 | if (!reachable) { |
| 35 | + logger.error("ip={}, port={} are not available", routeInfo.getIp(), routeInfo.getCimServerPort()); | ||
| 36 | + | ||
| 37 | + // rebuild cache | ||
| 38 | + serverCache.rebuildCacheList(); | ||
| 39 | + | ||
| 26 | throw new CIMException(StatusEnum.SERVER_NOT_AVAILABLE) ; | 40 | throw new CIMException(StatusEnum.SERVER_NOT_AVAILABLE) ; |
| 27 | } | 41 | } |
| 28 | 42 |
| @@ -22,19 +22,19 @@ app.zk.connect.timeout=15000 | @@ -22,19 +22,19 @@ app.zk.connect.timeout=15000 | ||
| 22 | app.zk.root=/route | 22 | app.zk.root=/route |
| 23 | 23 | ||
| 24 | #路由策略,轮询 | 24 | #路由策略,轮询 |
| 25 | -#app.route.way=com.crossoverjie.cim.common.route.algorithm.loop.LoopHandle | 25 | +app.route.way=com.crossoverjie.cim.common.route.algorithm.loop.LoopHandle |
| 26 | 26 | ||
| 27 | #路由策略,随机 | 27 | #路由策略,随机 |
| 28 | #app.route.way=com.crossoverjie.cim.common.route.algorithm.random.RandomHandle | 28 | #app.route.way=com.crossoverjie.cim.common.route.algorithm.random.RandomHandle |
| 29 | 29 | ||
| 30 | #路由策略,一致性 hash | 30 | #路由策略,一致性 hash |
| 31 | -app.route.way=com.crossoverjie.cim.common.route.algorithm.consistenthash.ConsistentHashHandle | 31 | +#app.route.way=com.crossoverjie.cim.common.route.algorithm.consistenthash.ConsistentHashHandle |
| 32 | 32 | ||
| 33 | #一致性 hash 算法具体实现--自定义有序 map | 33 | #一致性 hash 算法具体实现--自定义有序 map |
| 34 | #app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.SortArrayMapConsistentHash | 34 | #app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.SortArrayMapConsistentHash |
| 35 | 35 | ||
| 36 | #一致性 hash 算法具体实现--TreeMap | 36 | #一致性 hash 算法具体实现--TreeMap |
| 37 | -app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.TreeMapConsistentHash | 37 | +#app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.TreeMapConsistentHash |
| 38 | 38 | ||
| 39 | # Redis 配置 | 39 | # Redis 配置 |
| 40 | spring.redis.host=xx | 40 | spring.redis.host=xx |
-
请 注册 或 登录 后发表评论