架構學習之路(二)-- 高並發實踐

來源:互聯網
上載者:User

(轉自:https://blog.csdn.net/Jeanphorn/article/details/79018205)

方案演化

1.直接使用goroutine

在Go語言原生並發的支援下,我們可以直接使用一個goroutine(如下方式)去平行處理這個請求。但是,這種方法明顯有些不好的地方,我們沒法控制goroutine產生數量,如果處理常式稍微耗時,在單機萬級十萬級qps請求下,goroutine大規模爆發,記憶體暴漲,處理效率會很快下降甚至引發程式崩潰。

go handle(request)
goroutine協同帶緩衝的管道

我們定義一個帶緩衝的管道

var queue = make(chan job, MAX_QUEUE_SIZE)

然後起一個協程處理管道傳來的請求

go func(){   for {    select {        case job := <-queue:            job.Do(request)        case <- quit:            return    }   }}()

接收請求,發送job進行處理

job := &Job{request}queue <- job

講真,這種方法使用了緩衝隊列一定程度上了提高了並發,但也是治標不治本,大規模並發只是延遲了問題的發生時間。當請求速度遠大於隊列的處理速度時,緩衝區很快被打滿,後面的請求一樣被堵塞了。

2.job隊列+工作池

只用緩衝隊列不能解決根本問題,這時候我們可以參考一下線程池的概念,定一個工作池(協程池),來限定最大goroutine數目。每次來新的job時,從工作池裡取出一個可用的worker來執行job。這樣一來即保障了goroutine的可控性,也儘可能大的提高了並發處理能力。


job隊列+工作池.png
工作池實現

首先,我們定義一個job的介面, 具體內容由具體job實現

type Job interface {    Do() error}

然後定義一下job隊列和work池類型,這裡我們work池也用golang的channel實現。

// define job channeltype JobChan chan Job// define worker channertype WorkerChan chan JobChan

我們分別維護一個全域的job隊列和工作池。

var (    JobQueue          JobChan    WorkerPool        WorkerChan)

worker的實現。每一個worker都有一個job channel,在啟動worker的時候會被註冊到work pool中。啟動後通過自身的job channel取到job並執行job。

type Worker struct {    JobChannel JobChan    quit       chan bool}func (w *Worker) Start() {    go func() {        for {            // regist current job channel to worker pool            WorkerPool <- w.JobChannel            select {            case job := <-w.JobChannel:                if err := job.Do(); err != nil {                    fmt.printf("excute job failed with err: %v", err)                }            // recieve quit event, stop worker            case <-w.quit:                return            }        }    }()}

實現一個分發器(Dispatcher)。分發器包含一個worker的指標數組,啟動時執行個體化並啟動最大數目的worker,然後從job隊列中不斷取job選擇可用的worker來執行job。

type Dispatcher struct {    Workers []*Worker    quit    chan bool}func (d *Dispatcher) Run() {    for i := 0; i < MaxWorkerPoolSize; i++ {        worker := NewWorker()        d.Workers = append(d.Workers, worker)        worker.Start()    }    for {        select {        case job := <-JobQueue:            go func(job Job) {                jobChan := <-WorkerPool                jobChan <- job            }(job)        // stop dispatcher        case <-d.quit:            return        }    }}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.