Golang负载均衡

请求者向均衡服务发送请求

type Request struct {
  fn func() int  // The operation to perform.
  c  chan int    // The channel to return the result.
}

注意这返回的通道是放在请求内部的。通道是first-class值

能很好的模拟一个请求者,一个负载产生者

func requester(work chan<- Request) {
  c := make(chan int)
  for {
      // Kill some time (fake load).
      Sleep(rand.Int63n(nWorker * 2 * Second))
      work <- Request{workFn, c} // send request
      result := <-c              // wait for answer
      furtherProcess(result)  
  }    
}

请求通道,加上一些负载记录数据

type Worker struct {
  requests chan Request // work to do (buffered channel)
  pending  int          // count of pending tasks
  index     int         // index in the heap
}

均衡服务将请求发送给压力最小的worker

func (w *Worker) work(done chan *Worker) {
  for {
      req := <-w.requests // get Request from balancer
      req.c <- req.fn()   // call fn and send result
      done <- w           // we've finished this request
  }
}

请求通道(w.requests)将请求提交给各个worker。均衡服务跟踪请求待处理的数量来判断负载情况。

每个响应直接反馈给它的请求者。

定义负载均衡器

// 负载均衡器需要一个装很多worker的池子和一个通道来让请求者报告任务完成情况。
type Pool []*Worker
type Balancer struct {
  pool Pool
  done chan *Worker
}

负载均衡函数

func (b *Balancer) balance(work chan Request) {
  for {
      select {
      case req := <-work: // received a Request...
          b.dispatch(req) // ...so send it to a Worker
      case w := <-b.done: // a worker has finished ...
          b.completed(w)  // ...so update its info
      }
  }
}

将负载均衡的池子用一个Heap接口实现

// 使用堆来跟踪负载情况
func (p Pool) Less(i, j int) bool {
  return p[i].pending < p[j].pending
}

Dispatch

// Send Request to worker
func (b *Balancer) dispatch(req Request) {
  // Grab the least loaded worker...
  w := heap.Pop(&b.pool).(*Worker)
  // ...send it the task.
  w.requests <- req
  // One more in its work queue.
  w.pending++
  // Put it into its place on the heap.
  heap.Push(&b.pool, w)
}

Completed

// Job is complete; update heap
func (b *Balancer) completed(w *Worker) {
  // One fewer in the queue.
  w.pending--
  // Remove it from heap.                  
  heap.Remove(&b.pool, w.index)
  // Put it into its place on the heap.
  heap.Push(&b.pool, w)
}

一个复杂的问题可以被拆分成容易理解的组件。它们可以被并发的处理。结果就是容易理解,高效,可扩展,好用。或许更加并行。

本文分享自微信公众号 - Golang语言社区(Golangweb),作者:丶沙工

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-11-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Golang语言社区--游戏开发-Tiled Map Editor瓦片地图编辑器使用教程

    Tiled 地图编辑器是一种用于通用目的的编辑器,可以用来创建2D和2.5D的地图。特点是比较好用,风格类似mini版的Photoshop Tiled 地图编辑...

    李海彬
  • 设计Go API的管道使用原则

    管道是并发安全的队列,用于在Go的轻量级线程(Go协程)之间安全地传递消息。总的来讲,这些原语是Go语言中最为称道的特色功能之一。这种消息传递范式使得开发者可以...

    李海彬
  • golang 裸写一个pool池控制协程的大小

    这几天深入的研究了一下golang 的协程,读了一个好文 http://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mi...

    李海彬
  • 不够持久?大疆无人机有了新无线充电系统,电力增强+++

    现在电力增强大法来了。据外媒GeekWire报道,专注于无人机和机器人无线充电的美国公司WiBotic为大疆研发出商用级无人机的无线电源系统,让无人机更持久。

    量子位
  • 解决MIUI8的冻结反弹

    用户1907613
  • RocketMQ Cluster命令【实战笔记】

    瓜农老梁
  • 7.11 VR扫描:Oculus VR或将低于399美元;美图与Natura推口红试妆服务

    VRPinea
  • 将iOS项目进行子工程化 原

        在iOS项目开发中,随着项目的越来越大,工程的结构化会变差,编译的速度也会越来越慢。使用静态库或动态库的方式来构建子工程不仅可以加快项目的编译速度,从结...

    珲少
  • 腾讯企业邮箱的安全技术实力介绍

    在网络时代,网络给企业带来各种便利的同时,也带来了各种信息安全问题。钓鱼软件、木马、欺诈邮件等恶意病毒给企业带来了巨大的信息安全风险,各种“泄密门”、“棱镜门”...

    小小强
  • 3. Powershell关键命令介绍

    我们将在这介绍三种简单的但是很关键的命令,这些命令能够让你的 Powershell之旅更加顺利。

    py3study

扫码关注云+社区

领取腾讯云代金券