attachments = invocation.getAttachments();
29 | RpcContext.getContext()
30 | .setAttachments(attachments)
31 | .setRemoteAddress(invocation.getUrl().getAddress(), invocation.getUrl().getPort())
32 | .setLocalAddress(invoker.getUrl().getHost(),
33 | invoker.getUrl().getPort());
34 | invocation.setInvoker(invoker);
35 | try {
36 | return invoker.invoke(invocation);
37 | } finally {
38 | RpcContext.removeContext();
39 | logger.debug("ContextFilter end");
40 | }
41 | }
42 |
43 |
44 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/EchoFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 |
4 | import com.colobu.rpcx.config.Constants;
5 | import com.colobu.rpcx.filter.Filter;
6 | import com.colobu.rpcx.rpc.Invoker;
7 | import com.colobu.rpcx.rpc.Result;
8 | import com.colobu.rpcx.rpc.RpcException;
9 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
10 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
11 | import com.colobu.rpcx.rpc.impl.RpcResult;
12 |
13 | /**
14 | * @author goodjava@qq.com
15 | */
16 | @RpcFilter(order = -2001, group = {Constants.PROVIDER})
17 | public class EchoFilter implements Filter {
18 |
19 | @Override
20 | public Result invoke(Invoker> invoker, RpcInvocation inv) throws RpcException {
21 | if (inv.getMethodName().equals(Constants.$ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) {
22 | return new RpcResult(inv.getArguments()[0]);
23 | }
24 | return invoker.invoke(inv);
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/ExceptionFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 |
4 | import com.colobu.rpcx.config.Constants;
5 | import com.colobu.rpcx.filter.Filter;
6 | import com.colobu.rpcx.rpc.*;
7 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
8 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
9 | import com.colobu.rpcx.rpc.impl.RpcResult;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 |
14 | /**
15 | * @author goodjava@qq.com
16 | */
17 | @RpcFilter(group = {Constants.PROVIDER}, order = -1999)
18 | public class ExceptionFilter implements Filter {
19 |
20 | private static final Logger logger = LoggerFactory.getLogger(ExceptionFilter.class);
21 |
22 | @Override
23 | public Result invoke(Invoker> invoker, RpcInvocation invocation) throws RpcException {
24 | try {
25 | Result result = invoker.invoke(invocation);
26 | return result;
27 | } catch (RpcException ex) {
28 | Result result = new RpcResult();
29 | result.setThrowable(ex);
30 | return result;
31 | } catch (Throwable throwable) {
32 | Result result = new RpcResult();
33 | result.setThrowable(throwable);
34 | return result;
35 | }
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/FailFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 | import com.colobu.rpcx.common.retry.RetryNTimes;
4 | import com.colobu.rpcx.config.Constants;
5 | import com.colobu.rpcx.fail.FailType;
6 | import com.colobu.rpcx.filter.Filter;
7 | import com.colobu.rpcx.rpc.Invoker;
8 | import com.colobu.rpcx.rpc.Result;
9 | import com.colobu.rpcx.rpc.RpcException;
10 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
11 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
12 | import com.colobu.rpcx.selector.SelectMode;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 |
16 | /**
17 | * @author goodjava@qq.com
18 | *
19 | * 负责管理失败的重试
20 | */
21 | @RpcFilter(group = {Constants.CONSUMER}, order = -1000)
22 | public class FailFilter implements Filter {
23 |
24 |
25 | private static final Logger logger = LoggerFactory.getLogger(FailFilter.class);
26 |
27 | @Override
28 | public Result invoke(Invoker> invoker, RpcInvocation invocation) throws RpcException {
29 | FailType failType = invocation.getFailType();
30 | RetryNTimes retry = new RetryNTimes(invocation.getRetryNum());
31 | Result result = retry.retry((n) -> {
32 | Result res = invoker.invoke(invocation);
33 | if (res.hasException()) {
34 | logger.warn("{} invoke error:{}", invocation.getUrl().getPath(), res.getException().getMessage());
35 | //失败了立刻返回
36 | if (failType.equals(FailType.FailFast)) {
37 | logger.info("------>failFast");
38 | res.getAttachments().put("needRetry", "false");
39 | return res;
40 | }
41 | //换个服务节点重试
42 | if (failType.equals(FailType.FailOver)) {
43 | logger.info("------>failOver");
44 | res.getAttachments().put("needRetry", "true");
45 | return res;
46 | }
47 | //当前节点重试
48 | if (failType.equals(FailType.FailTry)) {
49 | logger.info("------>failTry");
50 | res.getAttachments().put("needRetry", "true");
51 | //这样走到下游的SelectFilter就不会再选出来一个新的Service了
52 | invocation.setSelectMode(SelectMode.SelectByUser);
53 | return res;
54 | }
55 | }
56 | res.getAttachments().put("needRetry", "false");
57 | return res;
58 | });
59 |
60 | return result;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/GenericFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 |
4 | import com.colobu.rpcx.common.ClassUtils;
5 | import com.colobu.rpcx.config.Constants;
6 | import com.colobu.rpcx.filter.Filter;
7 | import com.colobu.rpcx.rpc.Invoker;
8 | import com.colobu.rpcx.rpc.ReflectUtils;
9 | import com.colobu.rpcx.rpc.Result;
10 | import com.colobu.rpcx.rpc.RpcException;
11 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
12 | import com.colobu.rpcx.rpc.impl.Exporter;
13 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
14 | import com.google.gson.Gson;
15 |
16 | import java.lang.reflect.Method;
17 | import java.util.stream.IntStream;
18 |
19 |
20 | /**
21 | * @author goodjava@qq.com
22 | * 泛化调用
23 | */
24 | @RpcFilter(group = {Constants.PROVIDER}, order = -2001)
25 | public class GenericFilter implements Filter {
26 |
27 | @Override
28 | public Result invoke(Invoker> invoker, RpcInvocation inv) throws RpcException {
29 | if (inv.getMethodName().equals(Constants.$INVOKE)) {
30 | String[] types = inv.getParameterTypeNames();
31 | final String[] args = (String[]) inv.getArguments();
32 |
33 | Gson gson = new Gson();
34 | int len = types.length;
35 |
36 | Class[] classTypes = new Class[types.length];
37 |
38 | Object[] params = IntStream.range(0, len).mapToObj(i -> {
39 | String type = types[i];
40 | Class> clazz = ReflectUtils.forName(type);
41 | classTypes[i] = clazz;
42 | int j = i + 1;
43 | String arg = args[j];
44 | Object obj = gson.fromJson(arg, clazz);
45 | return obj;
46 | }).toArray(Object[]::new);
47 |
48 | //从新组装Invocation
49 | inv.setMethodName(args[0]);
50 | inv.setParameterTypes(classTypes);
51 | inv.setArguments(params);
52 |
53 |
54 | Method method = ClassUtils.getMethod(inv.getClassName(), inv.getMethodName(), inv.getParameterTypeNames());
55 | invoker.setMethod(method);
56 |
57 | Result res = invoker.invoke(inv);
58 |
59 | if (!res.hasException()) {
60 | Object value = res.getValue();
61 | res.setValue(gson.toJson(value));
62 | return res;
63 | }
64 |
65 | }
66 |
67 | return invoker.invoke(inv);
68 | }
69 |
70 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/HotDeployFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 |
4 | import com.colobu.rpcx.common.Config;
5 | import com.colobu.rpcx.common.StringUtils;
6 | import com.colobu.rpcx.config.Constants;
7 | import com.colobu.rpcx.deploy.AgentLoader;
8 | import com.colobu.rpcx.filter.Filter;
9 | import com.colobu.rpcx.rpc.Invoker;
10 | import com.colobu.rpcx.rpc.Result;
11 | import com.colobu.rpcx.rpc.RpcException;
12 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
13 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
14 | import com.colobu.rpcx.rpc.impl.RpcResult;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 |
18 | import java.io.IOException;
19 | import java.lang.management.ManagementFactory;
20 | import java.lang.management.RuntimeMXBean;
21 | import java.nio.file.Files;
22 | import java.nio.file.Paths;
23 | import java.util.UUID;
24 |
25 | /**
26 | * @author goodjava@qq.com
27 | * 支持热更新
28 | */
29 | @RpcFilter(order = -2002, group = {Constants.PROVIDER})
30 | public class HotDeployFilter implements Filter {
31 |
32 | private static final Logger logger = LoggerFactory.getLogger(HotDeployFilter.class);
33 |
34 | @Override
35 | public Result invoke(Invoker> invoker, RpcInvocation inv) throws RpcException {
36 | if (inv.getMethodName().equals(Constants.$HOT_DEPLOY) && inv.getArguments().length == 3) {
37 | logger.info("hot deploy begin");
38 | Object[] arguments = inv.getArguments();
39 |
40 | String className = arguments[0].toString();
41 | String token = arguments[1].toString();
42 |
43 | String configToken = Config.ins().get("rpcx.deploy.tokey");
44 | if (StringUtils.isEmpty(configToken) || !token.equals(configToken)) {
45 | throw new RpcException("token error");
46 | }
47 |
48 | byte[] classData = (byte[]) arguments[2];
49 | String uuid = UUID.randomUUID().toString();
50 | String file = "/tmp/" + uuid;
51 | String pid = getPid();
52 | logger.info("className:{} file:{} pid:{} data len:{}", className, file, pid, classData.length);
53 | try {
54 | Files.write(Paths.get(file), classData);
55 | } catch (IOException e) {
56 | e.printStackTrace();
57 | }
58 | new AgentLoader().loadAgent(pid, Config.ins().get("rpcx_agent_path"), file + "__" + className);
59 |
60 | try {
61 | Files.delete(Paths.get(file));
62 | } catch (IOException e) {
63 | e.printStackTrace();
64 | }
65 | return new RpcResult("Finish");
66 | }
67 |
68 | return invoker.invoke(inv);
69 | }
70 |
71 |
72 | public String getPid() {
73 | RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
74 | // format: "pid@hostname"
75 | String name = runtime.getName();
76 | return name.substring(0, name.indexOf('@'));
77 | }
78 |
79 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/SelectorFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 | import com.colobu.rpcx.config.Constants;
4 | import com.colobu.rpcx.filter.Filter;
5 | import com.colobu.rpcx.rpc.*;
6 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
7 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
8 | import com.colobu.rpcx.selector.SelectMode;
9 | import com.colobu.rpcx.selector.Weighted;
10 | import com.colobu.rpcx.selector.WeightedRountRobin;
11 |
12 | import java.security.SecureRandom;
13 | import java.util.List;
14 | import java.util.concurrent.ConcurrentHashMap;
15 | import java.util.stream.Collectors;
16 |
17 |
18 | /**
19 | * @author goodjava@qq.com
20 | */
21 | @RpcFilter(group = {Constants.CONSUMER})
22 | public class SelectorFilter implements Filter {
23 |
24 | private static SecureRandom secureRandom = new SecureRandom();
25 |
26 | private static ConcurrentHashMap selectIndexMap = new ConcurrentHashMap<>();
27 |
28 | /**
29 | * 基于权重
30 | */
31 | private static ConcurrentHashMap weightRoundRobinMap = new ConcurrentHashMap<>();
32 |
33 | @Override
34 | public Result invoke(Invoker> invoker, RpcInvocation invocation) throws RpcException {
35 | //目前使用类名当服务名称
36 | String serviceName = invocation.getClassName();
37 |
38 | //获取服务列表(ip:port?param)
39 | List serviceList = invoker.serviceDiscovery().getServices(serviceName);
40 |
41 | serviceList = serviceList.stream().filter(it->{
42 | URL url = URL.valueOf(it);
43 | if (!it.contains("state=inactive") && invocation.getGroup().equals(url.getParameter(Constants.GROUP_KEY,""))) {
44 | return true;
45 | }
46 | return false;
47 | }).collect(Collectors.toList());
48 |
49 |
50 | if (serviceList.size() <= 0) {
51 | throw new RpcException("service list size <=0 ", "-3");
52 | }
53 |
54 | SelectMode selectMode = invocation.getSelectMode();
55 | switch (selectMode) {
56 | case RandomSelect: {
57 | String service = randomSelect(serviceList);
58 | RpcContext.getContext().setServiceAddr(service);
59 | break;
60 | }
61 | case RoundRobin: {
62 | String service = roundRobin(serviceList, serviceName);
63 | RpcContext.getContext().setServiceAddr(service);
64 | break;
65 | }
66 | case WeightedRoundRobin: {
67 | String service = weightedRountRobin(serviceList, serviceName);
68 | RpcContext.getContext().setServiceAddr(service);
69 | break;
70 | }
71 | case SelectByUser: {
72 | break;
73 | }
74 | }
75 |
76 |
77 | return invoker.invoke(invocation);
78 | }
79 |
80 |
81 | private String roundRobin(List serviceList, String serviceName) {
82 | Integer index = selectIndexMap.get(serviceName);
83 | if (null == index) {
84 | selectIndexMap.putIfAbsent(serviceName, 0);
85 | index = selectIndexMap.get(serviceName);
86 | }
87 |
88 | int i = index % serviceList.size();
89 | String serviceAddr = serviceList.get(i);
90 | selectIndexMap.compute(serviceName, (k, v) -> {
91 | v = v + 1;
92 | return v;
93 | });
94 | return URL.valueOf(serviceAddr).getAddress();
95 | }
96 |
97 |
98 | private String weightedRountRobin(List serviceList, String serviceName) {
99 | WeightedRountRobin weightedRountRobin = weightRoundRobinMap.get(serviceName);
100 | if (null == weightedRountRobin) {
101 | weightRoundRobinMap.putIfAbsent(serviceName, new WeightedRountRobin(serviceList));
102 | weightedRountRobin = weightRoundRobinMap.get(serviceName);
103 | }
104 | //需要更新权重列表,有可能服务器上下线
105 | weightedRountRobin.updateWeighteds(serviceList);
106 |
107 | Weighted wei = weightedRountRobin.nextWeighted();
108 | if (null == wei) {
109 | return null;
110 | }
111 | return URL.valueOf(wei.getServer()).getAddress();
112 | }
113 |
114 |
115 | private String randomSelect(List serviceList) {
116 | int index = secureRandom.nextInt(serviceList.size());
117 | return URL.valueOf(serviceList.get(index)).getAddress();
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/TimeoutFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 |
4 | import com.colobu.rpcx.config.Constants;
5 | import com.colobu.rpcx.filter.Filter;
6 | import com.colobu.rpcx.rpc.Invoker;
7 | import com.colobu.rpcx.rpc.Result;
8 | import com.colobu.rpcx.rpc.RpcException;
9 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
10 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import java.util.Arrays;
15 |
16 |
17 | /**
18 | * @author goodjava@qq.com
19 | */
20 | @RpcFilter(order = -1000, group = {Constants.PROVIDER})
21 | public class TimeoutFilter implements Filter {
22 |
23 | private static final Logger logger = LoggerFactory.getLogger(TimeoutFilter.class);
24 |
25 | @Override
26 | public Result invoke(Invoker> invoker, RpcInvocation invocation) throws RpcException {
27 | if (!("-1".equals(invoker.getUrl().getParameter(Constants.TIMEOUT_KEY)))) {
28 | long start = System.currentTimeMillis();
29 | Result result = invoker.invoke(invocation);
30 | long elapsed = System.currentTimeMillis() - start;
31 |
32 | int v = invoker.getUrl().getParameter(Constants.TIMEOUT_KEY, Integer.MAX_VALUE);
33 | if (invoker.getUrl() != null && v != 0 && elapsed > v) {
34 | logger.warn("invoke time out. method: " + invocation.getMethodName()
35 | + " arguments: " + Arrays.toString(invocation.getArguments()) + " , url is "
36 | + invoker.getUrl() + ", invoke elapsed " + elapsed + " ms.");
37 | }
38 | return result;
39 | }
40 |
41 | return invoker.invoke(invocation);
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/TokenFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 |
4 | import com.colobu.rpcx.common.StringUtils;
5 | import com.colobu.rpcx.config.Constants;
6 | import com.colobu.rpcx.filter.Filter;
7 | import com.colobu.rpcx.rpc.Invoker;
8 | import com.colobu.rpcx.rpc.Result;
9 | import com.colobu.rpcx.rpc.RpcContext;
10 | import com.colobu.rpcx.rpc.RpcException;
11 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
12 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
13 |
14 | import java.util.Map;
15 |
16 | /**
17 | * Created by goodjava@qq.com.
18 | */
19 | @RpcFilter(order = -999, group = {Constants.PROVIDER})
20 | public class TokenFilter implements Filter {
21 |
22 | @Override
23 | public Result invoke(Invoker> invoker, RpcInvocation inv)
24 | throws RpcException {
25 | String token = invoker.getUrl().getParameter(Constants.TOKEN_KEY,"");
26 | if (!StringUtils.isEmpty(token)) {
27 | Class> serviceType = invoker.getInterface();
28 | Map attachments = inv.getAttachments();
29 | String remoteToken = attachments == null ? null : attachments.get(Constants.TOKEN_KEY);
30 | if (!token.equals(remoteToken)) {
31 | throw new RpcException("Invalid token! Forbid invoke remote service " + serviceType + " method " + inv.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost());
32 | }
33 | }
34 | return invoker.invoke(inv);
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/TpsLimitFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 |
4 | import com.colobu.rpcx.config.Constants;
5 | import com.colobu.rpcx.filter.Filter;
6 | import com.colobu.rpcx.rpc.Invoker;
7 | import com.colobu.rpcx.rpc.Result;
8 | import com.colobu.rpcx.rpc.RpcException;
9 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
10 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
11 | import com.colobu.rpcx.tps.DefaultTPSLimiter;
12 | import com.colobu.rpcx.tps.TPSLimiter;
13 |
14 | /**
15 | * Created by goodjava@qq.com.
16 | */
17 | @RpcFilter(group = {Constants.PROVIDER})
18 | public class TpsLimitFilter implements Filter {
19 |
20 | private static final TPSLimiter tpsLimiter = new DefaultTPSLimiter();
21 |
22 | @Override
23 | public Result invoke(Invoker> invoker, RpcInvocation invocation) throws RpcException {
24 | if (invocation.getUrl().getParameter(Constants.TPS_LIMIT_RATE_KEY,"-1").equals("-1")) {
25 | return invoker.invoke(invocation);
26 | }
27 |
28 | if (!tpsLimiter.isAllowable(invoker.getUrl(), invocation)) {
29 | throw new RpcException(
30 | new StringBuilder(64)
31 | .append("Failed to invoke service ")
32 | .append(invoker.getInterface().getName())
33 | .append(".")
34 | .append(invocation.getMethodName())
35 | .append(" because exceed max service tps.")
36 | .toString());
37 | }
38 |
39 | return invoker.invoke(invocation);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/filter/impl/TraceidFilter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.filter.impl;
2 |
3 | import com.colobu.rpcx.common.ClassUtils;
4 | import com.colobu.rpcx.common.StringUtils;
5 | import com.colobu.rpcx.config.Constants;
6 | import com.colobu.rpcx.filter.Filter;
7 | import com.colobu.rpcx.rpc.Invoker;
8 | import com.colobu.rpcx.rpc.Result;
9 | import com.colobu.rpcx.rpc.RpcContext;
10 | import com.colobu.rpcx.rpc.RpcException;
11 | import com.colobu.rpcx.rpc.annotation.RpcFilter;
12 | import com.colobu.rpcx.rpc.impl.RpcInvocation;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 |
16 | import java.util.UUID;
17 |
18 | /**
19 | * @author goodjava@qq.com
20 | */
21 | @RpcFilter(order = -999, group = {Constants.PROVIDER})
22 | public class TraceidFilter implements Filter {
23 |
24 | private static final Logger logger = LoggerFactory.getLogger(TraceidFilter.class);
25 |
26 | @Override
27 | public Result invoke(Invoker> invoker, RpcInvocation invocation) throws RpcException {
28 | String clientTraceId = invocation.getAttachment(Constants.TRACE_ID);
29 | String key = ClassUtils.getMethodKey(invocation.getClassName(), invocation.getMethodName(), invocation.getParameterTypeNames());
30 | String traceId = "";
31 | String spanId = invocation.getAttachment(Constants.SPAN_ID, "");
32 | if (StringUtils.isNotEmpty(clientTraceId)) {
33 | traceId = clientTraceId;
34 | spanId = spanId + "," + UUID.randomUUID().toString();
35 | } else {
36 | //new
37 | traceId = UUID.randomUUID().toString();
38 | spanId = traceId;
39 | }
40 | logger.info("invoke begin:{} traceId:{} spanId:{}", key, traceId, spanId);
41 | RpcContext.getContext().getAttachments().put(Constants.TRACE_ID, traceId);
42 | RpcContext.getContext().getAttachments().put(Constants.SPAN_ID, spanId);
43 | try {
44 | Result res = invoker.invoke(invocation);
45 | logger.info("invoke end:{} success traceId:{} spanId:{}", key, traceId, spanId);
46 | return res;
47 | } catch (Throwable ex) {
48 | logger.info("invoke end:{} failure traceId:{} spanId:{}", key, traceId, spanId);
49 | throw ex;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/io/UnsafeStringWriter.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.io;
2 |
3 | import java.io.IOException;
4 | import java.io.Writer;
5 |
6 |
7 | /**
8 | * Created by goodjava@qq.com.
9 | */
10 | public class UnsafeStringWriter extends Writer
11 | {
12 | private StringBuilder mBuffer;
13 |
14 | public UnsafeStringWriter()
15 | {
16 | lock = mBuffer = new StringBuilder();
17 | }
18 |
19 | public UnsafeStringWriter(int size)
20 | {
21 | if( size < 0 ) {
22 | throw new IllegalArgumentException("Negative buffer size");
23 | }
24 |
25 | lock = mBuffer = new StringBuilder();
26 | }
27 |
28 | @Override
29 | public void write(int c)
30 | {
31 | mBuffer.append((char)c);
32 | }
33 |
34 | @Override
35 | public void write(char[] cs) throws IOException
36 | {
37 | mBuffer.append(cs, 0, cs.length);
38 | }
39 |
40 | @Override
41 | public void write(char[] cs, int off, int len) throws IOException
42 | {
43 | if( (off < 0) || (off > cs.length) || (len < 0) ||
44 | ((off + len) > cs.length) || ((off + len) < 0) ) {
45 | throw new IndexOutOfBoundsException();
46 | }
47 |
48 | if( len > 0 ) {
49 | mBuffer.append(cs, off, len);
50 | }
51 | }
52 |
53 | @Override
54 | public void write(String str)
55 | {
56 | mBuffer.append(str);
57 | }
58 |
59 | @Override
60 | public void write(String str, int off, int len)
61 | {
62 | mBuffer.append(str.substring(off, off + len));
63 | }
64 |
65 | @Override
66 | public Writer append(CharSequence csq)
67 | {
68 | if (csq == null) {
69 | write("null");
70 | } else {
71 | write(csq.toString());
72 | }
73 | return this;
74 | }
75 |
76 | @Override
77 | public Writer append(CharSequence csq, int start, int end)
78 | {
79 | CharSequence cs = (csq == null ? "null" : csq);
80 | write(cs.subSequence(start, end).toString());
81 | return this;
82 | }
83 |
84 | @Override
85 | public Writer append(char c)
86 | {
87 | mBuffer.append(c);
88 | return this;
89 | }
90 |
91 | @Override
92 | public void close(){}
93 |
94 | @Override
95 | public void flush(){}
96 |
97 | @Override
98 | public String toString()
99 | {
100 | return mBuffer.toString();
101 | }
102 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/monitor/Monitor.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.monitor;
2 |
3 | import com.colobu.rpcx.rpc.Node;
4 |
5 | /**
6 | * Created by goodjava@qq.com.
7 | */
8 | public interface Monitor extends Node, MonitorService {
9 |
10 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/monitor/MonitorFactory.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.monitor;
2 |
3 | import com.colobu.rpcx.monitor.impl.RpcxMonitor;
4 | import com.colobu.rpcx.rpc.URL;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import java.util.List;
8 |
9 | /**
10 | * @author goodjava@qq.com
11 | */
12 | public class MonitorFactory {
13 |
14 | private static final Logger logger = LoggerFactory.getLogger(MonitorFactory.class);
15 |
16 | /**
17 | * Create monitor.
18 | */
19 | public Monitor getMonitor(URL url) {
20 | return new RpcxMonitor(new MonitorService() {
21 | @Override
22 | public void collect(URL statistics) {
23 | logger.info(statistics.toFullString());
24 | }
25 |
26 | @Override
27 | public List lookup(URL query) {
28 | return null;
29 | }
30 | });
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/monitor/MonitorService.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.monitor;
2 |
3 |
4 | import com.colobu.rpcx.config.Constants;
5 | import com.colobu.rpcx.rpc.URL;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Created by goodjava@qq.com.
11 | */
12 | public interface MonitorService {
13 |
14 | String APPLICATION = "application";
15 |
16 | String INTERFACE = "interface";
17 |
18 | String METHOD = "method";
19 |
20 | String GROUP = "group";
21 |
22 | String VERSION = "version";
23 |
24 | String CONSUMER = "consumer";
25 |
26 | String PROVIDER = "provider";
27 |
28 | String TIMESTAMP = "timestamp";
29 |
30 | String SUCCESS = "success";
31 |
32 | String FAILURE = "failure";
33 |
34 | String INPUT = Constants.INPUT_KEY;
35 |
36 | String OUTPUT = Constants.OUTPUT_KEY;
37 |
38 | String ELAPSED = "elapsed";
39 |
40 | String CONCURRENT = "concurrent";
41 |
42 | String MAX_INPUT = "max.input";
43 |
44 | String MAX_OUTPUT = "max.output";
45 |
46 | String MAX_ELAPSED = "max.elapsed";
47 |
48 | String MAX_CONCURRENT = "max.concurrent";
49 |
50 | /**
51 | * 监控数据采集.
52 | * 1. 支持调用次数统计:count://host/interface?application=foo&method=foo&provider=10.20.153.11:20880&success=12&failure=2&elapsed=135423423
53 | * 1.1 host,application,interface,group,version,method 记录监控来源主机,应用,接口,方法信息。
54 | * 1.2 如果是消费者发送的数据,加上provider地址参数,反之,加上来源consumer地址参数。
55 | * 1.3 success,faulure,elapsed 记录距上次采集,调用的成功次数,失败次数,成功调用总耗时,平均时间将用总耗时除以成功次数。
56 | *
57 | * @param statistics
58 | */
59 | void collect(URL statistics);
60 |
61 | /**
62 | * 监控数据查询.
63 | * 1. 支持按天查询:count://host/interface?application=foo&method=foo&side=provider&view=chart&date=2012-07-03
64 | * 1.1 host,application,interface,group,version,method 查询主机,应用,接口,方法的匹配条件,缺失的条件的表示全部,host用0.0.0.0表示全部。
65 | * 1.2 side=consumer,provider 查询由调用的哪一端采集的数据,缺省为都查询。
66 | * 1.3 缺省为view=summary,返回全天汇总信息,支持view=chart表示返回全天趋势图表图片的URL地址,可以进接嵌入其它系统的页面上展示。
67 | * 1.4 date=2012-07-03 指定查询数据的日期,缺省为当天。
68 | *
69 | * @param query
70 | * @return statistics
71 | */
72 | List lookup(URL query);
73 |
74 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/ChannelEventListener.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | import io.netty.channel.Channel;
4 |
5 | /**
6 | * @author goodjava@qq.com
7 | */
8 | public interface ChannelEventListener {
9 |
10 | void onChannelConnect(final String remoteAddr, final Channel channel);
11 |
12 | void onChannelClose(final String remoteAddr, final Channel channel);
13 |
14 | void onChannelException(final String remoteAddr, final Channel channel);
15 |
16 | void onChannelIdle(final String remoteAddr, final Channel channel);
17 | }
18 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/ChannelWrapper.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | import io.netty.channel.Channel;
4 | import io.netty.channel.ChannelFuture;
5 |
6 | /**
7 | * @author goodjava@qq.com
8 | */
9 | public class ChannelWrapper {
10 |
11 | private final ChannelFuture channelFuture;
12 |
13 |
14 | public ChannelWrapper(ChannelFuture channelFuture) {
15 | this.channelFuture = channelFuture;
16 | }
17 |
18 |
19 | public boolean isOK() {
20 | return this.channelFuture.channel() != null && this.channelFuture.channel().isActive();
21 | }
22 |
23 |
24 | public boolean isWriteable() {
25 | return this.channelFuture.channel().isWritable();
26 | }
27 |
28 |
29 | public Channel getChannel() {
30 | return this.channelFuture.channel();
31 | }
32 |
33 |
34 | public ChannelFuture getChannelFuture() {
35 | return channelFuture;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/ClientChannelEventListener.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | import io.netty.channel.Channel;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | /**
8 | * @author goodjava@qq.com
9 | */
10 | public class ClientChannelEventListener implements ChannelEventListener {
11 |
12 | private static final Logger logger = LoggerFactory.getLogger(ClientChannelEventListener.class);
13 |
14 |
15 | public ClientChannelEventListener() {
16 | }
17 |
18 | @Override
19 | public void onChannelConnect(String remoteAddr, Channel channel) {
20 | logger.info("client connect remoteAddr:{}", remoteAddr);
21 | }
22 |
23 | @Override
24 | public void onChannelClose(String remoteAddr, Channel channel) {
25 | logger.info("client close remoteAddr:" + remoteAddr);
26 | }
27 |
28 | @Override
29 | public void onChannelException(String remoteAddr, Channel channel) {
30 | logger.info("client onChannelException remoteAddr:{}", remoteAddr);
31 | }
32 |
33 | @Override
34 | public void onChannelIdle(String remoteAddr, Channel channel) {
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/DecoderState.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | /**
4 | * @author goodjava@qq.com
5 | */
6 | public enum DecoderState {
7 | /**
8 | * 魔术值
9 | */
10 | MagicNumber,
11 | /**
12 | * 包头
13 | */
14 | Header,
15 | /**
16 | * 包体
17 | */
18 | Body,
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/IClient.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | import com.colobu.rpcx.discovery.IServiceDiscovery;
4 | import com.colobu.rpcx.protocol.Message;
5 |
6 | /**
7 | * @author goodjava@qq.com
8 | */
9 | public interface IClient {
10 |
11 | Message call(Message req, long timeOut, String sendType) throws Exception;
12 |
13 | Message call(String addr, Message req, long timeOut) throws Exception;
14 |
15 | IServiceDiscovery getServiceDiscovery();
16 |
17 | void close();
18 |
19 | }
20 |
21 |
22 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/NettyClientHandler.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | import com.colobu.rpcx.protocol.RemotingCommand;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.channel.SimpleChannelInboundHandler;
6 |
7 | /**
8 | * @author goodjava@qq.com
9 | */
10 | public class NettyClientHandler extends SimpleChannelInboundHandler {
11 |
12 | private final NettyRemotingAbstract nettyClient;
13 |
14 | public NettyClientHandler(NettyRemotingAbstract nettyClient) {
15 | this.nettyClient = nettyClient;
16 | }
17 |
18 | @Override
19 | protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) {
20 | nettyClient.processMessageReceived(ctx, msg);
21 | }
22 |
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/NettyConnetManageHandler.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | import com.colobu.rpcx.common.RemotingHelper;
4 | import io.netty.channel.ChannelDuplexHandler;
5 | import io.netty.channel.ChannelHandlerContext;
6 | import io.netty.channel.ChannelPromise;
7 | import io.netty.handler.timeout.IdleState;
8 | import io.netty.handler.timeout.IdleStateEvent;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import java.net.SocketAddress;
13 |
14 | import static com.colobu.rpcx.common.RemotingUtil.closeChannel;
15 |
16 | /**
17 | * @author goodjava@qq.com
18 | */
19 | public class NettyConnetManageHandler extends ChannelDuplexHandler {
20 |
21 | private static final Logger log = LoggerFactory.getLogger(NettyConnetManageHandler.class);
22 |
23 | private final NettyRemotingAbstract nettyRemotingAbstract;
24 |
25 | public NettyConnetManageHandler(NettyRemotingAbstract nettyRemotingAbstract) {
26 | this.nettyRemotingAbstract = nettyRemotingAbstract;
27 | }
28 |
29 | @Override
30 | public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise)
31 | throws Exception {
32 | final String local = localAddress == null ? "UNKNOW" : localAddress.toString();
33 | final String remote = remoteAddress == null ? "UNKNOW" : remoteAddress.toString();
34 | log.info("NETTY CLIENT PIPELINE: CONNECT {} => {}", local, remote);
35 | super.connect(ctx, remoteAddress, localAddress, promise);
36 |
37 | if (nettyRemotingAbstract.hasEventListener()) {
38 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress.toString(), ctx.channel()));
39 | }
40 | }
41 |
42 |
43 | @Override
44 | public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
45 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
46 | log.info("NETTY CLIENT PIPELINE: DISCONNECT {}", remoteAddress);
47 | closeChannel(ctx.channel());
48 | super.disconnect(ctx, promise);
49 |
50 | if (nettyRemotingAbstract.hasEventListener()) {
51 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress.toString(), ctx.channel()));
52 | }
53 | }
54 |
55 |
56 | @Override
57 | public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
58 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
59 | log.info("NETTY CLIENT PIPELINE: CLOSE {}", remoteAddress);
60 | nettyRemotingAbstract.closeChannel(ctx.channel());
61 | super.close(ctx, promise);
62 |
63 | if (nettyRemotingAbstract.hasEventListener()) {
64 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress.toString(), ctx.channel()));
65 | }
66 | }
67 |
68 | @Override
69 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
70 | if (evt instanceof IdleStateEvent) {
71 | IdleStateEvent evnet = (IdleStateEvent) evt;
72 | if (evnet.state().equals(IdleState.ALL_IDLE)) {
73 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
74 | log.warn("NETTY CLIENT PIPELINE: IDLE exception [{}]", remoteAddress);
75 | closeChannel(ctx.channel());
76 | if (nettyRemotingAbstract.hasEventListener()) {
77 | nettyRemotingAbstract
78 | .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress.toString(), ctx.channel()));
79 | }
80 | }
81 | }
82 |
83 | ctx.fireUserEventTriggered(evt);
84 | }
85 |
86 | @Override
87 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
88 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
89 | log.warn("NETTY CLIENT PIPELINE: exceptionCaught {}", remoteAddress);
90 | log.warn("NETTY CLIENT PIPELINE: exceptionCaught exception.", cause);
91 | closeChannel(ctx.channel());
92 | if (nettyRemotingAbstract.hasEventListener()) {
93 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress.toString(), ctx.channel()));
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/common/src/main/java/com/colobu/rpcx/netty/NettyDecoder.java:
--------------------------------------------------------------------------------
1 | package com.colobu.rpcx.netty;
2 |
3 | import com.colobu.rpcx.protocol.Message;
4 | import com.colobu.rpcx.protocol.RemotingCommand;
5 | import com.colobu.rpcx.rpc.RpcException;
6 | import io.netty.buffer.ByteBuf;
7 | import io.netty.channel.ChannelHandlerContext;
8 | import io.netty.handler.codec.ReplayingDecoder;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * @author goodjava@qq.com
14 | */
15 | public class NettyDecoder extends ReplayingDecoder {
16 |
17 | private Message message = null;
18 |
19 | public NettyDecoder() {
20 | super(DecoderState.MagicNumber);
21 | }
22 |
23 | @Override
24 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List