Skip to content

Commit a159594

Browse files
committed
<案例><添加><raft案例>
1 parent bc6f3ea commit a159594

File tree

807 files changed

+237503
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

807 files changed

+237503
-0
lines changed

demo/dou/main.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
)
7+
8+
func Decimal(value float64) float64 {
9+
value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
10+
return value
11+
}
12+
13+
func main() {
14+
var i float64
15+
var ii, jj float64 = 10, 3
16+
i = ii / jj
17+
fmt.Println(i)
18+
fmt.Println(Decimal(i))
19+
}

demo/httptest/beego/main.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package main
2+
3+
import (
4+
"github.com/astaxie/beego"
5+
"github.com/astaxie/beego/context"
6+
"github.com/astaxie/beego/logs"
7+
)
8+
9+
func OpenTrance(c *context.Context) {
10+
bodyBytes := c.Input.RequestBody
11+
bodyStr := string(bodyBytes)
12+
13+
logs.Info("请求地址:", c.Input.URI())
14+
logs.Info("请求内容:", bodyStr)
15+
c.WriteString("")
16+
}
17+
18+
// 启动方法
19+
func main() {
20+
beego.Any("*", OpenTrance)
21+
beego.Run(":80")
22+
}

demo/raft/etcd/Procfile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Use goreman to run `go get github.com/mattn/goreman`
2+
raftexample1: ./raftexample --id 1 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 12380
3+
raftexample2: ./raftexample --id 2 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 22380
4+
raftexample3: ./raftexample --id 3 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 32380

