You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ha...@apache.org on 2024/09/02 00:47:41 UTC
(skywalking-banyandb) branch doc updated (a9ab2e06 -> f2eaf738)
This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a change to branch doc
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git
discard a9ab2e06 Add a series of docs about operation
new f2eaf738 Add a series of docs about operation
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (a9ab2e06)
\
N -- N -- N refs/heads/doc (f2eaf738)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
CHANGES.md | 1 +
1 file changed, 1 insertion(+)
(skywalking-banyandb) 01/01: Add a series of docs about operation
Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a commit to branch doc
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git
commit f2eaf73863e7dc1498de4e1d95be19a50af874da
Author: Gao Hongtao <ha...@gmail.com>
AuthorDate: Mon Sep 2 00:43:04 2024 +0000
Add a series of docs about operation
Signed-off-by: Gao Hongtao <ha...@gmail.com>
---
CHANGES.md | 1 +
banyand/measure/merger_policy.go | 12 ++-
banyand/measure/service.go | 3 +-
banyand/observability/metrics_system.go | 2 +-
banyand/queue/pub/pub.go | 2 +-
banyand/queue/sub/server.go | 8 +-
banyand/stream/merger_policy.go | 12 ++-
banyand/stream/service.go | 3 +-
bydbctl/internal/cmd/group.go | 10 +-
bydbctl/internal/cmd/health_check.go | 6 +-
bydbctl/internal/cmd/health_check_test.go | 54 +++++++++-
bydbctl/internal/cmd/index_rule.go | 10 +-
bydbctl/internal/cmd/index_rule_binding.go | 10 +-
bydbctl/internal/cmd/measure.go | 12 +--
bydbctl/internal/cmd/property.go | 10 +-
bydbctl/internal/cmd/rest.go | 6 +-
bydbctl/internal/cmd/root.go | 4 +-
bydbctl/internal/cmd/stream.go | 12 +--
docs/README.md | 2 +-
docs/interacting/bydbctl/bydbctl.md | 6 +-
docs/menu.yml | 20 +---
docs/operation/configuration.md | 125 ++++++++++++++++++++++
docs/operation/observability.md | 34 +++++-
docs/operation/security.md | 43 ++++++++
docs/operation/system.md | 35 +++++++
docs/operation/troubleshooting.md | 134 ++++++++++++++++++++++++
docs/operation/upgrade.md | 55 ++++++++++
pkg/test/helpers/http_health.go | 24 ++++-
pkg/test/setup/setup.go | 8 +-
test/integration/distributed/setup/node_test.go | 2 +-
test/integration/etcd/client_test.go | 6 +-
31 files changed, 581 insertions(+), 90 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index b1215801..789d1aef 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -50,6 +50,7 @@ Release Notes.
- Add web-ui interacting guide.
- Add bydbctl interacting guide.
- Add cluster management guide.
+- Add operation related documents: configuration, troubleshooting, system, upgrade, and observability.
### Chores
diff --git a/banyand/measure/merger_policy.go b/banyand/measure/merger_policy.go
index b04e26cc..750122ef 100644
--- a/banyand/measure/merger_policy.go
+++ b/banyand/measure/merger_policy.go
@@ -20,6 +20,8 @@ package measure
import (
"math"
"sort"
+
+ "github.com/apache/skywalking-banyandb/pkg/run"
)
// MergePolicy aims to choose an optimal combination
@@ -27,20 +29,20 @@ import (
type mergePolicy struct {
maxParts int
minMergeMultiplier float64
- maxFanOutSize uint64
+ maxFanOutSize run.Bytes
}
// NewDefaultMergePolicy create a MergePolicy with default parameters.
func newDefaultMergePolicy() *mergePolicy {
- return newMergePolicy(8, 1.7, math.MaxUint64)
+ return newMergePolicy(8, 1.7, run.Bytes(math.MaxInt64))
}
func newDefaultMergePolicyForTesting() *mergePolicy {
- return newMergePolicy(4, 1.7, math.MaxUint64)
+ return newMergePolicy(4, 1.7, run.Bytes(math.MaxInt64))
}
// NewMergePolicy creates a MergePolicy with given parameters.
-func newMergePolicy(maxParts int, minMergeMul float64, maxFanOutSize uint64) *mergePolicy {
+func newMergePolicy(maxParts int, minMergeMul float64, maxFanOutSize run.Bytes) *mergePolicy {
return &mergePolicy{
maxParts: maxParts,
minMergeMultiplier: minMergeMul,
@@ -53,7 +55,7 @@ func (l *mergePolicy) getPartsToMerge(dst, src []*partWrapper, freeDiskSize uint
return dst
}
- maxFanOut := min(freeDiskSize, l.maxFanOutSize)
+ maxFanOut := min(freeDiskSize, uint64(l.maxFanOutSize))
// Filter out too big parts.
// This should reduce N for O(N^2) algorithm below.
maxInPartBytes := uint64(float64(maxFanOut) / l.minMergeMultiplier)
diff --git a/banyand/measure/service.go b/banyand/measure/service.go
index 53aaa860..22a58918 100644
--- a/banyand/measure/service.go
+++ b/banyand/measure/service.go
@@ -19,7 +19,6 @@ package measure
import (
"context"
- "math"
"path"
"github.com/pkg/errors"
@@ -82,7 +81,7 @@ func (s *service) FlagSet() *run.FlagSet {
flagS.StringVar(&s.root, "measure-root-path", "/tmp", "the root path of database")
flagS.DurationVar(&s.option.flushTimeout, "measure-flush-timeout", defaultFlushTimeout, "the memory data timeout of measure")
s.option.mergePolicy = newDefaultMergePolicy()
- flagS.Uint64Var(&s.option.mergePolicy.maxFanOutSize, "max-fan-out-size", math.MaxUint64, "the upper bound of a single file size after merge")
+ flagS.VarP(&s.option.mergePolicy.maxFanOutSize, "measure-max-fan-out-size", "", "the upper bound of a single file size after merge of measure")
return flagS
}
diff --git a/banyand/observability/metrics_system.go b/banyand/observability/metrics_system.go
index 5e3054f4..8b1b7ecc 100644
--- a/banyand/observability/metrics_system.go
+++ b/banyand/observability/metrics_system.go
@@ -33,7 +33,7 @@ import (
"github.com/apache/skywalking-banyandb/pkg/meter"
)
-var log = logger.GetLogger("observability", "metrics", "system")
+var log = logger.GetLogger("metrics")
var (
cpuCount = 0
diff --git a/banyand/queue/pub/pub.go b/banyand/queue/pub/pub.go
index acada3b0..e8b3b0f2 100644
--- a/banyand/queue/pub/pub.go
+++ b/banyand/queue/pub/pub.go
@@ -200,7 +200,7 @@ func (*pub) Name() string {
}
func (p *pub) PreRun(context.Context) error {
- p.log = logger.GetLogger("server-queue")
+ p.log = logger.GetLogger("server-queue-pub")
p.metadata.RegisterHandler("queue-client", schema.KindNode, p)
return nil
}
diff --git a/banyand/queue/sub/server.go b/banyand/queue/sub/server.go
index e69e20d7..89bddbc3 100644
--- a/banyand/queue/sub/server.go
+++ b/banyand/queue/sub/server.go
@@ -94,7 +94,7 @@ func NewServer(omr observability.MetricsRegistry) queue.Server {
}
func (s *server) PreRun(_ context.Context) error {
- s.log = logger.GetLogger("server-queue")
+ s.log = logger.GetLogger("server-queue-sub")
s.metrics = newMetrics(s.omr.With(queueSubScope))
return nil
}
@@ -129,7 +129,7 @@ func (s *server) Validate() error {
if s.addr == ":" {
return errNoAddr
}
- s.healthAddr = net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.healthPort), 10))
+ s.healthAddr = net.JoinHostPort(s.host, strconv.FormatUint(uint64(s.healthPort), 10))
if s.healthAddr == ":" {
return errNoAddr
}
@@ -194,10 +194,10 @@ func (s *server) Serve() run.StopNotify {
}
gwMux := runtime.NewServeMux(runtime.WithHealthzEndpoint(client))
mux := chi.NewRouter()
- mux.Mount("/api", gwMux)
+ mux.Mount("/api", http.StripPrefix("/api", gwMux))
s.healthSrv = &http.Server{
Addr: s.healthAddr,
- Handler: chi.NewRouter(),
+ Handler: mux,
ReadHeaderTimeout: 3 * time.Second,
}
var wg sync.WaitGroup
diff --git a/banyand/stream/merger_policy.go b/banyand/stream/merger_policy.go
index 254873de..e694f804 100644
--- a/banyand/stream/merger_policy.go
+++ b/banyand/stream/merger_policy.go
@@ -20,6 +20,8 @@ package stream
import (
"math"
"sort"
+
+ "github.com/apache/skywalking-banyandb/pkg/run"
)
// MergePolicy aims to choose an optimal combination
@@ -27,16 +29,16 @@ import (
type mergePolicy struct {
maxParts int
minMergeMultiplier float64
- maxFanOutSize uint64
+ maxFanOutSize run.Bytes
}
// NewDefaultMergePolicy create a MergePolicy with default parameters.
func newDefaultMergePolicy() *mergePolicy {
- return newMergePolicy(15, 1.7, math.MaxUint64)
+ return newMergePolicy(15, 1.7, run.Bytes(math.MaxInt64))
}
func newDefaultMergePolicyForTesting() *mergePolicy {
- return newMergePolicy(4, 1.7, math.MaxUint64)
+ return newMergePolicy(4, 1.7, run.Bytes(math.MaxInt64))
}
func newDisabledMergePolicyForTesting() *mergePolicy {
@@ -44,7 +46,7 @@ func newDisabledMergePolicyForTesting() *mergePolicy {
}
// NewMergePolicy creates a MergePolicy with given parameters.
-func newMergePolicy(maxParts int, minMergeMul float64, maxFanOutSize uint64) *mergePolicy {
+func newMergePolicy(maxParts int, minMergeMul float64, maxFanOutSize run.Bytes) *mergePolicy {
return &mergePolicy{
maxParts: maxParts,
minMergeMultiplier: minMergeMul,
@@ -57,7 +59,7 @@ func (l *mergePolicy) getPartsToMerge(dst, src []*partWrapper, freeDiskSize uint
return dst
}
- maxFanOut := min(freeDiskSize, l.maxFanOutSize)
+ maxFanOut := min(freeDiskSize, uint64(l.maxFanOutSize))
// Filter out too big parts.
// This should reduce N for O(N^2) algorithm below.
maxInPartBytes := uint64(float64(maxFanOut) / l.minMergeMultiplier)
diff --git a/banyand/stream/service.go b/banyand/stream/service.go
index 2622b545..ae54e82a 100644
--- a/banyand/stream/service.go
+++ b/banyand/stream/service.go
@@ -19,7 +19,6 @@ package stream
import (
"context"
- "math"
"path"
"github.com/pkg/errors"
@@ -82,7 +81,7 @@ func (s *service) FlagSet() *run.FlagSet {
flagS.DurationVar(&s.option.flushTimeout, "stream-flush-timeout", defaultFlushTimeout, "the memory data timeout of stream")
flagS.DurationVar(&s.option.elementIndexFlushTimeout, "element-index-flush-timeout", defaultFlushTimeout, "the elementIndex timeout of stream")
s.option.mergePolicy = newDefaultMergePolicy()
- flagS.Uint64Var(&s.option.mergePolicy.maxFanOutSize, "max-fan-out-size", math.MaxUint64, "the upper bound of a single file size after merge")
+ flagS.VarP(&s.option.mergePolicy.maxFanOutSize, "stream-max-fan-out-size", "", "the upper bound of a single file size after merge of stream")
return flagS
}
diff --git a/bydbctl/internal/cmd/group.go b/bydbctl/internal/cmd/group.go
index 25a0a269..412c757d 100644
--- a/bydbctl/internal/cmd/group.go
+++ b/bydbctl/internal/cmd/group.go
@@ -61,7 +61,7 @@ func newGroupCmd() *cobra.Command {
fmt.Printf("group %s is created", reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -90,7 +90,7 @@ func newGroupCmd() *cobra.Command {
fmt.Printf("group %s is updated", reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
bindFileFlag(createCmd, updateCmd)
@@ -102,7 +102,7 @@ func newGroupCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("group", request.group).Get(getPath("/api/v1/group/schema/{group}"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -118,7 +118,7 @@ func newGroupCmd() *cobra.Command {
fmt.Printf("group %s is deleted", reqBody.group)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -129,7 +129,7 @@ func newGroupCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(nil, func(request request) (*resty.Response, error) {
return request.req.Get(getPath("/api/v1/group/schema/lists"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
diff --git a/bydbctl/internal/cmd/health_check.go b/bydbctl/internal/cmd/health_check.go
index 8585d052..ce54b6e6 100644
--- a/bydbctl/internal/cmd/health_check.go
+++ b/bydbctl/internal/cmd/health_check.go
@@ -49,15 +49,15 @@ func newHealthCheckCmd() *cobra.Command {
if grpcAddr == "" {
return rest(nil, func(request request) (*resty.Response, error) {
return request.req.Get(getPath("/api/healthz"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
}
if enableTLS {
config := &tls.Config{
// #nosec G402
InsecureSkipVerify: insecure,
}
- if grpcCert != "" {
- cert, errRead := os.ReadFile(grpcCert)
+ if cert != "" {
+ cert, errRead := os.ReadFile(cert)
if errRead != nil {
return errRead
}
diff --git a/bydbctl/internal/cmd/health_check_test.go b/bydbctl/internal/cmd/health_check_test.go
index 471c0c00..6041b267 100644
--- a/bydbctl/internal/cmd/health_check_test.go
+++ b/bydbctl/internal/cmd/health_check_test.go
@@ -30,7 +30,7 @@ import (
"github.com/apache/skywalking-banyandb/pkg/test/setup"
)
-var _ = Describe("health check after launching banyandb server", func() {
+var _ = Describe("health check after launching banyandb server with gRPC and HTTP TLS", func() {
var deferFunc func()
var grpcAddr, httpAddr, certFile string
var rootCmd *cobra.Command
@@ -47,7 +47,7 @@ var _ = Describe("health check after launching banyandb server", func() {
})
It("http health check should pass", func() {
- rootCmd.SetArgs([]string{"health", "--addr", "http://" + httpAddr})
+ rootCmd.SetArgs([]string{"health", "--addr", "https://" + httpAddr, "--cert", certFile, "--enable-tls", "true"})
out := capturer.CaptureStdout(func() {
err := rootCmd.Execute()
Expect(err).NotTo(HaveOccurred())
@@ -55,8 +55,23 @@ var _ = Describe("health check after launching banyandb server", func() {
Expect(out).To(ContainSubstring("SERVING"))
})
+ It("http health check should pass with insecure flag set", func() {
+ rootCmd.SetArgs([]string{"health", "--addr", "https://" + httpAddr, "--insecure", "true", "--enable-tls", "true"})
+ out := capturer.CaptureStdout(func() {
+ err := rootCmd.Execute()
+ Expect(err).NotTo(HaveOccurred())
+ })
+ Expect(out).To(ContainSubstring("SERVING"))
+ })
+
+ It("http health check should fail without the proper cert", func() {
+ rootCmd.SetArgs([]string{"health", "--addr", "https://" + httpAddr, "--enable-tls", "true"})
+ err := rootCmd.Execute()
+ Expect(err).To(HaveOccurred())
+ })
+
It("grpc health check should pass", func() {
- rootCmd.SetArgs([]string{"health", "--grpc-addr", grpcAddr, "--grpc-cert", certFile, "--enable-tls", "true"})
+ rootCmd.SetArgs([]string{"health", "--grpc-addr", grpcAddr, "--cert", certFile, "--enable-tls", "true"})
out := capturer.CaptureStdout(func() {
err := rootCmd.Execute()
Expect(err).NotTo(HaveOccurred())
@@ -84,6 +99,39 @@ var _ = Describe("health check after launching banyandb server", func() {
})
})
+var _ = Describe("health check after launching banyandb server", func() {
+ var deferFunc func()
+ var grpcAddr, httpAddr string
+ var rootCmd *cobra.Command
+ BeforeEach(func() {
+ grpcAddr, httpAddr, deferFunc = setup.Standalone()
+ rootCmd = &cobra.Command{Use: "root"}
+ cmd.RootCmdFlags(rootCmd)
+ })
+
+ It("http health check should pass", func() {
+ rootCmd.SetArgs([]string{"health", "--addr", "http://" + httpAddr})
+ out := capturer.CaptureStdout(func() {
+ err := rootCmd.Execute()
+ Expect(err).NotTo(HaveOccurred())
+ })
+ Expect(out).To(ContainSubstring("SERVING"))
+ })
+
+ It("grpc health check should pass", func() {
+ rootCmd.SetArgs([]string{"health", "--grpc-addr", grpcAddr})
+ out := capturer.CaptureStdout(func() {
+ err := rootCmd.Execute()
+ Expect(err).NotTo(HaveOccurred())
+ })
+ Expect(out).To(ContainSubstring("connected"))
+ })
+
+ AfterEach(func() {
+ deferFunc()
+ })
+})
+
var _ = Describe("health check without launching banyandb server", func() {
var rootCmd *cobra.Command
BeforeEach(func() {
diff --git a/bydbctl/internal/cmd/index_rule.go b/bydbctl/internal/cmd/index_rule.go
index ac18fd1a..b28c19bf 100644
--- a/bydbctl/internal/cmd/index_rule.go
+++ b/bydbctl/internal/cmd/index_rule.go
@@ -64,7 +64,7 @@ func newIndexRuleCmd() *cobra.Command {
fmt.Printf("indexRule %s.%s is created", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -95,7 +95,7 @@ func newIndexRuleCmd() *cobra.Command {
fmt.Printf("indexRule %s.%s is updated", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -106,7 +106,7 @@ func newIndexRuleCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("name", request.name).SetPathParam("group", request.group).Get(getPath(indexRuleSchemaPathWithParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -121,7 +121,7 @@ func newIndexRuleCmd() *cobra.Command {
fmt.Printf("indexRule %s.%s is deleted", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
bindNameFlag(getCmd, deleteCmd)
@@ -133,7 +133,7 @@ func newIndexRuleCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("group", request.group).Get(getPath("/api/v1/index-rule/schema/lists/{group}"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
diff --git a/bydbctl/internal/cmd/index_rule_binding.go b/bydbctl/internal/cmd/index_rule_binding.go
index b26f3461..34b055ac 100644
--- a/bydbctl/internal/cmd/index_rule_binding.go
+++ b/bydbctl/internal/cmd/index_rule_binding.go
@@ -64,7 +64,7 @@ func newIndexRuleBindingCmd() *cobra.Command {
fmt.Printf("indexRuleBinding %s.%s is created", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -95,7 +95,7 @@ func newIndexRuleBindingCmd() *cobra.Command {
fmt.Printf("indexRuleBinding %s.%s is updated", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -106,7 +106,7 @@ func newIndexRuleBindingCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("name", request.name).SetPathParam("group", request.group).Get(getPath(indexRuleBindingSchemaPathWithParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -121,7 +121,7 @@ func newIndexRuleBindingCmd() *cobra.Command {
fmt.Printf("indexRuleBinding %s.%s is deleted", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
bindNameFlag(getCmd, deleteCmd)
@@ -133,7 +133,7 @@ func newIndexRuleBindingCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("group", request.group).Get(getPath("/api/v1/index-rule-binding/schema/lists/{group}"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
diff --git a/bydbctl/internal/cmd/measure.go b/bydbctl/internal/cmd/measure.go
index 56ee9289..d2d7c32f 100644
--- a/bydbctl/internal/cmd/measure.go
+++ b/bydbctl/internal/cmd/measure.go
@@ -64,7 +64,7 @@ func newMeasureCmd() *cobra.Command {
fmt.Printf("measure %s.%s is created", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -95,7 +95,7 @@ func newMeasureCmd() *cobra.Command {
fmt.Printf("measure %s.%s is updated", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -106,7 +106,7 @@ func newMeasureCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("name", request.name).SetPathParam("group", request.group).Get(getPath(measureSchemaPathWithParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -121,7 +121,7 @@ func newMeasureCmd() *cobra.Command {
fmt.Printf("measure %s.%s is deleted", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
bindNameFlag(getCmd, deleteCmd)
@@ -133,7 +133,7 @@ func newMeasureCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("group", request.group).Get(getPath("/api/v1/measure/schema/lists/{group}"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -146,7 +146,7 @@ func newMeasureCmd() *cobra.Command {
return rest(func() ([]reqBody, error) { return parseTimeRangeFromFlagAndYAML(cmd.InOrStdin()) },
func(request request) (*resty.Response, error) {
return request.req.SetBody(request.data).Post(getPath("/api/v1/measure/data"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
bindFileFlag(createCmd, updateCmd, queryCmd)
diff --git a/bydbctl/internal/cmd/property.go b/bydbctl/internal/cmd/property.go
index e8aacbe7..1b0587b3 100644
--- a/bydbctl/internal/cmd/property.go
+++ b/bydbctl/internal/cmd/property.go
@@ -69,7 +69,7 @@ func newPropertyCmd() *cobra.Command {
}
return request.req.SetPathParam("group", request.group).SetPathParam("name", request.name).
SetPathParam("id", request.id).SetBody(b).Put(getPath(propertySchemaPathWithoutTagParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
bindFileFlag(applyCmd)
@@ -83,7 +83,7 @@ func newPropertyCmd() *cobra.Command {
return request.req.SetPathParam("name", request.name).SetPathParam("group", request.group).
SetPathParam("id", request.id).SetPathParam("tag", request.tags()).
Get(getPath(propertySchemaPathWithTagParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -95,7 +95,7 @@ func newPropertyCmd() *cobra.Command {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("name", request.name).SetPathParam("group", request.group).
SetPathParam("id", request.id).SetPathParam("tag", request.tags()).Delete(getPath(propertySchemaPathWithTagParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
bindNameAndIDAndTagsFlag(getCmd, deleteCmd)
@@ -111,7 +111,7 @@ func newPropertyCmd() *cobra.Command {
}
return request.req.SetPathParam("name", request.name).SetPathParam("group", request.group).
SetPathParam("ids", request.ids()).SetPathParam("tags", request.tags()).Get(getPath(propertyListSchemaPathWithTagParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
listCmd.Flags().StringVarP(&name, "name", "n", "", "the name of the resource")
@@ -132,7 +132,7 @@ func newPropertyCmd() *cobra.Command {
}, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("lease_id", strconv.FormatInt(request.leaseID, 10)).
Put(getPath(propertySchemaPath + "/lease/{lease_id}"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
keepAliveCmd.Flags().Int64VarP(&leaseID, "lease_id", "i", 0, "the lease id of the property")
diff --git a/bydbctl/internal/cmd/rest.go b/bydbctl/internal/cmd/rest.go
index 1ba5a5a7..924f93c1 100644
--- a/bydbctl/internal/cmd/rest.go
+++ b/bydbctl/internal/cmd/rest.go
@@ -308,7 +308,7 @@ func yamlPrinter(index int, _ reqBody, body []byte) error {
return nil
}
-func rest(pfn paramsFn, fn reqFn, printer printer, enableTLS bool, insecure bool, grpcCert string) (err error) {
+func rest(pfn paramsFn, fn reqFn, printer printer, enableTLS bool, insecure bool, cert string) (err error) {
var requests []reqBody
if pfn == nil {
requests = []reqBody{{}}
@@ -326,8 +326,8 @@ func rest(pfn paramsFn, fn reqFn, printer printer, enableTLS bool, insecure bool
// #nosec G402
InsecureSkipVerify: insecure,
}
- if grpcCert != "" {
- cert, err := os.ReadFile(grpcCert)
+ if cert != "" {
+ cert, err := os.ReadFile(cert)
if err != nil {
return err
}
diff --git a/bydbctl/internal/cmd/root.go b/bydbctl/internal/cmd/root.go
index 5f562281..4efff65c 100644
--- a/bydbctl/internal/cmd/root.go
+++ b/bydbctl/internal/cmd/root.go
@@ -39,7 +39,7 @@ var (
cfgFile string
enableTLS bool
insecure bool
- grpcCert string
+ cert string
rootCmd = &cobra.Command{
DisableAutoGenTag: true,
Version: version.Build(),
@@ -149,6 +149,6 @@ func bindTLSRelatedFlag(commands ...*cobra.Command) {
for _, c := range commands {
c.Flags().BoolVarP(&enableTLS, "enable-tls", "", false, "Used to enable tls")
c.Flags().BoolVarP(&insecure, "insecure", "", false, "Used to skip server's cert")
- c.Flags().StringVarP(&grpcCert, "grpc-cert", "", "", "Grpc certificate for tls")
+ c.Flags().StringVarP(&cert, "cert", "", "", "Certificate for tls")
}
}
diff --git a/bydbctl/internal/cmd/stream.go b/bydbctl/internal/cmd/stream.go
index 01891044..adad7bab 100644
--- a/bydbctl/internal/cmd/stream.go
+++ b/bydbctl/internal/cmd/stream.go
@@ -69,7 +69,7 @@ func newStreamCmd() *cobra.Command {
fmt.Printf("stream %s.%s is created", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -100,7 +100,7 @@ func newStreamCmd() *cobra.Command {
fmt.Printf("stream %s.%s is updated", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
@@ -111,7 +111,7 @@ func newStreamCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("name", request.name).SetPathParam("group", request.group).Get(getPath(streamSchemaPathWithParams))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -126,7 +126,7 @@ func newStreamCmd() *cobra.Command {
fmt.Printf("stream %s.%s is deleted", reqBody.group, reqBody.name)
fmt.Println()
return nil
- }, enableTLS, insecure, grpcCert)
+ }, enableTLS, insecure, cert)
},
}
bindNameFlag(getCmd, deleteCmd)
@@ -138,7 +138,7 @@ func newStreamCmd() *cobra.Command {
RunE: func(_ *cobra.Command, _ []string) (err error) {
return rest(parseFromFlags, func(request request) (*resty.Response, error) {
return request.req.SetPathParam("group", request.group).Get(getPath("/api/v1/stream/schema/lists/{group}"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
@@ -151,7 +151,7 @@ func newStreamCmd() *cobra.Command {
return rest(func() ([]reqBody, error) { return parseTimeRangeFromFlagAndYAML(cmd.InOrStdin()) },
func(request request) (*resty.Response, error) {
return request.req.SetBody(request.data).Post(getPath("/api/v1/stream/data"))
- }, yamlPrinter, enableTLS, insecure, grpcCert)
+ }, yamlPrinter, enableTLS, insecure, cert)
},
}
bindFileFlag(createCmd, updateCmd, queryCmd)
diff --git a/docs/README.md b/docs/README.md
index c1030c72..9d44786b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -21,7 +21,7 @@ You might also find these links interesting:
- The latest and old releases are all available
at [Apache SkyWalking release page](https://skywalking.apache.org/downloads/). The change logs can be
- found [here](https://github.com/apache/skywalking/tree/master/changes).
+ found [here](https://github.com/apache/skywalking-banyandb/tree/master/CHANGES.md).
- [SkyWalking WIKI](https://cwiki.apache.org/confluence/display/SKYWALKING/Home) hosts the context of some changes and
events.
diff --git a/docs/interacting/bydbctl/bydbctl.md b/docs/interacting/bydbctl/bydbctl.md
index 90c0f466..e2621752 100644
--- a/docs/interacting/bydbctl/bydbctl.md
+++ b/docs/interacting/bydbctl/bydbctl.md
@@ -17,4 +17,8 @@ group: ""
## HTTP client
-Users could select any HTTP client to access the HTTP based endpoints. The default address is `localhost:17913/api`
\ No newline at end of file
+Users could select any HTTP client to access the HTTP based endpoints. The default address is `localhost:17913/api`
+
+## TLS
+
+TLS is supported by `bydbctl`.`--tls=true` and `--cert <cert_file>` are the flags to enable TLS and specify the certificate file. If you want to ignore the certificate verification, use `--insecure=true`.
diff --git a/docs/menu.yml b/docs/menu.yml
index 38b95d55..97cab235 100644
--- a/docs/menu.yml
+++ b/docs/menu.yml
@@ -98,29 +98,19 @@ catalog:
- name: "Operation and Maintenance"
catalog:
- name: "Configure BanyanDB"
- path: ""
+ path: "/operation/configuration"
- name: "System Configuration"
- path: ""
+ path: "/operation/system"
- name: "Upgrade"
- catalog:
- - name: "Server and File Versioning"
- path: ""
- - name: "Upgrade"
- path: ""
- - name: "Rollback"
- path: ""
+ path: "/operation/upgrade"
- name: "Observability"
path: "/operation/observability"
- name: "Cluster Management"
path: "/operation/cluster"
- - name: "Security"
- catalog:
- - name: "TLS Configuration"
- path: ""
- name: "Troubleshooting"
- path: ""
+ path: "/operation/troubleshooting"
- name: "Security"
- path: ""
+ path: "/operation/security"
- name: "File Format"
catalog:
- name: "v1.1.0"
diff --git a/docs/operation/configuration.md b/docs/operation/configuration.md
new file mode 100644
index 00000000..5bc648de
--- /dev/null
+++ b/docs/operation/configuration.md
@@ -0,0 +1,125 @@
+# Configuration
+
+BanyanD is the BanyanDB server. There are two ways to configure BanyanD: using a bootstrap flag or using environment variables. The environment variable name has a prefix "BYDB_" followed by the flag name in uppercase. For example, the flag `--port` can be set using the environment variable `BYDB_PORT`.
+
+## Commands
+
+### Bootstrap commands
+
+There are three bootstrap commands: `data`, `liaison`, and `standalone`. You could use them to boot different roles of BanyanD.
+
+- `data`: Run as the data server. It stores the data and processes the data requests.
+- `liaison`: Run as the liaison server. It is responsible for the communication between the data servers and clients.
+- `standalone`: Run as the standalone server. It combines the data, liaison server and embed etcd server for development and testing.
+
+### Other commands
+
+- `completion`: Generate the autocompletion script for the specified shell.
+- `help`: Help about any command.
+
+## Flags
+
+Below are the available flags for configuring BanyanDB:
+
+### Liaison & Network
+
+BanyanDB uses gRPC for communication between the servers. The following flags are used to configure the network settings.
+
+- `--grpc-host string`: The host BanyanDB listens on.
+- `--grpc-port uint32`: The port BanyanDB listens on (default: 17912).
+- `--http-grpc-addr string`: HTTP server redirects gRPC requests to this address (default: "localhost:17912").
+- `--http-host string`: Listen host for HTTP.
+- `--http-port uint32`: Listen port for HTTP (default: 17913).
+- `--max-recv-msg-size bytes`: The size of the maximum receiving message (default: 10.00MiB).
+
+The following flags are used to configure access logs for the data ingestion:
+
+- `--access-log-root-path string`: Access log root path.
+- `--enable-ingestion-access-log`: Enable ingestion access log.
+
+BanyanDB uses etcd for service discovery and configuration. The following flags are used to configure the etcd settings. These flags are only used when running as a liaison or data server. Standalone server embeds etcd server and does not need these flags.
+
+- `--etcd-listen-client-url strings`: A URL to listen on for client traffic (default: [http://localhost:2379]).
+- `--etcd-listen-peer-url strings`: A URL to listen on for peer traffic (default: [http://localhost:2380]).
+
+The following flags are used to configure the timeout of data sending from liaison to data servers:
+
+- `--stream-write-timeout duration`: Stream write timeout (default: 15s).
+- `--measure-write-timeout duration`: Measure write timeout (default: 15s).
+
+### TLS
+
+If you want to enable TLS for the communication between the client and liaison/standalone, you can use the following flags:
+
+- `--tls`: gRPC connection uses TLS if true, else plain TCP.
+- `--http-tls`: http connection uses TLS if true, else plain HTTP.
+- `--key-file string`: The TLS key file.
+- `--cert-file string`: The TLS certificate file.
+- `--http-grpc-cert-file string`: The gRPC TLS certificate file if the gRPC server enables TLS. It should be the same as the `cert-file`.
+- `--http-key-file string`: The TLS key file of the HTTP server.
+- `--http-cert-file string`: The TLS certificate file of the HTTP server.
+
+### Data & Storage
+
+If the node is running as a data server, you can configure the health check server port:
+
+`--health-port uint32`: the port of banyand health check listens (default 17913)
+
+The following flags are used to configure the measure storage engine:
+
+- `--measure-flush-timeout duration`: The memory data timeout of measure (default: 5s).
+- `--measure-root-path string`: The root path of the database (default: "/tmp").
+- `--measure-max-fan-out-size bytes`: the upper bound of a single file size after merge of measure (default 8.00EiB)
+
+The following flags are used to configure the stream storage engine:
+
+- `--stream-flush-timeout duration`: The memory data timeout of stream (default: 1s).
+- `--stream-root-path string`: The root path of the database (default: "/tmp").
+- `--stream-max-fan-out-size bytes`: the upper bound of a single file size after merge of stream (default 8.00EiB)
+- `--element-index-flush-timeout duration`: The element index timeout of stream (default: 1s).
+
+The following flags are used to configure the embedded etcd storage engine which is only used when running as a standalone server:
+
+- `--metadata-root-path string`: The root path of metadata (default: "/tmp").
+
+### Observability
+
+- `--observability-listener-addr string`: Listen address for observability (default: ":2121").
+- `--observability-modes strings`: Modes for observability (default: [prometheus]).
+- `--pprof-listener-addr string`: Listen address for pprof (default: ":6060").
+
+### Other
+
+- `-n, --name string`: Name of this service.
+- `-h, --help`: Help for standalone.
+- `--show-rungroup-units`: Show rungroup units.
+- `-v, --version`: Version for standalone.
+
+### Global Flags
+
+- `--logging-env string`: The logging environment (default: "prod").
+- `--logging-level string`: The root level of logging (default: "info").
+- `--logging-levels strings`: The level logging of logging.
+- `--logging-modules strings`: The specific module for logging.
+- `--node-host string`: The node host of the server, only used when `node-host-provider` is "flag".
+- `--node-host-provider nodeIDProvider`: The node host provider, can be hostname, IP, or flag (default: Hostname).
+
+## Example Command
+
+```sh
+banyand standalone --logging-env=dev --logging-level=debug --grpc-port=18913
+```
+
+If you want to use environment variables to configure BanyanD, you can set the environment variables like this:
+
+```sh
+export BYDB_LOGGING_ENV=dev
+export BYDB_LOGGING_LEVEL=debug
+export BYDB_GRPC_PORT=18913
+```
+
+Then you can run BanyanD without any flags:
+
+```sh
+banyand standalone
+```
diff --git a/docs/operation/observability.md b/docs/operation/observability.md
index 0b9c9455..7b4e6141 100644
--- a/docs/operation/observability.md
+++ b/docs/operation/observability.md
@@ -2,6 +2,18 @@
This document outlines the observability features of BanyanDB, which include metrics, profiling, and tracing. These features help monitor and understand the performance, behavior, and overall health of BanyanDB.
+## Logging
+
+BanyanDB uses the [zerolo](https://github.com/rs/zerolog) library for logging. The log level can be set using the `log-level` flag. The supported log levels are `debug`, `info`, `warn`, `error`, and `fatal`. The default log level is `info`.
+
+`logging-env` is used to set the logging environment. The default value is `prod`. The logging environment can be set to `dev` for development or `prod` for production. The logging environment affects the log format and output. In the `dev` environment, logs are output in a human-readable format, while in the `prod` environment, logs are output in JSON format.
+
+`logging-modules` and `logging-levels` are used to set the log level for specific modules. The `logging-modules` flag is a comma-separated list of module names, and the `logging-levels` flag is a comma-separated list of log levels corresponding to the module names. The log level for a specific module can be set using these flags. Available modules are `storage`, `distributed-query`, `liaison-grpc`, `liaison-http`, `measure`, `stream`, `metadata`, `etcd`, `metrics`, `pprof-service`, `quer [...]
+
+```sh
+--logging-modules=storage --logging-levels=debug
+```
+
## Metrics
BanyanDB has built-in support for metrics collection. Currently, there are two supported metrics provider: `prometheus` and `native`. These can be enabled through `observability-modes` flag, allowing you to activate one or both of them.
@@ -38,4 +50,24 @@ The read flow is the same as reading data from `measure`, with each metric being
Banyand, the server of BanyanDB, supports profiling automatically. The profiling data is collected by the `pprof` package and can be accessed through the `/debug/pprof` endpoint. The port of the profiling server is `2122` by default.
-## Tracing
+## Query Tracing
+
+BanyanDB supports query tracing, which allows you to trace the execution of a query. The tracing data includes the query plan, execution time, and other useful information. You can enable query tracing by setting the `QueryRequest.trace` field to `true` when sending a query request.
+
+The below command could query data in the last 30 minutes with `trace` enabled:
+
+```shell
+bydbctl measure query --start -30m -f - <<EOF
+name: "service_cpm_minute"
+groups: ["measure-minute"]
+tagProjection:
+ tagFamilies:
+ - name: "storage-only"
+ tags: ["entity_id"]
+fieldProjection:
+ names: ["total", "value"]
+trace: true
+EOF
+```
+
+The result will include the tracing data in the response. The duration time unit is in nano seconds.
diff --git a/docs/operation/security.md b/docs/operation/security.md
new file mode 100644
index 00000000..3ea84191
--- /dev/null
+++ b/docs/operation/security.md
@@ -0,0 +1,43 @@
+# Security
+
+Security is a critical aspect of any application. In this section, we will discuss the security features of the BanyanDB.
+
+## Authentication
+
+BanyanDB supports TLS for secure communication between servers. The following flags are used to configure TLS:
+
+- `--tls`: gRPC Connection uses TLS if true, else plain TCP.
+- `--http-tls`: HTTP Connection uses TLS if true, else plain HTTP.
+- `--key-file string`: The TLS key file for gRPC.
+- `--cert-file string`: The TLS certificate file for gRPC.
+- `--http-grpc-cert-file string`: The gRPC TLS certificate file if the gRPC server enables TLS. It should be the same as the `cert-file`. It is used for gRPC over HTTP.
+- `--http-key-file string`: The TLS key file of the HTTP server.
+- `--http-cert-file string`: The TLS certificate file of the HTTP server.
+
+For example, to enable TLS for gRPC communication, you can use the following flags:
+
+```shell
+banyand liaison --tls=true --key-file=server.key --cert-file=server.crt --http-grpc-cert-file=server.crt --http-tls=true --http-key-file=server.key --http-cert-file=server.crt
+```
+
+If you only want to security gRPC connection, you can leave `--http-tls=false`.
+
+```shell
+banyand liaison --tls=true --key-file=server.key --cert-file=server.crt --http-grpc-cert-file=server.crt
+```
+
+Also, you can enable TLS for HTTP connection only.
+
+```shell
+banyand liaison --http-tls=true --http-key-file=server.key --http-cert-file=server.crt
+```
+
+> Note: BanyanDB does not support TLS between liaison and data nodes.
+
+## Authorization
+
+BanyanDB does not have built-in authorization mechanisms. However, you can use external tools like [Envoy](https://www.envoyproxy.io/) or [Istio](https://istio.io/) to manage access control and authorization.
+
+## Data Encryption
+
+BanyanDB does not provide data encryption at rest. If you require data encryption, you can use disk-level encryption or other encryption mechanisms provided by the underlying storage system.
diff --git a/docs/operation/system.md b/docs/operation/system.md
new file mode 100644
index 00000000..0e233724
--- /dev/null
+++ b/docs/operation/system.md
@@ -0,0 +1,35 @@
+# System Configuration
+
+Several system configuration settings should be set before running BanyanDB.
+
+## Remove System Limits
+
+BanyanDB requires a large number of open files and a large number of processes. The default system limits are not sufficient for BanyanDB.
+
+```sh
+ulimit -l unlimited
+ulimit -n 800000
+ulimit -u 8096
+```
+
+`ulimit -l unlimited`: This command sets the maximum size of memory that can be locked into RAM to unlimited. Locking memory can be important for performance-critical applications that need to ensure certain data remains in physical memory and is not swapped out to disk.
+
+`ulimit -n 800000`: This command sets the maximum number of open file descriptors to 800,000. File descriptors are references to open files, sockets, or other input/output resources. Increasing this limit is often necessary for applications that handle a large number of simultaneous connections or open files.
+
+`ulimit -u 8096`: This command sets the maximum number of user processes to 8,096. This limit controls how many processes a single user can create. Raising this limit can be important for applications that spawn many subprocesses or threads.
+
+## NTP Setup
+
+BanyanDB requires accurate time synchronization across all servers. We recommend setting up NTP (Network Time Protocol) to ensure that all servers have synchronized clocks.
+
+But the nodes in a cluster are independently obtaining their time from random pool servers out on the Internet, the chances that two nodes can have widely (by NTP standards) differing time is high. This can cause problems in a distributed system like BanyanDB. In order to avoid this, we recommend setting up a local NTP server that all nodes in the cluster can sync to.
+
+## Kernel Configuration
+
+BanyanDB requires a few kernel parameters to be set to ensure optimal performance. These parameters can be set by adding the following lines to `/etc/sysctl.conf`:
+
+```sh
+
+# Make the system very reluctant to swap memory to disk
+vm.swappiness = 1
+```
diff --git a/docs/operation/troubleshooting.md b/docs/operation/troubleshooting.md
new file mode 100644
index 00000000..99a1f1b8
--- /dev/null
+++ b/docs/operation/troubleshooting.md
@@ -0,0 +1,134 @@
+# Troubleshooting
+
+## Error Checklist
+
+When facing issues with BanyanDB, follow this checklist to effectively troubleshoot and resolve errors.
+
+### 1. Collect Information
+
+Gather detailed information about the error to assist in diagnosing the issue:
+
+- **Error Message**: Note the exact error message displayed.
+- **Logs**: Collect relevant log files from the BanyanDB system. See the [Logging](./observability.md#logging) section for more information.
+- **Query Tracing**: If the error is related to a query, enable query tracing to capture detailed information about the query execution. See the [Query Tracing](./observability.md#query-tracing) section for more information.
+- **Environment**: Document the environment details, including OS, BanyanDB version, and hardware specifications.
+- **Database Schema**: Provide the schema details related to the error. See the [Schema Management](../interacting/bydbctl/schema/) section for more information.
+- **Data Sample**: If applicable, include a sample of the data causing the error.
+- **Configuration Settings**: Share the relevant configuration settings.
+- **Data Files**: Attach any relevant data files. See the [Configuration](./configuration.md) section to find where the date files is stored.
+- **Reproduction Steps**: Describe the steps to reproduce the error.
+
+### 2. Define Error Type
+
+Classify the error to streamline the troubleshooting process:
+
+- **Configuration Error**: Issues related to incorrect configuration settings.
+- **Network Error**: Problems caused by network connectivity.
+- **Performance Error**: Slowdowns or high resource usage.
+- **Data Error**: Inconsistencies or corruption in stored data.
+
+### 3. Error Support Procedure
+
+Follow this procedure to address the identified error type:
+
+- Identify the error type based on the collected information.
+- Refer to the relevant sections in the documentation to troubleshoot the error.
+- Refer to the issues section in the SkyWalking repository for known issues and solutions.
+- If the issue persists, submit a discussion in the [SkyWalking Discussion](https://github.com/apache/skywalking/discussions) for assistance.
+- You can also raise a bug report in the [SkyWalking Issue Tracker](https://github.com/apache/skywalking/issues) if the issue is not resolved.
+- Finally, As a OpenSource project, you could try to fix the issue by yourself and submit a pull request.
+
+Here's an expanded section on common issues for your BanyanDB troubleshooting document:
+
+## Common Issues
+
+### Write Failures
+
+**Troubleshooting Steps:**
+
+1. **Check Disk Space**: Ensure there is enough disk space available for writes.
+2. **Review Permissions**: Verify that BanyanDB has the necessary permissions to write to the target directories.
+3. **Examine Logs**: Look for error messages in the logs that might indicate the cause of the failure.
+4. **Network Issues**: Ensure network stability if the write operation involves remote nodes.
+5. **Configuration Settings**: Double-check configuration settings related to write operations.
+
+### Incorrect Query Results
+
+**Diagnose and Fix:**
+
+1. **Verify Query Syntax**: Ensure that the query syntax is correct and aligns with BanyanDB's query API.
+2. **Inspect Indexes**: Ensure indexes are correctly defined and up-to-date.
+3. **Review Recent Changes**: Consider any recent changes to data or schema that might affect query results.
+4. **
+
+### Performance Issues
+
+#### Slow Write
+
+**Steps to Address:**
+
+1. **Resource Allocation**: Ensure adequate resources (CPU, memory) are allocated to BanyanDB.
+2. **Batch Writes**: Increasing batch sizes can improve write performance.
+3. **Monitor Disk I/O**: Check for disk I/O bottlenecks.
+
+#### Slow Query
+
+**Optimize Slow Queries:**
+
+1. **Analyze Query Plans**: Use query tracing to understand execution plans and identify bottlenecks.
+2. **Index Usage**: Ensure appropriate indexes are used to speed up queries.
+3. **Refactor Queries**: Simplify complex queries where possible. For example, using `IN` instead of multiple `OR` conditions.
+4. **Sharding**: Consider adding more shards to distribute query load.
+
+#### Out of Memory (OOM)
+
+**Handle OOM Errors:**
+
+1. **Increase Memory Limits**: Adjust memory allocation settings for BanyanDB.
+2. **Optimize Queries**: Ensure queries are efficient and not causing excessive memory usage.
+3. **Data Sharding**: Distribute data across shards to reduce memory pressure.
+4. **Monitor Memory Usage**: Use monitoring tools to track memory usage patterns.
+
+### Process Crashes and File Corruption
+
+**Steps to Diagnose and Recover:**
+
+1. **Examine Log Files**: Check logs for error messages leading up to the crash.
+2. **Check File System**: Ensure the file system is not corrupted and is functioning properly.
+3. **Update Software**: Ensure BanyanDB and its dependencies are up-to-date with the latest patches.
+4. **Remove Corrupted Data**: If data corruption is detected, remove the corrupted data and restore from backups if necessary.
+
+### How to Remove Corrupted Data
+
+Corrupted data can cause BanyanDB to malfunction or produce incorrect results. Follow these steps to safely remove corrupted data from BanyanDB:
+
+1. **Identify the Corrupted Data**:
+ Monitor the BanyanDB logs for any error messages indicating data corruption. The file is located in a part directory. You have to remove the whole part directory instead of a single file.
+
+2. **Shutdown BanyanDB**:
+ - Before making any changes to the data files, ensure that BanyanDB is not running. This prevents further corruption and ensures data integrity.
+ - Send `SIGTERM` or `SIGINT` signals to the BanyanDB process to gracefully shut it down
+
+3. **Locate the Snapshot File**:
+ - In each shard of the TSDB (Time Series Database), there is a [snapshot file](../concept/tsdb.md#shard) that contains all alive parts directories.
+ - Navigate to the directory where BanyanDB stores its data. This is typically specified in the [flags](./configuration.md)
+
+4. **Remove the Corrupted File**:
+ - Identify the corrupted part within the snapshot directory.
+ - Remove the part's record from the snapshot file.
+
+5. **Clean Up Part**:
+ - Remove the corrupted part directory from the disk.
+
+6. **Restart BanyanDB**:
+ - Once the corrupted part is removed and the metadata is cleaned up, restart BanyanDB to apply the changes
+
+7. **Verify the Integrity**:
+ - After restarting, monitor the BanyanDB logs to ensure that the corruption issues have been resolved.
+ - Run any necessary integrity checks or queries to verify that the database is functioning correctly.
+
+8. **Prevent Future Corruptions**:
+ - Monitor system resources and ensure that the hardware and storage systems are functioning correctly.
+ - Keep BanyanDB and its dependencies updated to the latest versions to benefit from bug fixes and improvements.
+
+By following these steps, you can safely remove corrupted data from BanyanDB and ensure the continued integrity and performance of your database.
diff --git a/docs/operation/upgrade.md b/docs/operation/upgrade.md
new file mode 100644
index 00000000..19e61f6d
--- /dev/null
+++ b/docs/operation/upgrade.md
@@ -0,0 +1,55 @@
+# Upgrade Procedure
+
+This document describes how to upgrade your existing installation of the BanyanDB database.
+
+## Server and File Versioning
+
+BanyanDB uses a separate version for the server and the file format. The server version is the version of the BanyanDB server binary, and the file version is the version of the data files stored on the disk.
+
+You can use "banyand liaison/data/standalone -v" to check the server version. The file version is stored in "metadata" file laid in each ["segment"](../concept/tsdb.md#segment) folder.
+
+The server will check the file version when it starts. If the file version is not compatible with the supported version list in the server, the server will refuse to start. Please check the [CHANGELOG.md](https://github.com/apache/skywalking-banyandb/tree/master/CHANGES.md) to ensure that the new version is compatible with the existing data files.
+
+BanyanDB upgrade procedure is a rolling upgrade. You can upgrade the BanyanDB cluster without downtime. But you need to follow the instructions carefully to avoid any data loss:
+
+- Perform the upgrades consecutively. You cannot skip versions.
+- You must keep the all nodes with the same version. Do not mix versions in the same cluster.
+
+All node roles (liaison and data) can be upgraded using the same procedure.
+
+## Upgrade a Single Node
+
+- Stop the server by sending a `SIGINT` or `SIGTERM` signal to the process.
+- Wait for the server to stop gracefully.
+- Replace the binary with the new version.
+- Start the server with the same configuration.
+
+## Rolling Strategy to Upgrade a Cluster
+
+Before upgrading the cluster, you should check CHANGELOG.md](https://github.com/apache/skywalking-banyandb/tree/master/CHANGES.md) to ensure that there are no breaking changes in the new version.
+
+- Upgrade the nodes one by one.
+- Wait for the node to join the cluster and become healthy before upgrading the next node.
+- Upgrade "data" nodes first, then "liaison" nodes.
+- After upgrading all nodes, the cluster will be running the new version.
+
+To ensure this strategy works, you should have a minimum of one node for each role of node in the cluster. For example, if you have a 2-node cluster, you should have at least one "liaison" and one "data" node.
+
+The cluster should also have enough capacity to handle the load when one node is down for upgrade.
+
+## Minimum Downtime Strategy to Upgrade a Cluster
+
+If the new version has breaking changes, you can use the following strategy to upgrade the cluster with minimum downtime:
+
+- Stop "liaison" nodes gracefully in a parallel manner.
+- Stop "data" gracefully.
+- Start the new version of "data" nodes.
+- Start the new version of "liaison" nodes.
+
+The data ingestion and retrieval will be stopped during the upgrade process. The downtime will be the sum of the time taken to stop and start the nodes. All these steps should be running in parallel to minimize the downtime.
+
+If you don't have enough resource to perform a rolling upgrade or you have a large cluster with many nodes, you can use the minimum downtime strategy.
+
+## Rollback
+
+If you encounter any issues during the upgrade process, you can rollback to the previous version by following the same procedure as the upgrade process. If file format is backward compatible, you can rollback to the previous version without any data loss. Please check the [CHANGELOG.md](https://https://github.com/apache/skywalking-banyandb/tree/master/CHANGES.md) to ensure that old version is compatible with the new data files.
diff --git a/pkg/test/helpers/http_health.go b/pkg/test/helpers/http_health.go
index bce8b485..80d7d621 100644
--- a/pkg/test/helpers/http_health.go
+++ b/pkg/test/helpers/http_health.go
@@ -18,7 +18,11 @@
package helpers
import (
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
"fmt"
+ "os"
"time"
"github.com/go-resty/resty/v2"
@@ -27,12 +31,28 @@ import (
)
// HTTPHealthCheck returns a function for ginkgo "Eventually" poll it repeatedly to check whether a HTTP server is ready.
-func HTTPHealthCheck(addr string) func() error {
+func HTTPHealthCheck(addr, cert string) func() error {
return func() error {
client := resty.New()
+ schema := "http"
+ if cert != "" {
+ // #nosec G402
+ config := tls.Config{}
+ cert, err := os.ReadFile(cert)
+ if err != nil {
+ return err
+ }
+ certPool := x509.NewCertPool()
+ if !certPool.AppendCertsFromPEM(cert) {
+ return errors.New("failed to add server's certificate")
+ }
+ config.RootCAs = certPool
+ client.SetTLSClientConfig(&config)
+ schema = "https"
+ }
resp, err := client.R().
SetHeader("Accept", "application/json").
- Get(fmt.Sprintf("http://%s/api/healthz", addr))
+ Get(fmt.Sprintf("%s://%s/api/healthz", schema, addr))
if err != nil {
time.Sleep(1 * time.Second)
return err
diff --git a/pkg/test/setup/setup.go b/pkg/test/setup/setup.go
index a9596105..b9ceb112 100644
--- a/pkg/test/setup/setup.go
+++ b/pkg/test/setup/setup.go
@@ -115,7 +115,8 @@ func standaloneServer(path string, ports []int, schemaLoaders []SchemaLoader, ce
}
tlsEnabled := false
if certFile != "" && keyFile != "" {
- ff = append(ff, "--tls=true", "--cert-file="+certFile, "--key-file="+keyFile, "--http-grpc-cert-file="+certFile)
+ ff = append(ff, "--tls=true", "--cert-file="+certFile, "--key-file="+keyFile, "--http-grpc-cert-file="+certFile,
+ "--http-tls=true", "--http-cert-file="+certFile, "--http-key-file="+keyFile)
tlsEnabled = true
}
if len(flags) > 0 {
@@ -129,12 +130,13 @@ func standaloneServer(path string, ports []int, schemaLoaders []SchemaLoader, ce
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Eventually(helpers.HealthCheck(addr, 10*time.Second, 10*time.Second, grpclib.WithTransportCredentials(creds)), testflags.EventuallyTimeout).
Should(gomega.Succeed())
+ gomega.Eventually(helpers.HTTPHealthCheck(httpAddr, certFile), testflags.EventuallyTimeout).Should(gomega.Succeed())
} else {
gomega.Eventually(
helpers.HealthCheck(addr, 10*time.Second, 10*time.Second, grpclib.WithTransportCredentials(insecure.NewCredentials())),
testflags.EventuallyTimeout).Should(gomega.Succeed())
+ gomega.Eventually(helpers.HTTPHealthCheck(httpAddr, ""), testflags.EventuallyTimeout).Should(gomega.Succeed())
}
- gomega.Eventually(helpers.HTTPHealthCheck(httpAddr), testflags.EventuallyTimeout).Should(gomega.Succeed())
if schemaLoaders != nil {
schemaRegistry, err := schema.NewEtcdSchemaRegistry(
@@ -245,7 +247,7 @@ func LiaisonNode(etcdEndpoint string) (string, func()) {
"--etcd-endpoints", etcdEndpoint,
"--node-host-provider", "flag",
"--node-host", nodeHost)
- gomega.Eventually(helpers.HTTPHealthCheck(httpAddr), testflags.EventuallyTimeout).Should(gomega.Succeed())
+ gomega.Eventually(helpers.HTTPHealthCheck(httpAddr, ""), testflags.EventuallyTimeout).Should(gomega.Succeed())
gomega.Eventually(func() (map[string]*databasev1.Node, error) {
return helpers.ListKeys(etcdEndpoint, fmt.Sprintf("/%s/nodes/%s:%d", metadata.DefaultNamespace, nodeHost, ports[0]))
}, testflags.EventuallyTimeout).Should(gomega.HaveLen(1))
diff --git a/test/integration/distributed/setup/node_test.go b/test/integration/distributed/setup/node_test.go
index 2d48b784..b120d6bb 100644
--- a/test/integration/distributed/setup/node_test.go
+++ b/test/integration/distributed/setup/node_test.go
@@ -53,7 +53,7 @@ var _ = Describe("Node registration", func() {
"--etcd-endpoints", etcdEndpoint,
"--node-host-provider", "flag",
"--node-host", nodeHost)
- Eventually(helpers.HTTPHealthCheck(httpAddr), flags.EventuallyTimeout).Should(Succeed())
+ Eventually(helpers.HTTPHealthCheck(httpAddr, ""), flags.EventuallyTimeout).Should(Succeed())
Eventually(func() (map[string]*databasev1.Node, error) {
return helpers.ListKeys(etcdEndpoint, fmt.Sprintf("/%s/nodes/%s:%d", namespace, nodeHost, ports[0]))
}, flags.EventuallyTimeout).Should(HaveLen(1))
diff --git a/test/integration/etcd/client_test.go b/test/integration/etcd/client_test.go
index ddfb4797..ae22e81d 100644
--- a/test/integration/etcd/client_test.go
+++ b/test/integration/etcd/client_test.go
@@ -126,7 +126,7 @@ var _ = Describe("Client Test", func() {
"--etcd-password", password)
defer closeFn()
- Eventually(helpers.HTTPHealthCheck(httpAddr), flags.EventuallyTimeout).Should(Succeed())
+ Eventually(helpers.HTTPHealthCheck(httpAddr, ""), flags.EventuallyTimeout).Should(Succeed())
Eventually(func() (map[string]*databasev1.Node, error) {
return listKeys(etcdEndpoint, username, password, clientConfig, fmt.Sprintf("/%s/nodes/%s:%d", namespace, nodeHost, ports[0]))
}, flags.EventuallyTimeout).Should(HaveLen(1))
@@ -167,7 +167,7 @@ var _ = Describe("Client Test", func() {
"--etcd-tls-ca-file", caFilePath)
defer closeFn()
- Eventually(helpers.HTTPHealthCheck(httpAddr), flags.EventuallyTimeout).Should(Succeed())
+ Eventually(helpers.HTTPHealthCheck(httpAddr, ""), flags.EventuallyTimeout).Should(Succeed())
Eventually(func() (map[string]*databasev1.Node, error) {
return listKeys(etcdEndpoint, "", "", clientConfig, fmt.Sprintf("/%s/nodes/%s:%d", namespace, nodeHost, ports[0]))
}, flags.EventuallyTimeout).Should(HaveLen(1))
@@ -214,7 +214,7 @@ var _ = Describe("Client Test", func() {
"--etcd-tls-key-file", clientKeyFilePath)
defer closeFn()
- Eventually(helpers.HTTPHealthCheck(httpAddr), flags.EventuallyTimeout).Should(Succeed())
+ Eventually(helpers.HTTPHealthCheck(httpAddr, ""), flags.EventuallyTimeout).Should(Succeed())
Eventually(func() (map[string]*databasev1.Node, error) {
return listKeys(etcdEndpoint, "", "", clientConfig, fmt.Sprintf("/%s/nodes/%s:%d", namespace, nodeHost, ports[0]))
}, flags.EventuallyTimeout).Should(HaveLen(1))