增加将接受到的数据缓存到缓存文件中

This commit is contained in:
ascrutae 2016-07-15 09:47:55 +08:00
parent f0058ab74c
commit 9c23c745c7
35 changed files with 1397 additions and 140 deletions

View File

@ -86,7 +86,7 @@ public class CurrentThreadSpanStack {
public void invalidatePresentSpans() {
for (SpanNode spanNode : spans) {
spanNode.getData().setInvalidate(true);
spanNode.getData().setValidate(true);
}
}
}

View File

@ -31,12 +31,13 @@ public abstract class BaseInvokeMonitor {
logger.debug("TraceId:" + spanData.getTraceId() + "\tviewpointId:" + id.getViewPoint() + "\tParentLevelId:" + spanData.getParentLevel() + "\tLevelId:" + spanData
.getLevelId());
}
// 根据SpanData生成RequestSpan并保存
ContextBuffer.save(RequestSpan.RequestSpanBuilder.
newBuilder(spanData).callType(id.getCallType())
.viewPoint(id.getViewPoint())
.spanTypeDesc(id.getSpanTypeDesc())
.build());
if (!spanData.isValidate()) {
// 根据SpanData生成RequestSpan并保存
ContextBuffer.save(RequestSpan.RequestSpanBuilder.
newBuilder(spanData).callType(id.getCallType()).viewPoint(id.getViewPoint()).spanTypeDesc(id.getSpanTypeDesc()).build());
}
// 将新创建的Context存放到ThreadLocal栈中
CurrentThreadSpanStack.push(spanData);
@ -51,7 +52,7 @@ public abstract class BaseInvokeMonitor {
// 弹出上下文的栈顶中的元素
Span spanData = CurrentThreadSpanStack.pop();
if (spanData == null || spanData.isInvalidate()) {
if (spanData == null || spanData.isValidate()) {
return;
}

View File

@ -63,7 +63,7 @@ public final class ContextGenerator {
// if true, current span is invalidate and current span also belong to RPC span
if (parentSpan.isRPCClientSpan()) {
span.setSpanType(SpanType.RPC_CLIENT);
span.setIsInvalidate(true);
span.setValidate(false);
}
if (!StringUtil.isEmpty(parentSpan.getParentLevel())) {

View File

@ -2,19 +2,19 @@ package test.ai.cloud.serialize;
import com.ai.cloud.skywalking.buffer.ContextBuffer;
import com.ai.cloud.skywalking.protocol.AckSpan;
import com.ai.cloud.skywalking.protocol.RequestSpan;
import com.ai.cloud.skywalking.protocol.Span;
import com.ai.cloud.skywalking.protocol.common.CallType;
import com.ai.cloud.skywalking.protocol.common.SpanType;
public class SerializeTest {
public static void main(String[] args) throws InterruptedException {
Span spandata = new Span("1.0b.1461060884539.7d6d06e.22489.1271.103", "", 0, "test-application", "test");
spandata.setSpanType(SpanType.LOCAL);
spandata.setStartDate(System.currentTimeMillis() - 1000 * 60);
AckSpan requestSpan = new AckSpan(spandata);
ContextBuffer.save(requestSpan);
while (true) {
Span spandata = new Span("1.0b.1461060884539.7d6d06e.22489.1271.103", "", 0, "test-application", "test");
spandata.setSpanType(SpanType.LOCAL);
spandata.setStartDate(System.currentTimeMillis() - 1000 * 60);
AckSpan requestSpan = new AckSpan(spandata);
ContextBuffer.save(requestSpan);
Thread.sleep(2 * 1000);
}
Thread.sleep(60 * 1000 * 10);
}
}

View File

@ -1206,6 +1206,20 @@ public final class TraceProtocol {
*/
com.google.protobuf.ByteString
getBussinessKeyBytes();
/**
* <code>required string agentId = 12;</code>
*/
boolean hasAgentId();
/**
* <code>required string agentId = 12;</code>
*/
java.lang.String getAgentId();
/**
* <code>required string agentId = 12;</code>
*/
com.google.protobuf.ByteString
getAgentIdBytes();
}
/**
* Protobuf type {@code RequestSpan}
@ -1322,6 +1336,12 @@ public final class TraceProtocol {
bussinessKey_ = bs;
break;
}
case 98: {
com.google.protobuf.ByteString bs = input.readBytes();
bitField0_ |= 0x00000800;
agentId_ = bs;
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@ -1743,6 +1763,48 @@ public final class TraceProtocol {
}
}
public static final int AGENTID_FIELD_NUMBER = 12;
private java.lang.Object agentId_;
/**
* <code>required string agentId = 12;</code>
*/
public boolean hasAgentId() {
return ((bitField0_ & 0x00000800) == 0x00000800);
}
/**
* <code>required string agentId = 12;</code>
*/
public java.lang.String getAgentId() {
java.lang.Object ref = agentId_;
if (ref instanceof java.lang.String) {
return (java.lang.String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
if (bs.isValidUtf8()) {
agentId_ = s;
}
return s;
}
}
/**
* <code>required string agentId = 12;</code>
*/
public com.google.protobuf.ByteString
getAgentIdBytes() {
java.lang.Object ref = agentId_;
if (ref instanceof java.lang.String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
agentId_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
private void initFields() {
traceId_ = "";
parentLevel_ = "";
@ -1755,6 +1817,7 @@ public final class TraceProtocol {
applicationId_ = "";
userId_ = "";
bussinessKey_ = "";
agentId_ = "";
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@ -1798,6 +1861,10 @@ public final class TraceProtocol {
memoizedIsInitialized = 0;
return false;
}
if (!hasAgentId()) {
memoizedIsInitialized = 0;
return false;
}
memoizedIsInitialized = 1;
return true;
}
@ -1838,6 +1905,9 @@ public final class TraceProtocol {
if (((bitField0_ & 0x00000400) == 0x00000400)) {
output.writeBytes(11, getBussinessKeyBytes());
}
if (((bitField0_ & 0x00000800) == 0x00000800)) {
output.writeBytes(12, getAgentIdBytes());
}
getUnknownFields().writeTo(output);
}
@ -1891,6 +1961,10 @@ public final class TraceProtocol {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(11, getBussinessKeyBytes());
}
if (((bitField0_ & 0x00000800) == 0x00000800)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(12, getAgentIdBytes());
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@ -2030,6 +2104,8 @@ public final class TraceProtocol {
bitField0_ = (bitField0_ & ~0x00000200);
bussinessKey_ = "";
bitField0_ = (bitField0_ & ~0x00000400);
agentId_ = "";
bitField0_ = (bitField0_ & ~0x00000800);
return this;
}
@ -2102,6 +2178,10 @@ public final class TraceProtocol {
to_bitField0_ |= 0x00000400;
}
result.bussinessKey_ = bussinessKey_;
if (((from_bitField0_ & 0x00000800) == 0x00000800)) {
to_bitField0_ |= 0x00000800;
}
result.agentId_ = agentId_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@ -2167,6 +2247,11 @@ public final class TraceProtocol {
bussinessKey_ = other.bussinessKey_;
onChanged();
}
if (other.hasAgentId()) {
bitField0_ |= 0x00000800;
agentId_ = other.agentId_;
onChanged();
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@ -2208,6 +2293,10 @@ public final class TraceProtocol {
return false;
}
if (!hasAgentId()) {
return false;
}
return true;
}
@ -2934,6 +3023,82 @@ public final class TraceProtocol {
return this;
}
private java.lang.Object agentId_ = "";
/**
* <code>required string agentId = 12;</code>
*/
public boolean hasAgentId() {
return ((bitField0_ & 0x00000800) == 0x00000800);
}
/**
* <code>required string agentId = 12;</code>
*/
public java.lang.String getAgentId() {
java.lang.Object ref = agentId_;
if (!(ref instanceof java.lang.String)) {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
if (bs.isValidUtf8()) {
agentId_ = s;
}
return s;
} else {
return (java.lang.String) ref;
}
}
/**
* <code>required string agentId = 12;</code>
*/
public com.google.protobuf.ByteString
getAgentIdBytes() {
java.lang.Object ref = agentId_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
agentId_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <code>required string agentId = 12;</code>
*/
public Builder setAgentId(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000800;
agentId_ = value;
onChanged();
return this;
}
/**
* <code>required string agentId = 12;</code>
*/
public Builder clearAgentId() {
bitField0_ = (bitField0_ & ~0x00000800);
agentId_ = getDefaultInstance().getAgentId();
onChanged();
return this;
}
/**
* <code>required string agentId = 12;</code>
*/
public Builder setAgentIdBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000800;
agentId_ = value;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:RequestSpan)
}
@ -2967,14 +3132,14 @@ public final class TraceProtocol {
"\n\023TraceProtocol.proto\"z\n\007AckSpan\022\017\n\007trac" +
"eId\030\001 \002(\t\022\023\n\013parentLevel\030\002 \001(\t\022\017\n\007levelI" +
"d\030\003 \002(\005\022\014\n\004cost\030\004 \002(\003\022\022\n\nstatusCode\030\005 \002(" +
"\005\022\026\n\016exceptionStack\030\006 \001(\t\"\343\001\n\013RequestSpa" +
"\005\022\026\n\016exceptionStack\030\006 \001(\t\"\364\001\n\013RequestSpa" +
"n\022\017\n\007traceId\030\001 \002(\t\022\023\n\013parentLevel\030\002 \001(\t\022" +
"\017\n\007levelId\030\003 \002(\005\022\023\n\013viewPointId\030\004 \002(\t\022\021\n" +
"\tstartDate\030\005 \002(\003\022\024\n\014spanTypeDesc\030\006 \002(\t\022\020" +
"\n\010callType\030\007 \002(\t\022\020\n\010spanType\030\010 \002(\r\022\025\n\rap" +
"plicationId\030\t \002(\t\022\016\n\006userId\030\n \002(\t\022\024\n\014bus" +
"sinessKey\030\013 \001(\tB(\n&com.ai.cloud.skywalki",
"ng.protocol.proto"
"sinessKey\030\013 \001(\t\022\017\n\007agentId\030\014 \002(\tB(\n&com.",
"ai.cloud.skywalking.protocol.proto"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
@ -2999,7 +3164,7 @@ public final class TraceProtocol {
internal_static_RequestSpan_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_RequestSpan_descriptor,
new java.lang.String[] { "TraceId", "ParentLevel", "LevelId", "ViewPointId", "StartDate", "SpanTypeDesc", "CallType", "SpanType", "ApplicationId", "UserId", "BussinessKey", });
new java.lang.String[] { "TraceId", "ParentLevel", "LevelId", "ViewPointId", "StartDate", "SpanTypeDesc", "CallType", "SpanType", "ApplicationId", "UserId", "BussinessKey", "AgentId", });
}
// @@protoc_insertion_point(outer_class_scope)

View File

@ -1,6 +1,7 @@
package com.ai.cloud.skywalking.protocol;
import com.ai.cloud.skywalking.protocol.common.AbstractDataSerializable;
import com.ai.cloud.skywalking.protocol.exception.ConvertFailedException;
import com.ai.cloud.skywalking.protocol.proto.TraceProtocol;
import com.google.protobuf.InvalidProtocolBufferException;
@ -24,18 +25,18 @@ public class AckSpan extends AbstractDataSerializable {
* 当前调用链的本机描述<br/>
* 如当前序号为0.1.0时levelId=0
*/
private int levelId = 0;
private int levelId = 0;
/**
* 节点调用花费时间
*/
private long cost = 0L;
private long cost = 0L;
/**
* 节点调用的状态<br/>
* 0成功<br/>
* 1异常<br/>
* 异常判断原则代码产生exception并且此exception不在忽略列表中
*/
private byte statusCode = 0;
private byte statusCode = 0;
/**
* 节点调用的错误堆栈<br/>
* 堆栈以JAVA的exception为主要判断依据
@ -124,11 +125,12 @@ public class AckSpan extends AbstractDataSerializable {
@Override
public byte[] getData() {
return TraceProtocol.AckSpan.newBuilder().setTraceId(traceId).setParentLevel(parentLevel).
setLevelId(levelId).setCost(cost).setStatusCode(statusCode).setExceptionStack(exceptionStack).build().toByteArray();
setLevelId(levelId).setCost(cost).setStatusCode(statusCode).setExceptionStack(exceptionStack).build()
.toByteArray();
}
@Override
public AbstractDataSerializable convertData(byte[] data) {
public AbstractDataSerializable convertData(byte[] data) throws ConvertFailedException {
AckSpan ackSpan = new AckSpan();
try {
TraceProtocol.AckSpan ackSpanProtocol = TraceProtocol.AckSpan.parseFrom(data);
@ -139,7 +141,7 @@ public class AckSpan extends AbstractDataSerializable {
ackSpan.setExceptionStack(ackSpanProtocol.getExceptionStack());
ackSpan.setStatusCode((byte) ackSpanProtocol.getStatusCode());
} catch (InvalidProtocolBufferException e) {
return null;
throw new ConvertFailedException();
}
return ackSpan;

View File

@ -3,6 +3,7 @@ package com.ai.cloud.skywalking.protocol;
import com.ai.cloud.skywalking.protocol.common.AbstractDataSerializable;
import com.ai.cloud.skywalking.protocol.common.CallType;
import com.ai.cloud.skywalking.protocol.common.SpanType;
import com.ai.cloud.skywalking.protocol.exception.ConvertFailedException;
import com.ai.cloud.skywalking.protocol.proto.TraceProtocol;
import com.google.protobuf.InvalidProtocolBufferException;
@ -79,6 +80,11 @@ public class RequestSpan extends AbstractDataSerializable {
*/
private String businessKey = "";
/**
* 实例ID
*/
private String agentId = "";
public RequestSpan(Span spanData) {
this.traceId = spanData.getTraceId();
this.parentLevel = spanData.getParentLevel();
@ -191,13 +197,15 @@ public class RequestSpan extends AbstractDataSerializable {
@Override
public byte[] getData() {
return TraceProtocol.RequestSpan.newBuilder().setTraceId(traceId).setParentLevel(parentLevel).setLevelId(levelId).setViewPointId(viewPointId).setStartDate(startDate)
.setSpanType(spanType.getValue()).setSpanTypeDesc(spanTypeDesc).setBussinessKey(businessKey).setCallType(callType).setApplicationId(applicationId).setUserId(userId)
.build().toByteArray();
return TraceProtocol.RequestSpan.newBuilder().setTraceId(traceId).setParentLevel(parentLevel)
.setLevelId(levelId).setViewPointId(viewPointId).setStartDate(startDate)
.setSpanType(spanType.getValue()).setSpanTypeDesc(spanTypeDesc).setBussinessKey(businessKey)
.setCallType(callType).setApplicationId(applicationId).setUserId(userId).setBussinessKey(businessKey)
.setAgentId(agentId).build().toByteArray();
}
@Override
public AbstractDataSerializable convertData(byte[] data) {
public AbstractDataSerializable convertData(byte[] data) throws ConvertFailedException {
RequestSpan requestSpan = new RequestSpan();
try {
TraceProtocol.RequestSpan requestSpanByte = TraceProtocol.RequestSpan.parseFrom(data);
@ -211,8 +219,10 @@ public class RequestSpan extends AbstractDataSerializable {
requestSpan.setStartDate(requestSpanByte.getStartDate());
requestSpan.setUserId(requestSpanByte.getUserId());
requestSpan.setViewPointId(requestSpanByte.getViewPointId());
requestSpan.setBusinessKey(requestSpanByte.getBussinessKey());
requestSpan.setAgentId(requestSpanByte.getAgentId());
} catch (InvalidProtocolBufferException e) {
return null;
throw new ConvertFailedException();
}
return requestSpan;
@ -223,6 +233,17 @@ public class RequestSpan extends AbstractDataSerializable {
return false;
}
public void setBusinessKey(String businessKey) {
this.businessKey = businessKey;
}
public String getAgentId() {
return agentId;
}
public void setAgentId(String agentId) {
this.agentId = agentId;
}
public static class RequestSpanBuilder {
private RequestSpan ackSpan;

View File

@ -2,6 +2,7 @@ package com.ai.cloud.skywalking.protocol;
import com.ai.cloud.skywalking.protocol.common.AbstractDataSerializable;
import com.ai.cloud.skywalking.protocol.common.NullableClass;
import com.ai.cloud.skywalking.protocol.exception.ConvertFailedException;
import com.ai.cloud.skywalking.protocol.util.IntegerAssist;
import java.util.HashMap;
@ -9,7 +10,8 @@ import java.util.Map;
import java.util.ServiceLoader;
public class SerializedFactory {
public static Map<Integer, AbstractDataSerializable> serializableMap = new HashMap<Integer, AbstractDataSerializable>();
public static Map<Integer, AbstractDataSerializable> serializableMap =
new HashMap<Integer, AbstractDataSerializable>();
static {
@ -20,13 +22,17 @@ public class SerializedFactory {
}
}
public static AbstractDataSerializable unSerialize(byte[] bytes) {
AbstractDataSerializable abstractDataSerializable = serializableMap.get(IntegerAssist.bytesToInt(bytes, 0));
if (abstractDataSerializable != null) {
NullableClass nullableClass = abstractDataSerializable.convert2Object(bytes);
if (!nullableClass.isNull()) {
return (AbstractDataSerializable) nullableClass;
public static AbstractDataSerializable unSerialize(byte[] bytes) throws ConvertFailedException {
try {
AbstractDataSerializable abstractDataSerializable = serializableMap.get(IntegerAssist.bytesToInt(bytes, 0));
if (abstractDataSerializable != null) {
NullableClass nullableClass = abstractDataSerializable.convert2Object(bytes);
if (!nullableClass.isNull()) {
return (AbstractDataSerializable) nullableClass;
}
}
} catch (Exception e) {
throw new ConvertFailedException();
}
return null;
}

View File

@ -49,7 +49,7 @@ public class Span {
* 节点的状态<br/>
* 不参与序列化
*/
protected boolean isInvalidate = false;
protected boolean isValidate = true;
/**
* 节点调用过程中的业务字段<br/>
@ -111,8 +111,8 @@ public class Span {
this.startDate = startDate;
}
public boolean isInvalidate() {
return isInvalidate;
public boolean isValidate() {
return isValidate;
}
public byte getStatusCode() {
@ -135,8 +135,8 @@ public class Span {
this.parameters = parameters;
}
public void setInvalidate(boolean invalidate) {
isInvalidate = invalidate;
public void setValidate(boolean validate) {
isValidate = validate;
}
public boolean isRPCClientSpan() {
@ -154,10 +154,6 @@ public class Span {
return spanType;
}
public void setIsInvalidate(boolean isInvalidate) {
this.isInvalidate = isInvalidate;
}
public void handleException(Throwable e, Set<String> exclusiveExceptionSet, int maxExceptionStackLength) {
ByteArrayOutputStream buf = null;
StringBuilder expMessage = new StringBuilder();
@ -217,4 +213,6 @@ public class Span {
public void setUserId(String userId) {
this.userId = userId;
}
}

View File

@ -16,44 +16,30 @@ public class TransportPackager {
return dataPackage;
}
public static List<byte[]> unpack(byte[] dataPackage) {
if (validateCheckSum(dataPackage)) {
return unpackDataBody(unpackCheckSum(dataPackage));
} else {
return new ArrayList<byte[]>();
}
}
private static byte[] unpackCheckSum(byte[] dataPackage) {
return Arrays.copyOfRange(dataPackage, 4, dataPackage.length);
}
private static List<byte[]> unpackDataBody(byte[] dataPackage) {
List<byte[]> serializeData = new ArrayList<byte[]>();
int currentLength = 0;
while (true) {
//读取长度
int dataLength = IntegerAssist.bytesToInt(dataPackage, currentLength);
// 反序列化
byte[] data = new byte[dataLength];
System.arraycopy(dataPackage, currentLength + 4, data, 0, dataLength);
//
serializeData.add(data);
currentLength = 4 + dataLength;
if (currentLength >= dataPackage.length) {
break;
public static List<byte[]> unpackDataBody(byte[] dataPackage) {
List<byte[]> serializeData = null;
try {
serializeData = new ArrayList<byte[]>();
int currentLength = 0;
while (true) {
//读取长度
int dataLength = IntegerAssist.bytesToInt(dataPackage, currentLength);
// 反序列化
byte[] data = new byte[dataLength];
System.arraycopy(dataPackage, currentLength + 4, data, 0, dataLength);
//
serializeData.add(data);
currentLength += 4 + dataLength;
if (currentLength >= dataPackage.length) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return serializeData;
}
private static boolean validateCheckSum(byte[] dataPackage) {
byte[] checkSum = generateChecksum(dataPackage, 4);
byte[] originCheckSum = new byte[4];
System.arraycopy(dataPackage, 0, originCheckSum, 0, 4);
return Arrays.equals(checkSum, originCheckSum);
}
/**
* 生成校验和参数
*

View File

@ -2,6 +2,7 @@ package com.ai.cloud.skywalking.protocol.common;
import com.ai.cloud.skywalking.protocol.NullClass;
import com.ai.cloud.skywalking.protocol.SerializedFactory;
import com.ai.cloud.skywalking.protocol.exception.ConvertFailedException;
import com.ai.cloud.skywalking.protocol.util.IntegerAssist;
import java.util.Arrays;
@ -14,7 +15,7 @@ public abstract class AbstractDataSerializable implements ISerializable, Nullabl
public abstract byte[] getData();
public abstract AbstractDataSerializable convertData(byte[] data);
public abstract AbstractDataSerializable convertData(byte[] data) throws ConvertFailedException;
/**
* 消息包结构:
@ -41,7 +42,7 @@ public abstract class AbstractDataSerializable implements ISerializable, Nullabl
}
@Override
public NullableClass convert2Object(byte[] data) {
public NullableClass convert2Object(byte[] data) throws ConvertFailedException {
int dataType = IntegerAssist.bytesToInt(data, 0);
if (!SerializedFactory.isCanSerialized(dataType)) {

View File

@ -1,11 +1,13 @@
package com.ai.cloud.skywalking.protocol.common;
import com.ai.cloud.skywalking.protocol.exception.ConvertFailedException;
/**
* Created by wusheng on 16/7/4.
*/
public interface ISerializable {
byte[] convert2Bytes();
NullableClass convert2Object(byte[] data);
NullableClass convert2Object(byte[] data) throws ConvertFailedException;
}

View File

@ -0,0 +1,4 @@
package com.ai.cloud.skywalking.protocol.exception;
public class ConvertFailedException extends Exception {
}

View File

@ -1,8 +1,8 @@
syntax="proto2";
syntax = "proto2";
option java_package = "com.ai.cloud.skywalking.protocol.proto";
message AckSpan{
message AckSpan {
required string traceId = 1;
optional string parentLevel = 2;
required int32 levelId = 3;
@ -24,4 +24,5 @@ message RequestSpan {
required string applicationId = 9;
required string userId = 10;
optional string bussinessKey = 11;
required string agentId = 12;
}

View File

@ -18,11 +18,6 @@
</properties>
<dependencies>
<dependency>
<groupId>com.ai.cloud</groupId>
<artifactId>skywalking-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.ai.cloud</groupId>
<artifactId>skywalking-api</artifactId>

View File

@ -4,6 +4,7 @@ import com.ai.cloud.skywalking.reciever.buffer.DataBufferThreadContainer;
import com.ai.cloud.skywalking.reciever.conf.Config;
import com.ai.cloud.skywalking.reciever.conf.ConfigInitializer;
import com.ai.cloud.skywalking.reciever.handler.CollectionServerDataHandler;
import com.ai.cloud.skywalking.reciever.peresistent.PersistenceThreadLauncher;
import com.ai.cloud.skywalking.reciever.selfexamination.ServerHealthCollector;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
@ -35,7 +36,8 @@ public class CollectionServer {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO))
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<io.netty.channel.socket.SocketChannel>() {
@Override
public void initChannel(io.netty.channel.socket.SocketChannel ch) throws Exception {
@ -61,6 +63,8 @@ public class CollectionServer {
initializeParam();
logger.info("To init server health collector...");
ServerHealthCollector.init();
logger.info("To launch register persistence thread....");
PersistenceThreadLauncher.doLaunch();
logger.info("To init data buffer thread container...");
DataBufferThreadContainer.init();
logger.info("Starting collection server.....");

View File

@ -0,0 +1,44 @@
package com.ai.cloud.skywalking.reciever.buffer;
import com.ai.cloud.skywalking.reciever.model.BufferDataPackagerGenerator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
class AppendEOFFlagThread extends Thread {
private Logger logger = LogManager.getLogger(AppendEOFFlagThread.class);
private File[] dataBufferFiles;
private CountDownLatch countDownLatch;
public AppendEOFFlagThread(File[] dataBufferFiles, CountDownLatch countDownLatch) {
super("AppendEOFFlagThread");
this.dataBufferFiles = dataBufferFiles;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
FileOutputStream fileOutputStream = null;
for (File file : dataBufferFiles) {
try {
logger.info("Add EOF flags to unprocessed data file[{}]", file.getName());
fileOutputStream = new FileOutputStream(new File(file.getParent(), file.getName()), true);
fileOutputStream.write(BufferDataPackagerGenerator.generateEOFPackage());
} catch (IOException e) {
logger.info("Add EOF flags to the unprocessed data file failed.", e);
} finally {
try {
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
logger.error("Flush data file failed", e);
}
}
countDownLatch.countDown();
}
}
}

View File

@ -1,20 +1,18 @@
package com.ai.cloud.skywalking.reciever.buffer;
import com.ai.cloud.skywalking.protocol.common.AbstractDataSerializable;
import com.ai.cloud.skywalking.protocol.util.AtomicRangeInteger;
import com.ai.cloud.skywalking.reciever.conf.Config;
import com.ai.cloud.skywalking.reciever.processor.IProcessor;
import com.ai.cloud.skywalking.reciever.processor.ProcessorFactory;
import com.ai.cloud.skywalking.reciever.model.BufferDataPackagerGenerator;
import com.ai.cloud.skywalking.reciever.selfexamination.ServerHealthCollector;
import com.ai.cloud.skywalking.reciever.selfexamination.ServerHeathReading;
import com.ai.cloud.skywalking.protocol.SerializedFactory;
import com.ai.cloud.skywalking.protocol.util.AtomicRangeInteger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.UUID;
import static com.ai.cloud.skywalking.reciever.conf.Config.Buffer.DATA_CONFLICT_WAIT_TIME;
import static com.ai.cloud.skywalking.reciever.conf.Config.Buffer.PER_THREAD_MAX_BUFFER_NUMBER;
@ -31,28 +29,30 @@ public class DataBufferThread extends Thread {
@Override
public void run() {
Map<Integer, List<AbstractDataSerializable>> serializeObjects;
FileOutputStream fileOutputStream = null;
int length = 0;
while (true) {
serializeObjects = new HashMap<Integer, List<AbstractDataSerializable>>();
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
continue;
}
AbstractDataSerializable serializeData = SerializedFactory.unSerialize(data[i]);
List<AbstractDataSerializable> hasBeenSerializedObjects = serializeObjects.get(serializeData.getDataType());
if (hasBeenSerializedObjects == null) {
serializeObjects.put(serializeData.getDataType(), new ArrayList<AbstractDataSerializable>());
if (fileOutputStream == null) {
fileOutputStream = acquiredNewBufferFileStream();
}
serializeObjects.get(serializeData.getDataType()).add(serializeData);
data[i] = null;
}
try {
fileOutputStream.write(BufferDataPackagerGenerator.pack(data[i]));
length += data[i].length;
data[i] = null;
} catch (IOException e) {
logger.error("Failed to write msg.", e);
}
for (Map.Entry<Integer, List<AbstractDataSerializable>> entry : serializeObjects.entrySet()) {
IProcessor processor = ProcessorFactory.chooseProcessor(entry.getKey());
if (processor != null) {
processor.process(entry.getValue());
if (length > Config.Buffer.BUFFER_FILE_MAX_LENGTH) {
closeCurrentBufferFile(fileOutputStream);
fileOutputStream = null;
}
}
@ -65,19 +65,73 @@ public class DataBufferThread extends Thread {
}
}
private void closeCurrentBufferFile(FileOutputStream fileOutputStream) {
try {
fileOutputStream.flush();
fileOutputStream.write(BufferDataPackagerGenerator.generateEOFPackage());
} catch (IOException e) {
logger.error("Failed to write msg.", e);
} finally {
try {
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
logger.error("Failed to flush and close file.", e);
}
}
}
private FileOutputStream acquiredNewBufferFileStream() {
checkBufferDirIsExists();
File outputFile = createNewBufferFile();
return generateFileOutputStream(outputFile);
}
private FileOutputStream generateFileOutputStream(File outputFile) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(outputFile);
} catch (FileNotFoundException e) {
logger.error("Failed to create File:{}", outputFile.getName(), e);
}
return fileOutputStream;
}
private File createNewBufferFile() {
File outputFile = new File(Config.Buffer.DATA_BUFFER_FILE_PARENT_DIR,
System.currentTimeMillis() + "-" + UUID.randomUUID().toString());
if (!outputFile.exists()) {
try {
outputFile.createNewFile();
ServerHealthCollector.getCurrentHeathReading(null)
.updateData(ServerHeathReading.INFO, "Create new Buffer file[" + outputFile.getName() + "]");
} catch (IOException e) {
logger.error("Failed to create File:{}", outputFile.getName(), e);
}
}
return outputFile;
}
private void checkBufferDirIsExists() {
File outPutDir = new File(Config.Buffer.DATA_BUFFER_FILE_PARENT_DIR);
if (!outPutDir.exists()) {
outPutDir.mkdirs();
}
}
public void saveTemporarily(byte[] s) {
int i = index.getAndIncrement();
while (data[i] != null) {
try {
ServerHealthCollector.getCurrentHeathReading(null).updateData(ServerHeathReading.WARNING, "DataBuffer index[" + i + "] data collision, service pausing. ");
ServerHealthCollector.getCurrentHeathReading(null).updateData(ServerHeathReading.WARNING,
"DataBuffer index[" + i + "] data collision, service pausing. ");
Thread.sleep(DATA_CONFLICT_WAIT_TIME);
} catch (InterruptedException e) {
logger.error("Failure sleep.", e);
}
}
ServerHealthCollector.getCurrentHeathReading(null).updateData(ServerHeathReading.INFO, "DataBuffer reveiving data.");
ServerHealthCollector.getCurrentHeathReading(null)
.updateData(ServerHeathReading.INFO, "DataBuffer reveiving data.");
data[i] = s;
}

View File

@ -1,13 +1,19 @@
package com.ai.cloud.skywalking.reciever.buffer;
import com.ai.cloud.skywalking.reciever.conf.Config;
import org.apache.commons.io.comparator.NameFileComparator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import static com.ai.cloud.skywalking.reciever.conf.Config.Persistence.MAX_APPEND_EOF_FLAGS_THREAD_NUMBER;
public class DataBufferThreadContainer {
private static Logger logger = LogManager.getLogger(DataBufferThreadContainer.class);
@ -23,7 +29,38 @@ public class DataBufferThreadContainer {
return buffers.get(ThreadLocalRandom.current().nextInt(buffers.size()));
}
public static void init() {
public static void init() throws InterruptedException {
logger.info("Add EOF flags to the unprocessed data file last time.");
File parentDir = new File(Config.Buffer.DATA_BUFFER_FILE_PARENT_DIR);
// 判断数据缓存文件是否存在如果不存在则创建
if (!parentDir.exists()) {
parentDir.mkdirs();
}
NameFileComparator sizeComparator = new NameFileComparator();
File[] dataFileList = sizeComparator.sort(parentDir.listFiles());
logger.info("Pending file number :" + dataFileList.length);
if (dataFileList.length > 0) {
int step = (int) Math.ceil(dataFileList.length * 1.0 / MAX_APPEND_EOF_FLAGS_THREAD_NUMBER);
int start = 0, end = 0;
CountDownLatch countDownLatch = new CountDownLatch(MAX_APPEND_EOF_FLAGS_THREAD_NUMBER);
while (true) {
if (end + step >= dataFileList.length) {
new AppendEOFFlagThread(Arrays.copyOfRange(dataFileList, start, dataFileList.length),
countDownLatch).start();
break;
}
end += step;
new AppendEOFFlagThread(Arrays.copyOfRange(dataFileList, start, end), countDownLatch).start();
start = end;
logger.debug("start:" + start + "\tend:" + end);
}
countDownLatch.await();
}
logger.info("Data buffer thread size {} begin to init ", Config.Server.
MAX_DEAL_DATA_THREAD_NUMBER);
for (int i = 0; i < Config.Server.MAX_DEAL_DATA_THREAD_NUMBER; i++) {
DataBufferThread dataBufferThread = new DataBufferThread(i);
dataBufferThread.start();

View File

@ -17,6 +17,8 @@ public class Config {
// 数据缓存配置类
public static class Buffer {
// 数据缓存文件目录
public static String DATA_BUFFER_FILE_PARENT_DIR = "/tmp/skywalking/data/buffer";
//每个线程最大缓存数量
public static int PER_THREAD_MAX_BUFFER_NUMBER = 1024;
@ -27,6 +29,33 @@ public class Config {
// 数据冲突时等待时间(单位:毫秒)
public static long DATA_CONFLICT_WAIT_TIME = 10L;
public static long BUFFER_FILE_MAX_LENGTH = 30 * 1024 * 1024;
}
public static class RegisterPersistence {
// 偏移量注册文件的目录
public static String REGISTER_FILE_PARENT_DIRECTORY = "../data/offset";
// 偏移量注册文件名
public static String REGISTER_FILE_NAME = "offset.A";
// 偏移量注册备份文件名
public static String REGISTER_BAK_FILE_NAME = "offset.B";
// 偏移量写入文件等待周期
public static long OFFSET_WRITTEN_FILE_WAIT_CYCLE = 5000L;
}
public static class Persistence {
// 切换文件等待时间
public static long SWITCH_FILE_WAIT_TIME = 5000L;
// 追加EOF标志位的线程数量
public static int MAX_APPEND_EOF_FLAGS_THREAD_NUMBER = 1;
}

View File

@ -1,15 +1,15 @@
package com.ai.cloud.skywalking.reciever.handler;
import com.ai.cloud.skywalking.protocol.util.IntegerAssist;
import com.ai.cloud.skywalking.reciever.buffer.DataBufferThreadContainer;
import com.ai.cloud.skywalking.reciever.conf.Config;
import com.ai.cloud.skywalking.reciever.util.RedisConnector;
import com.ai.cloud.skywalking.protocol.TransportPackager;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import redis.clients.jedis.Jedis;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Arrays;
public class CollectionServerDataHandler extends SimpleChannelInboundHandler<byte[]> {
@ -18,11 +18,8 @@ public class CollectionServerDataHandler extends SimpleChannelInboundHandler<byt
Thread.currentThread().setName("ServerReceiver");
// 当接受到这条消息的是空则忽略
if (msg != null && msg.length >= 0) {
List<byte[]> byteSerializeObjects = TransportPackager.unpack(msg);
if (byteSerializeObjects.size() > 0) {
cacheSerializeObjects(byteSerializeObjects);
if (validateCheckSum(msg)) {
DataBufferThreadContainer.getDataBufferThread().saveTemporarily(unpackCheckSum(msg));
} else {
// 处理错误包
dealFailedPackage(ctx);
@ -30,12 +27,27 @@ public class CollectionServerDataHandler extends SimpleChannelInboundHandler<byt
}
}
private void cacheSerializeObjects(List<byte[]> byteSerializeObjects) {
for (byte[] byteSerializeObject : byteSerializeObjects) {
DataBufferThreadContainer.getDataBufferThread().saveTemporarily(byteSerializeObject);
}
private byte[] unpackCheckSum(byte[] msg) {
return Arrays.copyOfRange(msg, 4, msg.length);
}
private boolean validateCheckSum(byte[] dataPackage) {
byte[] checkSum = generateChecksum(dataPackage, 4);
byte[] originCheckSum = new byte[4];
System.arraycopy(dataPackage, 0, originCheckSum, 0, 4);
return Arrays.equals(checkSum, originCheckSum);
}
private static byte[] generateChecksum(byte[] data, int offset) {
int result = data[offset];
for (int i = offset + 1; i < data.length; i++) {
result ^= data[i];
}
return IntegerAssist.intToBytes(result);
}
private void dealFailedPackage(ChannelHandlerContext ctx) {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().localAddress();
String key = ctx.name() + "-" + socketAddress.getHostName() + ":" + socketAddress.getPort();

View File

@ -0,0 +1,39 @@
package com.ai.cloud.skywalking.reciever.model;
import com.ai.cloud.skywalking.protocol.util.IntegerAssist;
public class BufferDataPackagerGenerator {
private static byte[] SPILT = new byte[] {127, 127, 127, 127};
private static byte[] EOF = null;
private BufferDataPackagerGenerator() {
//DO Nothing
}
public static byte[] generateEOFPackage() {
if (EOF != null) {
return EOF;
}
EOF = generatePackage("EOF".getBytes());
return EOF;
}
public static byte[] pack(byte[] msg) {
return generatePackage(msg);
}
private static byte[] generatePackage(byte[] msg) {
byte[] dataPackage = new byte[msg.length + 8];
// 前四位长度
System.arraycopy(IntegerAssist.intToBytes(msg.length), 0, dataPackage, 0, 4);
// 中间正文
System.arraycopy(msg, 0, dataPackage, 4, msg.length);
// 后四位特殊字符
System.arraycopy(SPILT, 0, dataPackage, msg.length + 4, 4);
return dataPackage;
}
}

View File

@ -0,0 +1,227 @@
package com.ai.cloud.skywalking.reciever.peresistent;
import com.ai.cloud.skywalking.protocol.util.IntegerAssist;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
public class BufferBalePlucker {
private File bufferFile;
private FileInputStream bufferInputStream;
private int currentOffset;
private boolean hasNextBufferBale = false;
private static final byte[] SPILT_BALE_ARRAY = new byte[] {127, 127, 127, 127};
private static final byte[] EOF_BALE_ARRAY = "EOF".getBytes();
private int remainderLength = 0;
private byte[] remainderByte = null;
private Logger logger = LogManager.getLogger(BufferBalePlucker.class);
private PluckerStatus status = PluckerStatus.INITIAL;
public BufferBalePlucker(File bufferFile, int currentOffset) {
this.bufferFile = bufferFile;
this.currentOffset = currentOffset;
if (bufferFile.length() >= currentOffset) {
hasNextBufferBale = true;
}
try {
this.bufferInputStream = new FileInputStream(bufferFile);
bufferInputStream.skip(currentOffset);
} catch (IOException e) {
hasNextBufferBale = false;
}
}
public boolean hasNextBufferBale() {
if (status == PluckerStatus.SUSPEND) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
logger.error("Failed to sleep ", e);
}
}
if (status == PluckerStatus.INITIAL) {
status = PluckerStatus.RUNNING;
return hasNextBufferBale;
}
if (status == PluckerStatus.RUNNING) {
byte[] spiltArray = new byte[4];
try {
bufferInputStream.read(spiltArray);
if (!Arrays.equals(spiltArray, SPILT_BALE_ARRAY)) {
skipToNextBufferBale();
}
} catch (IOException e) {
return false;
}
currentOffset += 4;
}
MemoryRegister.instance().updateOffSet(bufferFile.getName(), currentOffset);
return hasNextBufferBale;
}
public byte[] pluck() throws IOException {
int packageLength = unpackBaleLength();
byte[] dataPackage = unpackDataContext(packageLength);
if (dataPackage == null || dataPackage.length == 0) {
// 文件没有完结,但是已经被处理完成了
return null;
}
if (checkDataPackageIsEOF(dataPackage)) {
hasNextBufferBale = false;
return null;
}
if (logger.isDebugEnabled()) {
logger.debug("Pluck bale size : " + dataPackage.length);
}
return dataPackage;
}
private boolean checkDataPackageIsEOF(byte[] dataPackage) {
if (dataPackage.length == EOF_BALE_ARRAY.length) {
return Arrays.equals(dataPackage, EOF_BALE_ARRAY);
}
return false;
}
private byte[] unpackDataContext(int length) throws IOException {
if (currentOffset >= bufferFile.length()) {
status = PluckerStatus.SUSPEND;
return null;
}
byte[] dataContext = new byte[length];
bufferInputStream.read(dataContext);
currentOffset += length;
return dataContext;
}
private int unpackBaleLength() {
int length;
while (true) {
try {
length = calculateCurrentPackageLength();
if (length > 0 && length < 90000) {
break;
}
skipToNextBufferBale();
} catch (IOException e) {
skipToNextBufferBale();
}
}
return length;
}
private int calculateCurrentPackageLength() throws IOException {
byte[] lengthByte = new byte[4 - remainderLength];
bufferInputStream.read(lengthByte);
currentOffset += 4 - remainderLength;
lengthByte = spliceRemainderByteOfPreviousSkipIfNecessary(lengthByte);
return IntegerAssist.bytesToInt(lengthByte, 0);
}
private byte[] spliceRemainderByteOfPreviousSkipIfNecessary(byte[] lengthByte) {
if (remainderLength != 0) {
byte[] length = Arrays.copyOf(remainderByte, 4);
System.arraycopy(lengthByte, 0, length, remainderLength, lengthByte.length);
remainderLength = 0;
return length;
}
return lengthByte;
}
public void skipToNextBufferBale() {
byte[] previousDataByte = new byte[4];
byte[] currentDataByte = new byte[4];
byte[] compactDataByte = new byte[8];
while (true) {
try {
currentOffset += bufferInputStream.read(currentDataByte);
} catch (IOException e) {
hasNextBufferBale = false;
}
if (Arrays.equals(currentDataByte, SPILT_BALE_ARRAY)) {
remainderLength = 0;
break;
}
//
if (currentOffset + 8000 >= bufferFile.length()) {
status = PluckerStatus.SUSPEND;
break;
}
System.arraycopy(previousDataByte, 0, compactDataByte, 0, 4);
System.arraycopy(currentDataByte, 0, compactDataByte, 4, 4);
int index = bytesIndexOf(compactDataByte, SPILT_BALE_ARRAY, 0, 8);
if (index != -1) {
recodeRemainderByteAndLength(compactDataByte, index);
break;
}
previousDataByte = Arrays.copyOf(currentDataByte, 4);
}
}
private void recodeRemainderByteAndLength(byte[] compactDataByte, int index) {
remainderLength = 8 - 4 - index;
remainderByte = Arrays.copyOfRange(compactDataByte, index + 4, index + 4 + remainderLength);
}
private int bytesIndexOf(byte[] Source, byte[] Search, int fromIndex, int endIndex) {
boolean find = false;
int i;
for (i = fromIndex; i < endIndex - Search.length; i++) {
if (Source[i] == Search[0]) {
find = true;
for (int j = 0; j < Search.length; j++) {
if (Source[i + j] != Search[j]) {
find = false;
}
}
}
if (find) {
break;
}
}
return !find ? -1 : i;
}
public void close() throws IOException {
if (bufferInputStream != null) {
bufferInputStream.close();
}
logger.info("Data in file[{}] has been successfully processed", bufferFile.getName());
boolean deleteSuccess = false;
while (!deleteSuccess) {
deleteSuccess = FileUtils.deleteQuietly(new File(bufferFile.getParent(), bufferFile.getName()));
}
logger.info("Delete file[{}] {}", bufferFile.getName(), (deleteSuccess ? "success" : "failed"));
MemoryRegister.instance().removeEntry(bufferFile.getName());
bufferFile = null;
}
enum PluckerStatus {
INITIAL,
RUNNING,
SUSPEND
}
}

View File

@ -0,0 +1,78 @@
package com.ai.cloud.skywalking.reciever.peresistent;
public class FileRegisterEntry {
private String fileName;
private int offset;
private FileRegisterEntryStatus status;
public FileRegisterEntry() {
}
public FileRegisterEntry(String fileName) {
this.fileName = fileName;
}
public FileRegisterEntry(String fileName, int offset) {
this.fileName = fileName;
this.offset = offset;
}
public FileRegisterEntry(String fileName, int offset, FileRegisterEntryStatus status) {
this.fileName = fileName;
this.offset = offset;
this.status = status;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public FileRegisterEntryStatus getStatus() {
return status;
}
public void setStatus(FileRegisterEntryStatus status) {
this.status = status;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof FileRegisterEntry))
return false;
FileRegisterEntry that = (FileRegisterEntry) o;
return !(getFileName() != null ? !getFileName().equals(that.getFileName()) : that.getFileName() != null);
}
@Override
public int hashCode() {
return getFileName() != null ? getFileName().hashCode() : 0;
}
@Override
public String toString() {
return fileName + '\t' + offset + "\t" + status;
}
public enum FileRegisterEntryStatus {
REGISTER,
UNREGISTER;
}
}

View File

@ -0,0 +1,127 @@
package com.ai.cloud.skywalking.reciever.peresistent;
import com.ai.cloud.skywalking.reciever.conf.Config;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.ai.cloud.skywalking.reciever.conf.Config.RegisterPersistence.*;
public class MemoryRegister {
private Logger logger = LogManager.getLogger(MemoryRegister.class);
private Map<String, FileRegisterEntry> entries = new ConcurrentHashMap<String, FileRegisterEntry>();
private File file;
private static MemoryRegister memoryRegister = new MemoryRegister();
public static MemoryRegister instance() {
return memoryRegister;
}
public void updateOffSet(String fileName, int offset) {
if (logger.isDebugEnabled()) {
logger.debug("Register entry[{}] offset[{}] into the memory register", fileName, offset);
}
if (entries.containsKey(fileName)) {
entries.get(fileName).setOffset(offset);
}
}
public void unRegister(String fileName) {
if (logger.isDebugEnabled()) {
logger.debug("Unregister[{}] from the memory register", fileName);
}
if (entries.containsKey(fileName)) {
entries.get(fileName).setStatus(FileRegisterEntry.FileRegisterEntryStatus.UNREGISTER);
}
}
public void removeEntry(String fileName) {
entries.remove(fileName);
}
public synchronized FileRegisterEntry doRegister(String fileName) {
logger.debug("Begin to register File[{}]", fileName);
FileRegisterEntry entry = null;
// 已经存在entries.
if (entries.containsKey(fileName)) {
logger.debug("FileRegisterEntry[{}] Status:[{}]", entries.get(fileName).getStatus());
// 已经被别的线程处理中
if (entries.get(fileName).getStatus() == FileRegisterEntry.FileRegisterEntryStatus.REGISTER) {
if (logger.isDebugEnabled()) {
logger.debug("Entry[{}] has been register", fileName);
}
} else {
// 没有被别的线程处理
entry = entries.get(fileName);
entry.setStatus(FileRegisterEntry.FileRegisterEntryStatus.REGISTER);
}
} else {
// 以前没有被注册过的
entry = new FileRegisterEntry(fileName, 0, FileRegisterEntry.FileRegisterEntryStatus.REGISTER);
entries.put(fileName, entry);
}
return entry;
}
public Collection<FileRegisterEntry> getEntries() {
return entries.values();
}
public int getOffSet(String fileName) {
if (entries.containsKey(fileName)) {
return entries.get(fileName).getOffset();
}
return -1;
}
private void checkOffSetExists() {
file = new File(REGISTER_FILE_PARENT_DIRECTORY, REGISTER_FILE_NAME);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
logger.error("Create offset filed failed", e);
}
}
}
private MemoryRegister() {
// 在处理数据之前需要初始化处理文件的处理状态
//去掉entries中无法与缓存数据文件匹配的文件
File parentDir = new File(Config.Buffer.DATA_BUFFER_FILE_PARENT_DIR);
//上次未处理的缓存数据文件entries内的数据主要以缓存
List<String> bufferFileNameList = Arrays.asList(parentDir.list());
try {
// 读取offset文件
OffsetFile mainOffsetFile = new OffsetFile(REGISTER_FILE_PARENT_DIRECTORY + File.separator +
REGISTER_FILE_NAME, bufferFileNameList);
OffsetFile backUpOffsetFile = new OffsetFile(REGISTER_FILE_PARENT_DIRECTORY + File.separator +
REGISTER_BAK_FILE_NAME, bufferFileNameList);
if (mainOffsetFile.compare(backUpOffsetFile)) {
entries.putAll(mainOffsetFile.getRegisterEntries());
} else {
entries.putAll(backUpOffsetFile.getRegisterEntries());
}
} catch (FileNotFoundException e) {
logger.error("The offset file does not exist.", e);
checkOffSetExists();
} catch (IOException e) {
logger.error("Read data from offset file failed.", e);
}
}
}

View File

@ -0,0 +1,69 @@
package com.ai.cloud.skywalking.reciever.peresistent;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OffsetFile {
private boolean isComplete = true;
private Map<String, FileRegisterEntry> registerEntries = new HashMap<String, FileRegisterEntry>();
private long lastModifyTime;
public OffsetFile(String offsetFileName, List<String> bufferFileNameList) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(offsetFileName));
String offsetData;
String lastModifyTimeStr = reader.readLine();
if (lastModifyTimeStr == null || lastModifyTimeStr.length() == 0) {
isComplete = false;
return;
}
lastModifyTime = Long.parseLong(lastModifyTimeStr);
while ((offsetData = reader.readLine()) != null && !"EOF".equals(offsetData)) {
String[] ss = offsetData.split("\t");
if (bufferFileNameList.contains(ss[0])) {
registerEntries.put(ss[0], new FileRegisterEntry(ss[0], Integer.valueOf(ss[1]),
FileRegisterEntry.FileRegisterEntryStatus.UNREGISTER));
}
}
if (!"EOF".equals(offsetData)) {
// 文件不完整
isComplete = false;
}
}
public boolean compare(OffsetFile offsetFile) {
if (isComplete && !offsetFile.isComplete) {
if (lastModifyTime > offsetFile.lastModifyTime) {
// 优先选择完整,并且时间是最新的
return true;
} else {
return false;
}
} else if (isComplete && offsetFile.isComplete) {
// 都是完整,则采用时间最新的
if (lastModifyTime > offsetFile.lastModifyTime) {
return true;
} else {
return false;
}
} else if (!isComplete && offsetFile.isComplete) {
//本身没有完成,但是别人完成了,采用别人的
return false;
} else {
// 自己没有完成,别人也没有完成,则比较时间
if (lastModifyTime > offsetFile.lastModifyTime) {
return true;
} else {
return false;
}
}
}
public Map<String, FileRegisterEntry> getRegisterEntries() {
return registerEntries;
}
}

View File

@ -0,0 +1,142 @@
package com.ai.cloud.skywalking.reciever.peresistent;
import com.ai.cloud.skywalking.protocol.SerializedFactory;
import com.ai.cloud.skywalking.protocol.TransportPackager;
import com.ai.cloud.skywalking.protocol.common.AbstractDataSerializable;
import com.ai.cloud.skywalking.protocol.exception.ConvertFailedException;
import com.ai.cloud.skywalking.reciever.conf.Config;
import com.ai.cloud.skywalking.reciever.processor.IProcessor;
import com.ai.cloud.skywalking.reciever.processor.ProcessorFactory;
import com.ai.cloud.skywalking.reciever.selfexamination.ServerHealthCollector;
import com.ai.cloud.skywalking.reciever.selfexamination.ServerHeathReading;
import org.apache.commons.io.comparator.NameFileComparator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PersistenceThread extends Thread {
private Logger logger = LogManager.getLogger(PersistenceThread.class);
private File bufferFile = null;
public PersistenceThread(int trdIndex) {
super("PersistentThread" + trdIndex);
}
@Override
public void run() {
while (true) {
bufferFile = chooseDealBufferFile();
if (bufferFile == null) {
try {
Thread.sleep(Config.Persistence.SWITCH_FILE_WAIT_TIME);
} catch (InterruptedException e) {
logger.error("Failure sleep.", e);
}
continue;
}
int offset = acquireOffset();
BufferBalePlucker bufferBalePlucker = new BufferBalePlucker(bufferFile, offset);
while (bufferBalePlucker.hasNextBufferBale()) {
try {
Map<Integer, List<AbstractDataSerializable>> spans = unSerializeSpans(bufferBalePlucker.pluck());
System.out.println(spans.size());
//handleSpans(spans);
} catch (ConvertFailedException e) {
bufferBalePlucker.skipToNextBufferBale();
} catch (IOException e) {
logger.error("The data file I/O exception.", e);
ServerHealthCollector.getCurrentHeathReading(null)
.updateData(ServerHeathReading.ERROR, e.getMessage());
}
}
try {
bufferBalePlucker.close();
} catch (IOException e) {
logger.error("The data file I/O exception.", e);
ServerHealthCollector.getCurrentHeathReading(null).updateData(ServerHeathReading.ERROR, e.getMessage());
}
try {
Thread.sleep(Config.Persistence.SWITCH_FILE_WAIT_TIME);
} catch (InterruptedException e) {
logger.error("Failure sleep.", e);
}
}
}
private int acquireOffset() {
int offset;
offset = MemoryRegister.instance().getOffSet(bufferFile.getName());
if (offset == -1 || offset == 0) {
offset = 0;
}
return offset;
}
private void handleSpans(Map<Integer, List<AbstractDataSerializable>> spans) {
for (Map.Entry<Integer, List<AbstractDataSerializable>> entry : spans.entrySet()) {
IProcessor processor = ProcessorFactory.chooseProcessor(entry.getKey());
if (processor != null) {
processor.process(entry.getValue());
}
}
}
private Map<Integer, List<AbstractDataSerializable>> unSerializeSpans(byte[] byteData)
throws ConvertFailedException {
Map<Integer, List<AbstractDataSerializable>> spans = new HashMap<Integer, List<AbstractDataSerializable>>();
if (byteData == null || byteData.length == 0) {
return spans;
}
List<byte[]> serializeData = TransportPackager.unpackDataBody(byteData);
for (byte[] dataBytes : serializeData) {
AbstractDataSerializable abstractDataSerializable = SerializedFactory.unSerialize(dataBytes);
if (spans.get(abstractDataSerializable.getDataType()) == null) {
spans.put(abstractDataSerializable.getDataType(), new ArrayList<AbstractDataSerializable>());
}
spans.get(abstractDataSerializable.getDataType()).add(abstractDataSerializable);
}
return spans;
}
private File chooseDealBufferFile() {
File file1 = null;
File parentDir = new File(Config.Buffer.DATA_BUFFER_FILE_PARENT_DIR);
NameFileComparator sizeComparator = new NameFileComparator();
File[] dataFileList = sizeComparator.sort(parentDir.listFiles());
if (dataFileList == null) {
return null;
}
for (File file : dataFileList) {
if (file.getName().startsWith(".")) {
continue;
}
if (MemoryRegister.instance().doRegister(file.getName()) == null) {
if (logger.isDebugEnabled())
logger.debug("The file [{}] is being used by another thread ", file);
continue;
}
if (logger.isDebugEnabled()) {
logger.debug("Begin to deal data file [{}]", file.getName());
}
file1 = file;
break;
}
return file1;
}
}

View File

@ -0,0 +1,12 @@
package com.ai.cloud.skywalking.reciever.peresistent;
import com.ai.cloud.skywalking.reciever.conf.Config;
public class PersistenceThreadLauncher {
public static void doLaunch() {
new RegisterPersistenceThread().start();
for (int i = 0; i < Config.Server.MAX_DEAL_DATA_THREAD_NUMBER; i++) {
new PersistenceThread(i).start();
}
}
}

View File

@ -0,0 +1,98 @@
package com.ai.cloud.skywalking.reciever.peresistent;
import com.ai.cloud.skywalking.reciever.selfexamination.ServerHealthCollector;
import com.ai.cloud.skywalking.reciever.selfexamination.ServerHeathReading;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import static com.ai.cloud.skywalking.reciever.conf.Config.RegisterPersistence.*;
public class RegisterPersistenceThread extends Thread {
private Logger logger = LogManager.getLogger(RegisterPersistenceThread.class);
private File offsetFile;
private File bakOffsetFile;
private BufferedWriter offsetBufferWriter;
private boolean isSwitch = true;
public RegisterPersistenceThread() {
super("RegisterPersistenceThread");
File offsetParentDir = new File(REGISTER_FILE_PARENT_DIRECTORY);
if (!offsetParentDir.exists()) {
offsetParentDir.mkdirs();
}
offsetFile = new File(REGISTER_FILE_PARENT_DIRECTORY, REGISTER_FILE_NAME);
bakOffsetFile = new File(REGISTER_FILE_PARENT_DIRECTORY, REGISTER_BAK_FILE_NAME);
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(OFFSET_WRITTEN_FILE_WAIT_CYCLE);
} catch (InterruptedException e) {
logger.error("Sleep failure", e);
}
chooseOffsetFile();
appendingTimestamp();
wirteFileRegisterEntries();
closeAndReleaseResource();
ServerHealthCollector.getCurrentHeathReading(null)
.updateData(ServerHeathReading.INFO, "flush memory register to file.");
}
}
private void chooseOffsetFile() {
try {
if (isSwitch) {
offsetBufferWriter = new BufferedWriter(new FileWriter(offsetFile));
} else {
offsetBufferWriter = new BufferedWriter(new FileWriter(bakOffsetFile));
}
isSwitch = !isSwitch;
} catch (IOException e) {
logger.error("Write The offset file anomalies.");
}
}
private void appendingTimestamp() {
try {
offsetBufferWriter.write(String.valueOf(System.currentTimeMillis()) + "\n");
} catch (IOException e) {
logger.error("Write The offset file anomalies.");
}
}
private void wirteFileRegisterEntries() {
Collection<FileRegisterEntry> fileRegisterEntries = MemoryRegister.instance().getEntries();
for (FileRegisterEntry fileRegisterEntry : fileRegisterEntries) {
try {
offsetBufferWriter.write(fileRegisterEntry.toString() + "\n");
} catch (IOException e) {
logger.error("Write file register entry to offset file failure", e);
}
}
}
private void closeAndReleaseResource() {
try {
offsetBufferWriter.write("EOF\n");
offsetBufferWriter.flush();
} catch (IOException e) {
logger.error("Flush offset file failure", e);
} finally {
try {
offsetBufferWriter.close();
} catch (IOException e) {
logger.error("close offset file failure", e);
}
}
}
}

View File

@ -14,6 +14,7 @@ import java.util.List;
import static com.ai.cloud.skywalking.reciever.util.SpanUtil.getTSBySpanTraceId;
@DefaultProcessor
public class AckSpanProcessor extends AbstractSpanProcessor {
@Override

View File

@ -0,0 +1,12 @@
package com.ai.cloud.skywalking.reciever.processor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultProcessor {
boolean defaultProcessor() default true;
}

View File

@ -8,15 +8,19 @@ import java.util.Map;
import java.util.ServiceLoader;
public class ProcessorFactory {
private static Logger logger = LogManager.getLogger(ProcessorFactory.class);
private static Logger logger = LogManager.getLogger(ProcessorFactory.class);
private static Map<Integer, IProcessor> type_processor_mapping = new HashMap<Integer, IProcessor>();
static {
ServiceLoader<IProcessor> processors = ServiceLoader.load(IProcessor.class);
for (IProcessor processor : processors) {
logger.info("Init protocol type and processor mapping : {} --> {}.", processor.getProtocolType(), processor.getClass().getName());
type_processor_mapping.put(processor.getProtocolType(), processor);
DefaultProcessor defaultProcessor = processor.getClass().getAnnotation(DefaultProcessor.class);
IProcessor processor1 = type_processor_mapping.get(processor.getProtocolType());
if (processor1 == null || (defaultProcessor != null && !defaultProcessor.defaultProcessor())) {
logger.info("Init protocol type and processor mapping : {} --> {}.", processor.getProtocolType(),
processor.getClass().getName());
type_processor_mapping.put(processor.getProtocolType(), processor);
}
}
}

View File

@ -14,6 +14,7 @@ import java.util.List;
import static com.ai.cloud.skywalking.reciever.util.SpanUtil.getTSBySpanTraceId;
@DefaultProcessor
public class RequestSpanProcessor extends AbstractSpanProcessor {
@ -35,7 +36,8 @@ public class RequestSpanProcessor extends AbstractSpanProcessor {
} else {
columnName = requestSpan.getParentLevel() + "." + requestSpan.getLevelId();
}
put.addColumn(Bytes.toBytes(Config.HBaseConfig.FAMILY_COLUMN_NAME), Bytes.toBytes(columnName), requestSpan.getData());
put.addColumn(Bytes.toBytes(Config.HBaseConfig.FAMILY_COLUMN_NAME), Bytes.toBytes(columnName),
requestSpan.getData());
puts.add(put);
}

View File

@ -11,16 +11,26 @@ buffer.max_wait_time=5000
#数据冲突时等待时间(单位:毫秒)
buffer.data_conflict_wait_time=10
#数据缓存文件目录
buffer.data_buffer_file_parent_directory=D:/test-data/data/buffer
buffer.data_buffer_file_parent_dir=/tmp/skywalking/data/buffer
#缓存数据文件最大长度(单位:byte)
buffer.data_file_max_length=104857600
#每次Flush的缓存数据的个数
buffer.flush_number_of_cache=30
buffer.buffer_file_max_length=104857600
#每次缓存数据写入失败,最大尝试时间
buffer.write_data_failure_retry_interval = 10000
#数据包的最大限制
datapackage.max_data_package=1048576
#切换数据文件,等待时间(单位:毫秒)
persistence.switch_file_wait_time=5000
#追加EOF标志位的线程数量
persistence.max_append_eof_flags_thread_number=1
#偏移量注册文件的目录
registerpersistence.register_file_parent_directory=/tmp/skywalking/data/offset
#偏移量注册文件名
registerpersistence.register_file_name=offset.txt
#偏移量注册备份文件名
registerpersistence.register_bak_file_name=offset.txt.bak
#偏移量写入文件等待周期(单位:毫秒)
registerpersistence.offset_written_file_wait_cycle=5000
#hbase表名
hbaseconfig.table_name=sw-call-chain-new
@ -50,4 +60,4 @@ redis.edis_max_total=20
#告警检查器:异常告警检查
alarm.checker.turn_on_exception_checker=true
#告警检查器:执行时间超时告警检查
alarm.checker.turn_on_execute_time_checker=true
alarm.checker.turn_on_execute_time_checker=true

View File

@ -0,0 +1,74 @@
package test.com.ai.cloud.skywalking.reciever.peresistent;
import com.ai.cloud.skywalking.protocol.util.IntegerAssist;
import com.ai.cloud.skywalking.reciever.peresistent.BufferBalePlucker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNull;
public class BufferBalePluckerTest {
private File file;
@Before
public void initData() throws IOException {
file = new File("/tmp", "test.file");
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte[] bytes = "HelloWorld".getBytes();
byte[] packageByte = Arrays.copyOf(IntegerAssist.intToBytes(bytes.length), bytes.length + 4 + 4);
System.arraycopy(bytes, 0, packageByte, 4, bytes.length);
System.arraycopy(new byte[] {127, 127, 127, 127}, 0, packageByte, bytes.length + 4, 4);
fileOutputStream.write(packageByte);
fileOutputStream.write(generatePackage("EOF".getBytes()));
fileOutputStream.close();
}
private static byte[] generatePackage(byte[] msg) {
byte[] dataPackage = new byte[msg.length + 8];
// 前四位长度
System.arraycopy(IntegerAssist.intToBytes(msg.length), 0, dataPackage, 0, 4);
// 中间正文
System.arraycopy(msg, 0, dataPackage, 4, msg.length);
// 后四位特殊字符
System.arraycopy(new byte[] {127, 127, 127, 127}, 0, dataPackage, msg.length + 4, 4);
return dataPackage;
}
@Test
public void pluck() throws Exception {
BufferBalePlucker plucker = new BufferBalePlucker(file, 0);
while (plucker.hasNextBufferBale()) {
byte[] data = plucker.pluck();
if (data == null)
continue;
assertArrayEquals("HelloWorld".getBytes(), data);
}
}
@Test
public void skipToNextBufferBale() throws Exception {
BufferBalePlucker plucker = new BufferBalePlucker(file, 3);
plucker.skipToNextBufferBale();
assertNull(plucker.pluck());
}
@After
public void clearData() {
file.deleteOnExit();
}
}