1. 소개
2. 사용 기술
3. 아키텍처
4. 개발
4-1. 코드
4-2. 화면
5. 성능 평가
6. 결과
허가형 블록체인의 실행환경에서 발생하는 이벤트(Contract Event, Block Event)를 수신하여 시간,공간,참가자,트랜잭션 데이터로 분류하여 오프체인 데이터베이스에 저장한다. 이를 통해 허가형 블록체인에 적용 가능한 분류별 데이터로 외부 서드파티 시스템과 함께 활용할 수 있으며, 블록체인 네트워크에 발생하는 부하를 해소할 수 있다.
- 블록체인 : Hyperledger Fabric, Fabric Gateway SDK
- 시스템 : Gin(Golang)
- 오프체인 데이터베이스 : MySQL
- 테스트 : 쉘스크립트, pandas
아키텍처 | 시퀀스 다이어그램 |
---|---|
func Connect() {
clientConnection := newGrpcConnection()
id := newIdentity()
sign := newSign()
gateway, err := client.Connect(
id,
client.WithSign(sign),
client.WithClientConnection(clientConnection),
client.WithEvaluateTimeout(5*time.Second),
client.WithEndorseTimeout(15*time.Second),
client.WithSubmitTimeout(5*time.Second),
client.WithCommitStatusTimeout(1*time.Minute),
)
if err != nil {
panic(err)
}
network = gateway.GetNetwork(channelName)
contract = network.GetContract(chaincodeName)
fmt.Printf("*** first:%s\n", contract)
ctx, _ := context.WithCancel(context.Background())
startChaincodeEventListening(ctx, network)
}
func startChaincodeEventListening(ctx context.Context, network *client.Network) {
blockEvents, blockErr := network.BlockEvents(ctx, client.WithStartBlock(1))
if blockErr != nil {
panic(fmt.Errorf("failed to start chaincode event listening: %w", blockErr))
}
fmt.Println("\n*** Start Block event listening")
ccEvents, ccErr := network.ChaincodeEvents(ctx, chaincodeName)
if ccErr != nil {
panic(fmt.Errorf("failed to start block event listening: %w", ccErr))
}
fmt.Println("\n*** Start chaincode event listening")
go func() {
for event := range blockEvents {
hashBytes := event.GetHeader().GetDataHash()
hashString := fmt.Sprintf("%x", hashBytes)
blockNumber := event.GetHeader().GetNumber()
fmt.Printf("\n<-- Block event received: \n Received block number : %d \n Received block hash - %s\n", blockNumber, hashString)
}
}()
go func() {
outputFile := "process.txt"
file, err := os.OpenFile(outputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
for event := range ccEvents {
startTime := time.Now().UnixNano()
startTimeString := fmt.Sprintf("%d", startTime)
eventStr := formatJSON(event.Payload)
var eventData Transaction
err := json.Unmarshal(event.Payload, &eventData)
if err != nil {
log.Println(err.Error())
}
switch event.EventName {
case "SellVehicle":
db.InsertTemporalData(eventData.toTemporalData())
db.InsertSpatialData(eventData.toSpatialData())
db.InsertParticipantData(eventData.toParticipantData())
db.InsertTransactionData(eventData.toTransactionData())
break
case "BuyVehicle":
db.UpdateTemporalData(eventData.toTemporalData())
db.UpdateSpatialData(eventData.toSpatialData())
db.UpdateParticipantData(eventData.toParticipantData())
db.UpdateTransactionData(eventData.toTransactionData())
break
case "CompromiseTransaction":
db.UpdateTemporalData(eventData.toTemporalData())
db.UpdateSpatialData(eventData.toSpatialData())
db.UpdateParticipantData(eventData.toParticipantData())
db.UpdateTransactionData(eventData.toTransactionData())
break
default:
fmt.Printf(event.EventName)
}
fmt.Printf("\n<-- Chaincode event received: %s - %s\n", event.EventName, eventStr)
endTime := time.Now().UnixNano()
endTimeString := fmt.Sprintf("%d", endTime)
if _, err := file.WriteString(startTimeString + " " + endTimeString + "\n"); err != nil {
log.Println(err)
}
}
}()
}
정보 | |
---|---|
판매 명세서 |
|
이벤트 수신 로그 |
|
이벤트 처리 로그 |
|
분류별 검색 필터 대시보드 |
본 프로젝트에서는 하이퍼레저 패브릭 네트워크와 연결하기 위해 Fabric Gateway SDK를 활용하였으며,
명령어 기반 실행과 SDK 기반 트랜잭션 성능을 평가하였다.
- 비교 방법 : 실행 속도
- 초기 블록 높이 : 5
- 실행 횟수 : 100회
- 데이터는 쉘스크립트에서 파이프라인을 통해 기록하고 이를 쉘스크립트를 통해 min, 25%, avg, 75%, max 로 종합, 정리함.
- 기존
- 기존 체인코드는 invoke 시 이벤트를 발생시키지 않도록 구현
- query 시 단일 데이터에 대해 key기반 조회 수행
- 제안
- 제안 체인코드는 invoke 시 이벤트를 발생시키도록 구현
- query 시 단일 데이터에 대해 key기반 조회 수행
- process는 이벤트로 발생한 데이터를 처리하는 시간을 측정
- CLI 첫 값의 latency가 매우 큼
- 아마 connection 문제일 듯, Gateway는 connection pool이 존재함.
- 99% line의 값과 maximum값의 차이가 매우 큼, 이는 한 값이 매우 튐을 추측할 수 있음.
- => 결과적으로 첫 번째 튀는 값을 제외한 나머지들을 통해서 min,25%, avg, 75%, max 값을 평가함.
제안 invoke | 제안 process | 제안 query | 기존 invoke | 기존 query | |
---|---|---|---|---|---|
Minimum | 114.671 | 2.634 | 0.0013 | 107.363 | 75.317 |
25% | 140.171 | 4.624 | 0.0015 | 137.604 | 104.527 |
Average | 158.730 | 7.562 | 0.0020 | 154.359 | 118.426 |
75% | 169.571 | 8.575 | 0.0022 | 168.678 | 128.319 |
Maximum | 214.056 | 60.633 | 0.0074 | 232.173 | 234.933 |
단위 : ms
- invoke시 약 12ms만큼 추가 시간이 소요, 그러나, query 시 약 110ms만큼 성능을 향상 시킬 수 있음
- 이는 블록체인의 체인 형태로 linked-list와 연결을 타고 올라가는 구조가 아닌 외부 오프체인 데이터베이스의 조회 메커니즘을 활용할 수 있기 때문임(MySQL, 인덱스 기반 조회)
- 따라서, 트랜잭션보다 조회가 자주 일어나는 일반적인 시스템에 더욱 큰 성능 이점을 가질 수 있으며 블록체인 네트워크에 추가적인 부하를 발생시키지 않음.
- 또한, 블록체인 네트워크의 실행환경에서 발생하는 이벤트를 기반으로 동작하므로 온체인 데이터 - 오프체인 데이터의 동기화에 이점이 있음.
- 다만, 데이터에 대한 무결성, 신뢰성, 불변성에 대한 부분이 떨어질 수 있으나 오프체인의 모든 데이터가 온체인에 동기화 되어 있기 때문에 교차 검증을 통해 무결성, 신뢰성을 검증할 수 있음.