写点什么

《架构师训练营》第五周 命题作业

用户头像
关注
发布于: 2020 年 07 月 08 日

一、基本思路

  • 缓存服务器节点(CacheServerNode),用来模拟从缓存服务器获取缓存数据的行为。

  • 缓存服务器集群(CacheServerNodeGroup),用来创建和管理服务器节点。同时这个服务器集群类组合了负载均衡器的功能,用来命中服务器节点。考虑到真实场景中方便扩容、缩容,这里使用环形单项链表存储缓存服务器节点。

  • 负载均衡器(LoadBalancer),考虑到命中节点的算法会对系统的性能影响很大,这里把负载均衡器设计为一个接口,支持替换成不同的负载均衡算法的实现。

二、具体代码实现(Go 语言)

2.1 缓存服务器节点(CacheServerNode)

为了模拟真是服务器的场景,缓存服务器启动后会在创建一个协程和一个用于和协程通信的 channel。在协程内循环阻塞等待从 channel 读取数据然后记录到计数器上面,直到 channel 关闭,协程才会结束循环然后退出。节点提供了以下功能:

  • 启动、停止缓存服务器节点

  • 从缓存服务器节点获取数据(计数器加1)

type CacheServerNode struct {
Next *CacheServerNode
Name string
Hash uint32
ReadCount int
ServerChan chan string
isRunning bool
}
func (node *CacheServerNode) Get(key string) {
node.ReadCount++
fmt.Printf("CacheServerNode: %s, key: %s, current read count: %d\n", node.Name, key, node.ReadCount)
}
func (node *CacheServerNode) Start() error {
if node.isRunning {
return errors.New(fmt.Sprintf("CacheServerNode: %s already started!", node.Name))
}
go func(n *CacheServerNode) {
for true {
select {
case key, ok := <-n.ServerChan:
if !ok {
return
}
n.Get(key)
}
}
}(node)
return nil
}
func (node *CacheServerNode) Stop() {
fmt.Printf("Cache CacheServerNode: %s\t, CacheServerNode Hash: %d\t, ReadCount: %d\n", node.Name, node.Hash, node.ReadCount)
close(node.ServerChan)
}

2.2 负载均衡器接口(LoadBalancer)

type LoadBalancer interface {
HitNode(nodes []*CacheServerNode, hash uint32) (*CacheServerNode, error)
}

2.3 缓存服务器集群(CacheServerNodeGroup)

缓存服务器集群提供了以下功能:

  • 启动、停止集群中的所有服务器

  • 读取数据(通过负载均衡器命中的缓存服务器节点读取)

  • 计算数据分布标准差

type CacheServerNodeGroup struct {
Selector LoadBalancer
CacheNodesCycle *CacheServerNode
CacheNodes []*CacheServerNode //为了支持二分查找算法
NodeCount int
Hasher hash.Hash32
}
func (ng *CacheServerNodeGroup) Get(key string) {
ng.Hasher.Reset()
_, _ = ng.Hasher.Write([]byte(key))
if node, err := ng.Selector.HitNode(ng.CacheNodes, ng.Hasher.Sum32()); err == nil {
node.Get(key)
}
}
func (ng *CacheServerNodeGroup) Boot() {
treeWalk(ng.CacheNodesCycle, func(node *CacheServerNode) {
if err := node.Start(); err != nil {
panic(err)
}
})
}
func (ng *CacheServerNodeGroup) Down() {
treeWalk(ng.CacheNodesCycle, func(node *CacheServerNode) {
node.Stop()
})
}
func (ng *CacheServerNodeGroup) KeyHitStandardDeviation() int64 {
totalKeys := 0
treeWalk(ng.CacheNodesCycle, func(node *CacheServerNode) {
totalKeys += node.ReadCount
})
average := totalKeys / ng.NodeCount
var squaredDifference int64
treeWalk(ng.CacheNodesCycle, func(node *CacheServerNode) {
squaredDifference += int64(node.ReadCount-average) * int64(node.ReadCount-average)
})
return int64(math.Sqrt(float64(squaredDifference / int64(ng.NodeCount))))
}

2.4 客户端代码

func main() {
loadBalancer := &consistences.SimpleLoadBalancer{}
ng := consistences.NewCacheNodeGroup(CacheNodeCount, crc32.NewIEEE(), loadBalancer)
ng.Boot()
for i := 0; i < KeyCount; i++ {
key := RandStringKey(KeyLength)
ng.Get(key)
}
ng.Down()
fmt.Printf("Standard Deviation: %d\n", ng.KeyHitStandardDeviation())
}

三、运行结果

CacheServerNode: CacheNode-1 Node Hash: 16415915 ReadKeyCount: 3747
CacheServerNode: CacheNode-5 Node Hash: 127383730 ReadKeyCount: 26054
CacheServerNode: CacheNode-9 Node Hash: 237106329 ReadKeyCount: 25313
CacheServerNode: CacheNode-4 Node Hash: 1888520228 ReadKeyCount: 385058
CacheServerNode: CacheNode-8 Node Hash: 2032583695 ReadKeyCount: 33244
CacheServerNode: CacheNode-2 Node Hash: 2582850833 ReadKeyCount: 127590
CacheServerNode: CacheNode-6 Node Hash: 2661214472 ReadKeyCount: 18359
CacheServerNode: CacheNode-7 Node Hash: 3919174046 ReadKeyCount: 293228
CacheServerNode: CacheNode-3 Node Hash: 4008975751 ReadKeyCount: 21082
CacheServerNode: CacheNode-0 Node Hash: 4294967295 ReadKeyCount: 66325

Standard Deviation: 125758



发布于: 2020 年 07 月 08 日阅读数: 48
用户头像

关注

还未添加个人签名 2018.06.14 加入

还未添加个人简介

评论

发布
暂无评论
《架构师训练营》第五周 命题作业