省住房城乡建设厅网站百度搜索指数1000是什么
前段时间同事问我,我们录制的流量中,尤其是dubbo的子调用显示经常他的末尾会带上一个小尾巴这个是什么意思呢,其实之前我没有太在意这个事情,只是同事这么疑问了,确实激起了好奇心,所以就差了下 到底是什么
我们先看下是什么样的现象, 如下图所示:
如上, 这里就会跟上一个~AP
的小尾巴,那这个到底是什么意思呢,是某个hash的结果吗?要了解这个,其实也不难,我们就看下dubbo子调用的identity是怎么赋值的就好了。所以我们来看下具体的逻辑
在录制过程中,事件过来的时候,如果是Before的情况下,就会进入如下内容,
protected void doBefore(BeforeEvent event) throws ProcessControlException {// 回放流量;如果是入口则放弃;子调用则进行mockif (RepeatCache.isRepeatFlow(Tracer.getTraceId())) {processor.doMock(event, entrance, invokeType);return;}Invocation invocation = initInvocation(event);invocation.setStart(System.currentTimeMillis());invocation.setTraceId(Tracer.getTraceId());invocation.setIndex(entrance ? 0 : SequenceGenerator.generate(Tracer.getTraceId()));invocation.setIdentity(processor.assembleIdentity(event));invocation.setEntrance(entrance);invocation.setType(invokeType);invocation.setProcessId(event.processId);invocation.setInvokeId(event.invokeId);invocation.setRequest(processor.assembleRequest(event));invocation.setResponse(processor.assembleResponse(event));invocation.setSerializeToken(ClassloaderBridge.instance().encode(event.javaClassLoader));try {// fix issue#14 : useGeneratedKeysif (processor.inTimeSerializeRequest(invocation, event)) {SerializerWrapper.inTimeSerialize(invocation);}} catch (SerializeException e) {Tracer.getContext().setSampled(false);log.error("Error occurred serialize", e);}RecordCache.cacheInvocation(event.invokeId, invocation);
}
所以identity
是经过各自的子调用处理器处理后生成的标识。这里我们具体的就是dubbo的调用,所以我们看下 DubboConsumerInvocationProcessor
的逻辑
public Identity assembleIdentity(BeforeEvent event) {Object invoker;Object invocation;if (ON_RESPONSE.equals(event.javaMethodName)) {// for record identity assemble// onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {}invoker = event.argumentArray[1];invocation = event.argumentArray[2];} else {// for repeater identity assemble// invoke(Invoker<?> invoker, Invocation invocation)invoker = event.argumentArray[0];invocation = event.argumentArray[1];}try {// methodNameString methodName = (String) MethodUtils.invokeMethod(invocation, "getMethodName");Class<?>[] parameterTypes = (Class<?>[]) MethodUtils.invokeMethod(invocation, "getParameterTypes");// interfaceNameString interfaceName = ((Class)MethodUtils.invokeMethod(invoker, "getInterface")).getCanonicalName();return new Identity(InvokeType.DUBBO.name(), interfaceName, getMethodDesc(methodName, parameterTypes), getExtra());} catch (Exception e) {// ignoreLogUtil.error("error occurred when assemble dubbo request", e);}return new Identity(InvokeType.DUBBO.name(), "unknown", "unknown", null);
}
我们看到Identity
直接就是通过 new Identity(InvokeType.DUBBO.name(), interfaceName, getMethodDesc(methodName, parameterTypes), getExtra())
完成的。 所以这的参数按照前面截图的来看的话,
-
InvokeType.DUBBO.name()
即dubbo
, -
interfaceName
则是com.xx.xx.api.service.UserAgreementApiService
-
getMethodDesc(methodName, parameterTypes)
这个看了下实现原来就是我们一直在寻找的带小尾巴的原因了, 我们来看下。protected String getMethodDesc(String methodName, Class<?>[] parameterTypes) {StringBuilder builder = new StringBuilder(methodName);if (parameterTypes != null && parameterTypes.length > 0) {builder.append("~");for (Class<?> parameterType : parameterTypes) {String className = parameterType.getSimpleName();builder.append(className.subSequence(0, 1));}}return builder.toString();}
我们可以看到它这里就是就是在拼接方法跟参数类型,不过他没有拿参数类型的所有内容,而是参数类型的类名,比如说 Java.lang.String 结果就是
string
了, 然后取这里的第一个字符。 -
getExtra() 暂时位置,看着是http的query的字段, 不过看到所有的录制的子调用录制逻辑基本都是null, 我们这里暂时就先忽略了。
那我们就直接看下Identity 的构造函数是怎么样的吧。
public Identity(String scheme, String location, String endpoint, Map<String, String> extra) {this.scheme = scheme;this.location = location;this.endpoint = endpoint;this.extra = extra;StringBuilder sb = new StringBuilder();sb.append(scheme).append(HOST_SPLITTER).append(Joiner.on("/").join(location, endpoint));if (extra != null && !extra.isEmpty()) {boolean firstKey = true;for (Map.Entry<String, String> entry : extra.entrySet()) {if (firstKey) {firstKey = false;sb.append(QUERY_STRING_COLLECTOR);} else {sb.append(KEY_VALUE_SPLITTER);}sb.append(entry.getKey()).append(KEY_VALUE_COLLECTOR).append(entry.getValue());}}this.uri = sb.toString();}
可以看到构造函数里面的逻辑其实重点是在构造一个uri, 而这个uri 应该就是我们最开始截图的时候看到的identity的内容了。 其实就是通过各个分隔符连接起来,构成我们传参进来的数据。