Commit 1a47e08d authored by caopingcp's avatar caopingcp Committed by vipwzw

raft prune wal

parent 90d2f148
This diff is collapsed.
...@@ -38,7 +38,7 @@ enableTxQuickIndex=true ...@@ -38,7 +38,7 @@ enableTxQuickIndex=true
seeds=["127.0.0.1:13802"] seeds=["127.0.0.1:13802"]
enable=false enable=false
isSeed=false isSeed=false
serverStart=true serverStart=false
innerSeedEnable=false innerSeedEnable=false
useGithub=false useGithub=false
innerBounds=300 innerBounds=300
...@@ -108,12 +108,14 @@ peersURL="http://127.0.0.1:9021" ...@@ -108,12 +108,14 @@ peersURL="http://127.0.0.1:9021"
# raft共识用到,指示raft集群中只读节点的IP(只同步日志,不参与raft共识) # raft共识用到,指示raft集群中只读节点的IP(只同步日志,不参与raft共识)
readOnlyPeersURL="" readOnlyPeersURL=""
addPeersURL="" addPeersURL=""
#raft共识用到,默认raft中多少条记录打包一个snapshot(这里为了测试调整小一点) #raft中多少条记录打包一个snapshot,默认为10000(这里为了测试调整小一点)
defaultSnapCount=2 defaultSnapCount=2
#raft共识用到,默认raft中写区块时间间隔 #raft中写区块时间间隔,默认为1秒
writeBlockSeconds=1 writeBlockSeconds=1
#raft共识用到,默认raft中leader发送心跳包时间间隔 #raft中leader发送心跳包时间间隔,默认为1秒
heartbeatTick=1 heartbeatTick=1
#raft中leader打包空区块的时间间隔,默认为0,表示不打包空区块
emptyBlockInterval=120
# =============== raft共识配置参数 =========================== # =============== raft共识配置参数 ===========================
[store] [store]
...@@ -134,7 +136,7 @@ dbCache=16 ...@@ -134,7 +136,7 @@ dbCache=16
signType="secp256k1" signType="secp256k1"
[wallet.sub.ticket] [wallet.sub.ticket]
minerdisable=false minerdisable=true
minerwhitelist=["*"] minerwhitelist=["*"]
minerWaitTime="1s" minerWaitTime="1s"
......
...@@ -19,27 +19,29 @@ var ( ...@@ -19,27 +19,29 @@ var (
rlog = log.New("module", "raft") rlog = log.New("module", "raft")
genesis string genesis string
genesisBlockTime int64 genesisBlockTime int64
defaultSnapCount uint64 = 1000 defaultSnapCount uint64 = 10000
snapshotCatchUpEntriesN uint64 = 1000 snapshotCatchUpEntriesN uint64 = 10000
writeBlockSeconds int64 = 1 writeBlockSeconds int64 = 1
heartbeatTick = 1 heartbeatTick = 1
isLeader = false emptyBlockInterval int64
isLeader = false
mux atomic.Value mux atomic.Value
confChangeC chan raftpb.ConfChange confChangeC chan raftpb.ConfChange
) )
type subConfig struct { type subConfig struct {
Genesis string `json:"genesis"` Genesis string `json:"genesis"`
GenesisBlockTime int64 `json:"genesisBlockTime"` GenesisBlockTime int64 `json:"genesisBlockTime"`
NodeID int64 `json:"nodeID"` NodeID int64 `json:"nodeID"`
PeersURL string `json:"peersURL"` PeersURL string `json:"peersURL"`
RaftAPIPort int64 `json:"raftAPIPort"` RaftAPIPort int64 `json:"raftAPIPort"`
IsNewJoinNode bool `json:"isNewJoinNode"` IsNewJoinNode bool `json:"isNewJoinNode"`
ReadOnlyPeersURL string `json:"readOnlyPeersURL"` ReadOnlyPeersURL string `json:"readOnlyPeersURL"`
AddPeersURL string `json:"addPeersURL"` AddPeersURL string `json:"addPeersURL"`
DefaultSnapCount int64 `json:"defaultSnapCount"` DefaultSnapCount int64 `json:"defaultSnapCount"`
WriteBlockSeconds int64 `json:"writeBlockSeconds"` WriteBlockSeconds int64 `json:"writeBlockSeconds"`
HeartbeatTick int32 `json:"heartbeatTick"` HeartbeatTick int32 `json:"heartbeatTick"`
EmptyBlockInterval int64 `json:"emptyBlockInterval"`
} }
func init() { func init() {
...@@ -64,7 +66,7 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -64,7 +66,7 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
//TODO 当传入的参数异常时,返回给主函数的是个nil,这时候需要做异常处理 //TODO 当传入的参数异常时,返回给主函数的是个nil,这时候需要做异常处理
return nil return nil
} }
// 默认1000个Entry打一个snapshot // 默认10000个Entry打一个snapshot
if subcfg.DefaultSnapCount > 0 { if subcfg.DefaultSnapCount > 0 {
defaultSnapCount = uint64(subcfg.DefaultSnapCount) defaultSnapCount = uint64(subcfg.DefaultSnapCount)
snapshotCatchUpEntriesN = uint64(subcfg.DefaultSnapCount) snapshotCatchUpEntriesN = uint64(subcfg.DefaultSnapCount)
...@@ -77,6 +79,11 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -77,6 +79,11 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
if subcfg.HeartbeatTick > 0 { if subcfg.HeartbeatTick > 0 {
heartbeatTick = int(subcfg.HeartbeatTick) heartbeatTick = int(subcfg.HeartbeatTick)
} }
// write empty block interval in second
if subcfg.EmptyBlockInterval > 0 {
emptyBlockInterval = subcfg.EmptyBlockInterval
}
var b *Client var b *Client
getSnapshot := func() ([]byte, error) { return b.getSnapshot() } getSnapshot := func() ([]byte, error) { return b.getSnapshot() }
// raft集群的建立,1. 初始化两条channel: propose channel用于客户端和raft底层交互, commit channel用于获取commit消息 // raft集群的建立,1. 初始化两条channel: propose channel用于客户端和raft底层交互, commit channel用于获取commit消息
...@@ -96,12 +103,13 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -96,12 +103,13 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
//采用context来统一管理所有服务 //采用context来统一管理所有服务
ctx, stop := context.WithCancel(context.Background()) ctx, stop := context.WithCancel(context.Background())
// propose channel // propose channel
proposeC := make(chan *types.Block) proposeC := make(chan BlockInfo)
confChangeC = make(chan raftpb.ConfChange) confChangeC = make(chan raftpb.ConfChange)
commitC, errorC, snapshotterReady, validatorC := NewRaftNode(ctx, int(subcfg.NodeID), subcfg.IsNewJoinNode, peers, readOnlyPeers, addPeers, getSnapshot, proposeC, confChangeC) node, commitC, errorC, snapshotterReady, validatorC := NewRaftNode(ctx, int(subcfg.NodeID), subcfg.IsNewJoinNode, peers, readOnlyPeers, addPeers, getSnapshot, proposeC, confChangeC)
//启动raft删除节点操作监听 //启动raft删除节点操作监听
go serveHTTPRaftAPI(ctx, int(subcfg.RaftAPIPort), confChangeC, errorC) go serveHTTPRaftAPI(ctx, int(subcfg.RaftAPIPort), confChangeC, errorC)
// 监听commit channel,取block // 监听commit channel,取block
b = NewBlockstore(ctx, cfg, <-snapshotterReady, proposeC, commitC, errorC, validatorC, stop) b = NewBlockstore(ctx, cfg, <-snapshotterReady, proposeC, commitC, errorC, validatorC, stop)
node.SetClient(b)
return b return b
} }
...@@ -6,6 +6,7 @@ package raft ...@@ -6,6 +6,7 @@ package raft
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
...@@ -14,7 +15,6 @@ import ( ...@@ -14,7 +15,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/33cn/chain33/types"
"github.com/coreos/etcd/etcdserver/stats" "github.com/coreos/etcd/etcdserver/stats"
"github.com/coreos/etcd/pkg/fileutil" "github.com/coreos/etcd/pkg/fileutil"
typec "github.com/coreos/etcd/pkg/types" typec "github.com/coreos/etcd/pkg/types"
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
"github.com/coreos/etcd/snap" "github.com/coreos/etcd/snap"
"github.com/coreos/etcd/wal" "github.com/coreos/etcd/wal"
"github.com/coreos/etcd/wal/walpb" "github.com/coreos/etcd/wal/walpb"
"github.com/golang/protobuf/proto"
) )
var ( var (
...@@ -32,9 +31,10 @@ var ( ...@@ -32,9 +31,10 @@ var (
) )
type raftNode struct { type raftNode struct {
proposeC <-chan *types.Block client *Client
proposeC <-chan BlockInfo
confChangeC <-chan raftpb.ConfChange confChangeC <-chan raftpb.ConfChange
commitC chan<- *types.Block commitC chan<- *BlockInfo
errorC chan<- error errorC chan<- error
id int id int
bootstrapPeers []string bootstrapPeers []string
...@@ -65,13 +65,21 @@ type raftNode struct { ...@@ -65,13 +65,21 @@ type raftNode struct {
restartC chan struct{} restartC chan struct{}
} }
type Node struct {
*raftNode
}
func (node *Node) SetClient(client *Client) {
node.client = client
}
// NewRaftNode create raft node // NewRaftNode create raft node
func NewRaftNode(ctx context.Context, id int, join bool, peers []string, readOnlyPeers []string, addPeers []string, getSnapshot func() ([]byte, error), proposeC <-chan *types.Block, func NewRaftNode(ctx context.Context, id int, join bool, peers []string, readOnlyPeers []string, addPeers []string, getSnapshot func() ([]byte, error), proposeC <-chan BlockInfo,
confChangeC <-chan raftpb.ConfChange) (<-chan *types.Block, <-chan error, <-chan *snap.Snapshotter, <-chan bool) { confChangeC <-chan raftpb.ConfChange) (*Node, <-chan *BlockInfo, <-chan error, <-chan *snap.Snapshotter, <-chan bool) {
rlog.Info("Enter consensus raft") rlog.Info("Enter consensus raft")
// commit channel // commit channel
commitC := make(chan *types.Block) commitC := make(chan *BlockInfo)
errorC := make(chan error) errorC := make(chan error)
rc := &raftNode{ rc := &raftNode{
proposeC: proposeC, proposeC: proposeC,
...@@ -94,7 +102,7 @@ func NewRaftNode(ctx context.Context, id int, join bool, peers []string, readOnl ...@@ -94,7 +102,7 @@ func NewRaftNode(ctx context.Context, id int, join bool, peers []string, readOnl
} }
go rc.startRaft() go rc.startRaft()
return commitC, errorC, rc.snapshotterReady, rc.validatorC return &Node{rc}, commitC, errorC, rc.snapshotterReady, rc.validatorC
} }
// 启动raft节点 // 启动raft节点
...@@ -224,7 +232,7 @@ func (rc *raftNode) serveChannels() { ...@@ -224,7 +232,7 @@ func (rc *raftNode) serveChannels() {
if !ok { if !ok {
rc.proposeC = nil rc.proposeC = nil
} else { } else {
out, err := proto.Marshal(prop) out, err := json.Marshal(prop)
if err != nil { if err != nil {
rlog.Error(fmt.Sprintf("failed to marshal block:%v ", err.Error())) rlog.Error(fmt.Sprintf("failed to marshal block:%v ", err.Error()))
} }
...@@ -257,6 +265,10 @@ func (rc *raftNode) serveChannels() { ...@@ -257,6 +265,10 @@ func (rc *raftNode) serveChannels() {
case <-ticker.C: case <-ticker.C:
rc.node.Tick() rc.node.Tick()
case rd := <-rc.node.Ready(): case rd := <-rc.node.Ready():
if !rc.checkEntries(rd.Entries) || !rc.checkEntries(rd.CommittedEntries) {
rc.stop()
return
}
rc.wal.Save(rd.HardState, rd.Entries) rc.wal.Save(rd.HardState, rd.Entries)
if !raft.IsEmptySnap(rd.Snapshot) { if !raft.IsEmptySnap(rd.Snapshot) {
rc.saveSnap(rd.Snapshot) rc.saveSnap(rd.Snapshot)
...@@ -283,6 +295,25 @@ func (rc *raftNode) serveChannels() { ...@@ -283,6 +295,25 @@ func (rc *raftNode) serveChannels() {
} }
} }
func (rc *raftNode) checkEntries(ents []raftpb.Entry) bool {
for i := range ents {
if ents[i].Type == raftpb.EntryNormal && len(ents[i].Data) != 0 {
info := &BlockInfo{}
if err := json.Unmarshal(ents[i].Data, info); err != nil {
rlog.Error("checkEntries Unmarshal BlockInfo fail", "err", err)
return false
}
if rc.client != nil {
if !rc.client.CheckBlockInfo(info) {
rlog.Error("checkEntries CheckBlockInfo fail")
return false
}
}
}
}
return true
}
func (rc *raftNode) updateValidator() { func (rc *raftNode) updateValidator() {
//TODO 这块监听后期需要根据场景进行优化? //TODO 这块监听后期需要根据场景进行优化?
...@@ -325,6 +356,7 @@ func (rc *raftNode) updateValidator() { ...@@ -325,6 +356,7 @@ func (rc *raftNode) updateValidator() {
} }
} }
func (rc *raftNode) Status() raft.Status { func (rc *raftNode) Status() raft.Status {
rc.stopMu.RLock() rc.stopMu.RLock()
defer rc.stopMu.RUnlock() defer rc.stopMu.RUnlock()
...@@ -383,15 +415,13 @@ func (rc *raftNode) maybeTriggerSnapshot() { ...@@ -383,15 +415,13 @@ func (rc *raftNode) maybeTriggerSnapshot() {
return return
} }
appliedIndex := rc.appliedIndex rlog.Info(fmt.Sprintf("start snapshot [applied index: %d | last snapshot index: %d]", rc.appliedIndex, rc.snapshotIndex))
snapshotIndex := rc.snapshotIndex data, err := rc.getSnapshot()
confState := rc.confState
rlog.Info(fmt.Sprintf("start snapshot [applied index: %d | last snapshot index: %d]", appliedIndex, snapshotIndex))
ents, err := rc.raftStorage.Entries(appliedIndex, appliedIndex+1, 2)
if err != nil { if err != nil {
rlog.Error(fmt.Sprintf("Err happened when get snapshot:%v", err.Error())) rlog.Error("getSnapshot fail", "err", err)
panic(err)
} }
snapShot, err := rc.raftStorage.CreateSnapshot(appliedIndex, &confState, ents[0].Data) snapShot, err := rc.raftStorage.CreateSnapshot(rc.appliedIndex, &rc.confState, data)
if err != nil { if err != nil {
panic(err) panic(err)
} }
...@@ -400,15 +430,15 @@ func (rc *raftNode) maybeTriggerSnapshot() { ...@@ -400,15 +430,15 @@ func (rc *raftNode) maybeTriggerSnapshot() {
} }
compactIndex := uint64(1) compactIndex := uint64(1)
if appliedIndex > snapshotCatchUpEntriesN { if rc.appliedIndex > snapshotCatchUpEntriesN {
compactIndex = appliedIndex - snapshotCatchUpEntriesN compactIndex = rc.appliedIndex - snapshotCatchUpEntriesN
} }
if err := rc.raftStorage.Compact(compactIndex); err != nil { if err := rc.raftStorage.Compact(compactIndex); err != nil {
panic(err) panic(err)
} }
rlog.Info(fmt.Sprintf("compacted log at index %d", compactIndex)) rlog.Info(fmt.Sprintf("compacted log at index %d", compactIndex))
rc.snapshotIndex = appliedIndex rc.snapshotIndex = rc.appliedIndex
} }
func (rc *raftNode) publishSnapshot(snapshotToSave raftpb.Snapshot) { func (rc *raftNode) publishSnapshot(snapshotToSave raftpb.Snapshot) {
...@@ -487,12 +517,13 @@ func (rc *raftNode) publishEntries(ents []raftpb.Entry) bool { ...@@ -487,12 +517,13 @@ func (rc *raftNode) publishEntries(ents []raftpb.Entry) bool {
break break
} }
// 解码 // 解码
block := &types.Block{} info := &BlockInfo{}
if err := proto.Unmarshal(ents[i].Data, block); err != nil { if err := json.Unmarshal(ents[i].Data, info); err != nil {
rlog.Error(fmt.Sprintf("failed to unmarshal: %v", err.Error())) rlog.Error("Unmarshal BlockInfo fail", "err", err)
break
} }
select { select {
case rc.commitC <- block: case rc.commitC <- info:
case <-rc.ctx.Done(): case <-rc.ctx.Done():
return false return false
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package main package main
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"log" "log"
...@@ -18,7 +19,6 @@ import ( ...@@ -18,7 +19,6 @@ import (
raftsnap "github.com/coreos/etcd/snap" raftsnap "github.com/coreos/etcd/snap"
"github.com/coreos/etcd/wal" "github.com/coreos/etcd/wal"
"github.com/coreos/etcd/wal/walpb" "github.com/coreos/etcd/wal/walpb"
"github.com/golang/protobuf/proto"
) )
func main() { func main() {
...@@ -94,12 +94,12 @@ func main() { ...@@ -94,12 +94,12 @@ func main() {
break break
} }
// 解码 // 解码
block := &Block{} info := &BlockInfo{}
if err := proto.Unmarshal(e.Data, block); err != nil { if err := json.Unmarshal(e.Data, info); err != nil {
log.Printf("failed to unmarshal: %v", err) log.Printf("failed to unmarshal: %v", err)
break break
} }
msg = fmt.Sprintf("%s\t BlockHeight:%d", msg, block.Height) msg = fmt.Sprintf("%s\tHeight=%d\tHash=%s", msg, info.Height, info.Hash)
case raftpb.EntryConfChange: case raftpb.EntryConfChange:
msg = fmt.Sprintf("%s\tconf", msg) msg = fmt.Sprintf("%s\tconf", msg)
var r raftpb.ConfChange var r raftpb.ConfChange
...@@ -133,21 +133,7 @@ func genIDSlice(a []uint64) []types.ID { ...@@ -133,21 +133,7 @@ func genIDSlice(a []uint64) []types.ID {
return ids return ids
} }
// Block struct type BlockInfo struct {
type Block struct { Height int64 `json:"height"`
Version int64 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` Hash string `json:"hash"`
ParentHash []byte `protobuf:"bytes,2,opt,name=parentHash,proto3" json:"parentHash,omitempty"`
TxHash []byte `protobuf:"bytes,3,opt,name=txHash,proto3" json:"txHash,omitempty"`
StateHash []byte `protobuf:"bytes,4,opt,name=stateHash,proto3" json:"stateHash,omitempty"`
Height int64 `protobuf:"varint,5,opt,name=height" json:"height,omitempty"`
BlockTime int64 `protobuf:"varint,6,opt,name=blockTime" json:"blockTime,omitempty"`
//Signature *Signature `protobuf:"bytes,8,opt,name=signature" json:"signature,omitempty"`
//Txs []*Transaction `protobuf:"bytes,7,rep,name=txs" json:"txs,omitempty"`
} }
// Reset method
func (m *Block) Reset() { *m = Block{} }
func (m *Block) String() string { return proto.CompactTextString(m) }
// ProtoMessage method
func (*Block) ProtoMessage() {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment