mirror of
https://github.com/DullJZ/s3-balance.git
synced 2026-07-02 00:21:21 +08:00
Remove consistent hash
This commit is contained in:
@@ -38,7 +38,7 @@ docker run -p 8080:8080 -v $(pwd)/config:/root/config s3-balance
|
||||
- `server`:监听地址与超时时间。
|
||||
- `database`:GORM 支持 sqlite/mysql/postgres,并存储对象元数据、分片会话等。
|
||||
- `buckets`:列出真实与虚拟桶。`virtual: true` 的条目会对外暴露,真实桶为 `virtual: false`。可设置 `path_style` 与 `max_size`。
|
||||
- `balancer`:策略 (`round-robin`|`least-space`|`weighted`|`consistent-hash`)、健康检查周期、重试次数与延迟。
|
||||
- `balancer`:策略 (`round-robin`|`least-space`|`weighted`)、健康检查周期、重试次数与延迟。
|
||||
- `metrics`:是否启用 Prometheus 指标及路径。
|
||||
- `s3api`:Access/Secret Key、`proxy_mode`(true=服务代理,false=重定向)、`auth_required`(Basic Auth)、`virtual_host`(Host-style 路由)。
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ balancer:
|
||||
# - "round-robin": 轮询
|
||||
# - "least-space": 选择剩余空间最多的存储桶
|
||||
# - "weighted": 基于权重的随机选择
|
||||
# - "consistent-hash": 一致性哈希(相同的key总是选择相同的存储桶)
|
||||
strategy: "least-space"
|
||||
|
||||
# 健康检查周期
|
||||
|
||||
@@ -30,8 +30,6 @@ func NewBalancer(manager *bucket.Manager, cfg *config.BalancerConfig) (*Balancer
|
||||
strategy = NewLeastSpaceStrategy()
|
||||
case "weighted":
|
||||
strategy = NewWeightedStrategy()
|
||||
case "consistent-hash":
|
||||
strategy = NewConsistentHashStrategy()
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown balancer strategy: %s", cfg.Strategy)
|
||||
}
|
||||
@@ -124,8 +122,6 @@ func (b *Balancer) SetStrategy(strategyName string) error {
|
||||
strategy = NewLeastSpaceStrategy()
|
||||
case "weighted":
|
||||
strategy = NewWeightedStrategy()
|
||||
case "consistent-hash":
|
||||
strategy = NewConsistentHashStrategy()
|
||||
default:
|
||||
return fmt.Errorf("unknown balancer strategy: %s", strategyName)
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package balancer
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/DullJZ/s3-balance/internal/bucket"
|
||||
)
|
||||
|
||||
// ConsistentHashStrategy 一致性哈希策略
|
||||
// 使用一致性哈希算法,确保相同的key总是映射到相同的存储桶
|
||||
// 当存储桶增加或减少时,能够最小化数据迁移
|
||||
type ConsistentHashStrategy struct {
|
||||
replicas int // 每个节点的虚拟节点数
|
||||
ring map[uint32]*bucket.BucketInfo // 哈希环
|
||||
nodes []uint32 // 排序的哈希值列表
|
||||
mu sync.RWMutex // 读写锁,保护并发访问
|
||||
}
|
||||
|
||||
// NewConsistentHashStrategy 创建一致性哈希策略
|
||||
func NewConsistentHashStrategy() *ConsistentHashStrategy {
|
||||
return &ConsistentHashStrategy{
|
||||
replicas: 100, // 每个节点的虚拟节点数,越大分布越均匀
|
||||
ring: make(map[uint32]*bucket.BucketInfo),
|
||||
}
|
||||
}
|
||||
|
||||
// SelectBucket 选择存储桶(基于一致性哈希)
|
||||
// 相同的key总是会映射到相同的存储桶
|
||||
func (s *ConsistentHashStrategy) SelectBucket(buckets []*bucket.BucketInfo, key string, size int64) (*bucket.BucketInfo, error) {
|
||||
if len(buckets) == 0 {
|
||||
return nil, fmt.Errorf("no buckets available")
|
||||
}
|
||||
|
||||
// 更新哈希环
|
||||
s.updateRing(buckets)
|
||||
|
||||
// 计算key的哈希值
|
||||
hash := s.hash(key)
|
||||
|
||||
// 在环上找到第一个大于等于hash的节点
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
// 二分查找第一个大于等于hash的节点
|
||||
idx := sort.Search(len(s.nodes), func(i int) bool {
|
||||
return s.nodes[i] >= hash
|
||||
})
|
||||
|
||||
// 如果没找到,返回第一个节点(环形结构)
|
||||
if idx == len(s.nodes) {
|
||||
idx = 0
|
||||
}
|
||||
|
||||
return s.ring[s.nodes[idx]], nil
|
||||
}
|
||||
|
||||
// updateRing 更新哈希环
|
||||
// 为每个存储桶创建多个虚拟节点,使哈希分布更均匀
|
||||
func (s *ConsistentHashStrategy) updateRing(buckets []*bucket.BucketInfo) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// 清空现有环
|
||||
s.ring = make(map[uint32]*bucket.BucketInfo)
|
||||
s.nodes = nil
|
||||
|
||||
// 为每个存储桶添加虚拟节点
|
||||
for _, b := range buckets {
|
||||
for i := 0; i < s.replicas; i++ {
|
||||
// 为每个虚拟节点生成唯一的key
|
||||
virtualKey := fmt.Sprintf("%s-%d", b.Config.Name, i)
|
||||
hash := s.hash(virtualKey)
|
||||
s.ring[hash] = b
|
||||
s.nodes = append(s.nodes, hash)
|
||||
}
|
||||
}
|
||||
|
||||
// 排序节点,便于二分查找
|
||||
sort.Slice(s.nodes, func(i, j int) bool {
|
||||
return s.nodes[i] < s.nodes[j]
|
||||
})
|
||||
}
|
||||
|
||||
// hash 计算哈希值
|
||||
// 使用MD5算法,取前4个字节作为uint32
|
||||
func (s *ConsistentHashStrategy) hash(key string) uint32 {
|
||||
h := md5.Sum([]byte(key))
|
||||
return binary.BigEndian.Uint32(h[:4])
|
||||
}
|
||||
|
||||
// Name 返回策略名称
|
||||
func (s *ConsistentHashStrategy) Name() string {
|
||||
return "consistent-hash"
|
||||
}
|
||||
|
||||
// SetReplicas 设置虚拟节点数
|
||||
// 虚拟节点越多,负载分布越均匀,但内存使用也越多
|
||||
func (s *ConsistentHashStrategy) SetReplicas(replicas int) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if replicas > 0 {
|
||||
s.replicas = replicas
|
||||
// 清空现有环,下次选择时会重新构建
|
||||
s.ring = make(map[uint32]*bucket.BucketInfo)
|
||||
s.nodes = nil
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ type BucketConfig struct {
|
||||
|
||||
// BalancerConfig 负载均衡配置
|
||||
type BalancerConfig struct {
|
||||
Strategy string `yaml:"strategy"` // 负载均衡策略: "round-robin", "least-space", "weighted", "consistent-hash"
|
||||
Strategy string `yaml:"strategy"` // 负载均衡策略: "round-robin", "least-space", "weighted"
|
||||
HealthCheckPeriod time.Duration `yaml:"health_check_period"` // 健康检查周期
|
||||
UpdateStatsPeriod time.Duration `yaml:"update_stats_period"` // 统计更新周期
|
||||
RetryAttempts int `yaml:"retry_attempts"` // 重试次数
|
||||
|
||||
Reference in New Issue
Block a user