demo/raft/etcd/README.md

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# raftexample
2+
3+
raftexample is an example usage of etcd's raft library. It provides a simple REST API for a key-value store cluster backed by the [Raft][raft] consensus algorithm.
4+
5+
[raft]: https://raft.github.io/
6+
7+
## Getting Started
8+
9+
### Running single node raftexample
10+
11+
First start a single-member cluster of raftexample:
12+
13+
```sh
14+
raftexample --id 1 --cluster http://127.0.0.1:12379 --port 12380
15+
```
16+
17+
Each raftexample process maintains a single raft instance and a key-value server.
18+
The process's list of comma separated peers (--cluster), its raft ID index into the peer list (--id), and http key-value server port (--port) are passed through the command line.
19+
20+
Next, store a value ("hello") to a key ("my-key"):
21+
22+
```
23+
curl -L http://127.0.0.1:12380/my-key -XPUT -d hello
24+
```
25+
26+
Finally, retrieve the stored key:
27+
28+
```
29+
curl -L http://127.0.0.1:12380/my-key
30+
```
31+
32+
### Running a local cluster
33+
34+
First install [goreman](https://github.com/mattn/goreman), which manages Procfile-based applications.
35+
36+
The [Procfile script](./Procfile) will set up a local example cluster. Start it with:
37+
38+
```sh
39+
goreman start
40+
```
41+
42+
This will bring up three raftexample instances.
43+
44+
Now it's possible to write a key-value pair to any member of the cluster and likewise retrieve it from any member.
45+
46+
### Fault Tolerance
47+
48+
To test cluster recovery, first start a cluster and write a value "foo":
49+
```sh
50+
goreman start
51+
curl -L http://127.0.0.1:12380/my-key -XPUT -d foo
52+
```
53+
54+
Next, remove a node and replace the value with "bar" to check cluster availability:
55+
56+
```sh
57+
goreman run stop raftexample2
58+
curl -L http://127.0.0.1:12380/my-key -XPUT -d bar
59+
curl -L http://127.0.0.1:32380/my-key
60+
```
61+
62+
Finally, bring the node back up and verify it recovers with the updated value "bar":
63+
```sh
64+
goreman run start raftexample2
65+
curl -L http://127.0.0.1:22380/my-key
66+
```
67+
68+
### Dynamic cluster reconfiguration
69+
70+
Nodes can be added to or removed from a running cluster using requests to the REST API.
71+
72+
For example, suppose we have a 3-node cluster that was started with the commands:
73+
```sh
74+
raftexample --id 1 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 12380
75+
raftexample --id 2 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 22380
76+
raftexample --id 3 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379 --port 32380
77+
```
78+
79+
A fourth node with ID 4 can be added by issuing a POST:
80+
```sh
81+
curl -L http://127.0.0.1:12380/4 -XPOST -d http://127.0.0.1:42379
82+
```
83+
84+
Then the new node can be started as the others were, using the --join option:
85+
```sh
86+
raftexample --id 4 --cluster http://127.0.0.1:12379,http://127.0.0.1:22379,http://127.0.0.1:32379,http://127.0.0.1:42379 --port 42380 --join
87+
```
88+
89+
The new node should join the cluster and be able to service key/value requests.
90+
91+
We can remove a node using a DELETE request:
92+
```sh
93+
curl -L http://127.0.0.1:12380/3 -XDELETE
94+
```
95+
96+
Node 3 should shut itself down once the cluster has processed this request.
97+
98+
## Design
99+
100+
The raftexample consists of three components: a raft-backed key-value store, a REST API server, and a raft consensus server based on etcd's raft implementation.
101+
102+
The raft-backed key-value store is a key-value map that holds all committed key-values.
103+
The store bridges communication between the raft server and the REST server.
104+
Key-value updates are issued through the store to the raft server.
105+
The store updates its map once raft reports the updates are committed.
106+
107+
The REST server exposes the current raft consensus by accessing the raft-backed key-value store.
108+
A GET command looks up a key in the store and returns the value, if any.
109+
A key-value PUT command issues an update proposal to the store.
110+
111+
The raft server participates in consensus with its cluster peers.
112+
When the REST server submits a proposal, the raft server transmits the proposal to its peers.
113+
When raft reaches a consensus, the server publishes all committed updates over a commit channel.
114+
For raftexample, this commit channel is consumed by the key-value store.
115+

demo/raft/etcd/doc.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// raftexample is a simple KV store using the raft and rafthttp libraries.
16+
package main

demo/raft/etcd/httpapi.go

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2015 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"io/ioutil"
19+
"log"
20+
"net/http"
21+
"strconv"
22+
23+
"go.etcd.io/etcd/raft/raftpb"
24+
)
25+
26+
// Handler for a http based key-value store backed by raft
27+
type httpKVAPI struct {
28+
store *kvstore
29+
confChangeC chan<- raftpb.ConfChange
30+
}
31+
32+
func (h *httpKVAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
33+
key := r.RequestURI
34+
switch {
35+
case r.Method == "PUT":
36+
v, err := ioutil.ReadAll(r.Body)
37+
if err != nil {
38+
log.Printf("Failed to read on PUT (%v)\n", err)
39+
http.Error(w, "Failed on PUT", http.StatusBadRequest)
40+
return
41+
}
42+
43+
h.store.Propose(key, string(v))
44+
45+
// Optimistic-- no waiting for ack from raft. Value is not yet
46+
// committed so a subsequent GET on the key may return old value
47+
w.WriteHeader(http.StatusNoContent)
48+
case r.Method == "GET":
49+
if v, ok := h.store.Lookup(key); ok {
50+
w.Write([]byte(v))
51+
} else {
52+
http.Error(w, "Failed to GET", http.StatusNotFound)
53+
}
54+
case r.Method == "POST":
55+
url, err := ioutil.ReadAll(r.Body)
56+
if err != nil {
57+
log.Printf("Failed to read on POST (%v)\n", err)
58+
http.Error(w, "Failed on POST", http.StatusBadRequest)
59+
return
60+
}
61+
62+
nodeId, err := strconv.ParseUint(key[1:], 0, 64)
63+
if err != nil {
64+
log.Printf("Failed to convert ID for conf change (%v)\n", err)
65+
http.Error(w, "Failed on POST", http.StatusBadRequest)
66+
return
67+
}
68+
69+
cc := raftpb.ConfChange{
70+
Type: raftpb.ConfChangeAddNode,
71+
NodeID: nodeId,
72+
Context: url,
73+
}
74+
h.confChangeC <- cc
75+
76+
// As above, optimistic that raft will apply the conf change
77+
w.WriteHeader(http.StatusNoContent)
78+
case r.Method == "DELETE":
79+
nodeId, err := strconv.ParseUint(key[1:], 0, 64)
80+
if err != nil {
81+
log.Printf("Failed to convert ID for conf change (%v)\n", err)
82+
http.Error(w, "Failed on DELETE", http.StatusBadRequest)
83+
return
84+
}
85+
86+
cc := raftpb.ConfChange{
87+
Type: raftpb.ConfChangeRemoveNode,
88+
NodeID: nodeId,
89+
}
90+
h.confChangeC <- cc
91+
92+
// As above, optimistic that raft will apply the conf change
93+
w.WriteHeader(http.StatusNoContent)
94+
default:
95+
w.Header().Set("Allow", "PUT")
96+
w.Header().Add("Allow", "GET")
97+
w.Header().Add("Allow", "POST")
98+
w.Header().Add("Allow", "DELETE")
99+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
100+
}
101+
}
102+
103+
// serveHttpKVAPI starts a key-value server with a GET/PUT API and listens.
104+
func serveHttpKVAPI(kv *kvstore, port int, confChangeC chan<- raftpb.ConfChange, errorC <-chan error) {
105+
srv := http.Server{
106+
Addr: ":" + strconv.Itoa(port),
107+
Handler: &httpKVAPI{
108+
store: kv,
109+
confChangeC: confChangeC,
110+
},
111+
}
112+
go func() {
113+
if err := srv.ListenAndServe(); err != nil {
114+
log.Fatal(err)
115+
}
116+
}()
117+
118+
// exit when raft goes down
119+
if err, ok := <-errorC; ok {
120+
log.Fatal(err)
121+
}
122+
}

0 commit comments

Comments
 (0)