今天的課程安排
流控
*****
### 流控
為什么要流控呢?
> 一年一度的「雙 11」又要到了,阿里的碼農們進入了一年中最辛苦的時光。各種容量評估、壓測、擴容讓我們忙得不可開交。洛陽親友如相問,就說我搞雙十一。
如何讓系統在洶涌澎湃的流量面前談笑風生?我們的策略是不要讓系統超負荷工作。如果現有的系統扛不住業務目標怎么辦?加機器!機器不夠怎么辦?業務降級,系統限流!
正所謂「他強任他強,清風拂山崗;他橫任他橫,明月照大江」,降級和限流是大促保障中必不可少的神兵利器,丟卒保車,以暫停邊緣業務為代價保障核心業務的資源,以系統不被突發流量壓掛為第一要務。
設置網站最大流量為1W第一個用戶進來返回正常信息第9999位用戶進來返回正常信息第1W1個用戶進來不提供服務
我們這里流控算法Token Bucket 令牌桶算法

用戶進來給他一個token,用戶離開就回收token
是不是很簡單啊!
golang實現思路
初始化一個channel
用戶進來判斷channel中數據的len 再判斷初始化max長度的大小
如果>=初始化長度就是流量過了
if < 初始化長度 就是流量還沒有到紅線
此時想channel添加數
如果用戶結束鏈接就想channel取數
哈哈非常easy吧 大家先動手實踐一下,再看我的代碼
這個就放在router文件夾下吧flowControl.go
```
package router
import "log"
type BucketLimit struct {
count int // 定義最大流量
bucket chan int // 定義令牌桶
}
func NewBucketLimit(cc int) *BucketLimit {
return &BucketLimit{
cc,
make(chan int,cc),
}
}
// 獲得令牌
func (cl *BucketLimit) GetConn() bool {
// 如果滿了
if len(cl.bucket) >= cl.count {
log.Println("滿了")
return false
}
// 沒有滿 就頒發令牌
cl.bucket <- 1
return true
}
// 回收令牌
func (cl *BucketLimit) ReleaseConn() {
i := <-cl.bucket
log.Printf("New connction coming:%d\n",i)
}
```
是不是非常簡單啊!
問題來了,寫是寫出來了,但是沒有和http關聯啊!
我們先做一個粗粒度的限流把,限制整個服務的流量
新建一個middleware.go
```
package router
import (
"GolangWebCourseware/response"
"github.com/julienschmidt/httprouter"
"net/http"
)
type middleWareHandle struct {
R *httprouter.Router
L *BucketLimit // 流控
}
func NewMiddleWareHandler(r *httprouter.Router,cc int) http.Handler {
handle := &middleWareHandle{}
handle.R =r
handle.L = NewBucketLimit(cc)
return handle
}
// 流控核心
func (m *middleWareHandle) ServeHTTP(w http.ResponseWriter,r *http.Request) () {
// 從桶中獲得令牌
if !m.L.GetConn() {
response.SendNormalResponse(w,"Too many requests",http.StatusTooManyRequests)
return
}
m.R.ServeHTTP(w,r)
defer func() {
// 當連接結束 令牌返回令牌桶中
m.L.ReleaseConn()
}()
}
```
修改main方法
```
func main() {
registerRouter := router.RegisterRouter()// 注冊路由
fmt.Println("server is runing ...")
// middleware 接替
handler := router.NewMiddleWareHandler(registerRouter,1000)
err := http.ListenAndServe(":8085", handler)
if err != nil {
fmt.Println("server error:",err.Error())
}
}
```
本次課程代碼:
[https://github.com/dollarkillerx/GolangWebCourseware/tree/%E6%B5%81%E6%8E%A7](https://github.com/dollarkillerx/GolangWebCourseware/tree/%E6%B5%81%E6%8E%A7)
- 初認GOlang Web
- 關于環境配置
- 路由
- 路由進階與目錄架構
- 靜態文件服務器
- 自定義Middleware
- 與MySQL起舞
- 主從模式概念
- 部署主從集群
- 分庫分表
- 補充:事務
- 補充:常用SQL示例
- Template使用
- 一些小的,但是要知道的東西
- 調度任務
- 流控算法
- 鑒權
- JWT鑒權前置知識:加密解密
- session
- 文件上傳與下載
- 帶緩存讀寫拷貝io
- 參考
- 寫好的文件上傳
- 文件下載
- 拓展:秒傳功能實現
- 擴展:分塊上傳和斷點續傳
- 擴展:分塊上傳
- 擴展:斷點續傳
- 擴展:分布式存儲
- 部署ceph集群
- cephAuth
- go操作ceph集群
- 擴展:云存儲
- go操作oss
- 補充:xorm框架
- 命令小結
- 補充:xorm框架高級部分
- 補充
- MongoDB
- 基礎概念
- 簡簡單單NoSql
- 操作集合(Collection)
- 操作文檔(Document)
- 帶條件的文檔 db.find
- 復雜條件抽文檔 db.find
- redis
- redis操作
- go操作redis
- (新增)配置鑒權
- 密碼學
- 文件校驗算法
- 未來課程的安排
- RPC實踐
- 爬蟲
- 正則表達式
- 爬取手機號
- 爬取郵箱
- 爬取超鏈接
- 爬取身份證號
- 并發爬圖片
- 擴展:CICD
- GO實現自動化部署系統
- 國際化支持
- 并發帶來問題的解決
- GOWEB小知識
- Sync包講解
- sync.Pool
- 千萬級WebSocket消息推送
- 微服務入門:開篇
- 路由通訊
- RabbitMQ
- RabbitMQ工作原理和轉發模式
- Dcoker 下 RabbitMQ and Ui
- Go操作RabbitMQ
- 初步微服務
- go-micro
- 補充:consul
- 快速入門
- 補充:consul超時
- 微服務架構
- 微服務架構全景圖
- 服務注冊和發現
- raft協議基本概念
- raft協議leader選舉詳解
- raft協議日志復制詳解
- raft協議safefy詳解
- rpc調用個服務監控
- etcd
- 命令行使用
- Golang操作etcd
- GO操作etcd OP方式 (分布式鎖基礎)
- etcd 分布式集群樂觀鎖
- (新增)鑒權
- 服務注冊
- 服務發現原理
- 選項設計模式介紹
- 基于插件的注冊組建
- 課前知識
- etcd注冊開發1
- ffmpeg
- 2.0新的啟航
- 高可用Mysql
- mysql邏輯架構
- 常見的MySQL高可用方案
- 索引
- MYSQL調優
- 什么影響了MYSQL的性能
- Mysql 服務器參數配置
- Go深入并發
- 基本同步原語
- 擴展同步原語
- 原子操作
- M P G 模型
- 簡單的消息總線
- GoMicro入門
- GO任務池編寫
- GO依賴注入
- 一些補充
- golang defer在什么時候執行
- 分布式理論篇(面試吹牛必備)
- CAP理論
- Raft協議
- 保證注冊中心的可靠性
- 鏈路追蹤
- 怎么實現強一致性