mirror of
https://github.com/DullJZ/s3-balance.git
synced 2026-09-06 08:16:38 +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`:监听地址与超时时间。
|
- `server`:监听地址与超时时间。
|
||||||
- `database`:GORM 支持 sqlite/mysql/postgres,并存储对象元数据、分片会话等。
|
- `database`:GORM 支持 sqlite/mysql/postgres,并存储对象元数据、分片会话等。
|
||||||
- `buckets`:列出真实与虚拟桶。`virtual: true` 的条目会对外暴露,真实桶为 `virtual: false`。可设置 `path_style` 与 `max_size`。
|
- `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 指标及路径。
|
- `metrics`:是否启用 Prometheus 指标及路径。
|
||||||
- `s3api`:Access/Secret Key、`proxy_mode`(true=服务代理,false=重定向)、`auth_required`(Basic Auth)、`virtual_host`(Host-style 路由)。
|
- `s3api`:Access/Secret Key、`proxy_mode`(true=服务代理,false=重定向)、`auth_required`(Basic Auth)、`virtual_host`(Host-style 路由)。
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ balancer:
|
|||||||
# - "round-robin": 轮询
|
# - "round-robin": 轮询
|
||||||
# - "least-space": 选择剩余空间最多的存储桶
|
# - "least-space": 选择剩余空间最多的存储桶
|
||||||
# - "weighted": 基于权重的随机选择
|
# - "weighted": 基于权重的随机选择
|
||||||
# - "consistent-hash": 一致性哈希(相同的key总是选择相同的存储桶)
|
|
||||||
strategy: "least-space"
|
strategy: "least-space"
|
||||||
|
|
||||||
# 健康检查周期
|
# 健康检查周期
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ func NewBalancer(manager *bucket.Manager, cfg *config.BalancerConfig) (*Balancer
|
|||||||
strategy = NewLeastSpaceStrategy()
|
strategy = NewLeastSpaceStrategy()
|
||||||
case "weighted":
|
case "weighted":
|
||||||
strategy = NewWeightedStrategy()
|
strategy = NewWeightedStrategy()
|
||||||
case "consistent-hash":
|
|
||||||
strategy = NewConsistentHashStrategy()
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown balancer strategy: %s", cfg.Strategy)
|
return nil, fmt.Errorf("unknown balancer strategy: %s", cfg.Strategy)
|
||||||
}
|
}
|
||||||
@@ -124,8 +122,6 @@ func (b *Balancer) SetStrategy(strategyName string) error {
|
|||||||
strategy = NewLeastSpaceStrategy()
|
strategy = NewLeastSpaceStrategy()
|
||||||
case "weighted":
|
case "weighted":
|
||||||
strategy = NewWeightedStrategy()
|
strategy = NewWeightedStrategy()
|
||||||
case "consistent-hash":
|
|
||||||
strategy = NewConsistentHashStrategy()
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown balancer strategy: %s", strategyName)
|
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 负载均衡配置
|
// BalancerConfig 负载均衡配置
|
||||||
type BalancerConfig struct {
|
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"` // 健康检查周期
|
HealthCheckPeriod time.Duration `yaml:"health_check_period"` // 健康检查周期
|
||||||
UpdateStatsPeriod time.Duration `yaml:"update_stats_period"` // 统计更新周期
|
UpdateStatsPeriod time.Duration `yaml:"update_stats_period"` // 统计更新周期
|
||||||
RetryAttempts int `yaml:"retry_attempts"` // 重试次数
|
RetryAttempts int `yaml:"retry_attempts"` // 重试次数
|
||||||
|
|||||||
Reference in New Issue
Block a user