哈哈好久不見啦
今天課程的安排:
調度任務講解 (這個是全部課程的精華,大家認真練習啊)
*****
### 調度任務
應用場景:
我們現在有一個業務就是用戶注冊返送短信驗證碼
用戶注冊->執行短信驗證碼方法
一個用戶注冊就會發送短信驗證碼,這是同步操作的,中間就會發生阻塞,一個人注冊沒有什么感覺,但是10w人同時注冊這個服務器就吃不消了
如果解決這個問題就
我們在這里用到了一個水庫模型
想想:
現在有一條大河,突然有一天漲水了,然后呢?就淹沒城市了哈哈
然后怎么解決呢?就是不止一條河排水


一個用戶注冊,我們把發送短信這個放到一個隊列里面,開另一個服務他來消費這個請求
這個就是簡單的一個流量削峰
- 必備基礎 channel和goroutine并發編程基礎
不如不會去看看官方文檔吧 那個go指南這個還是挺簡單的
### 現在就開始上半部分的課程了 Scheduler
- task runner 生產/消費 模型
- timer 定時器
新建taskrunner文件夾
```
并建立一下文件
.
├── defs.go 定義
├── runner.go 任務調用核心
├── task.go 生產者消費者定義
└── trmain.go
```
defs.go
```
package taskrunner
const (
READY_TO_DISPATCH = "d" // 開始生產 通知
READY_TO_EXECUTE = "e" // 開始消費 通知
CLOSE = "c" // 停止 沒有任務可做,或者出錯
)
type controllerChan chan string // 通知 通知處理
type dataChan chan interface{} // 存放處理數據
type fn func (dc dataChan) error // 處理方法 生產者消費者方法
```
這樣講的有點多,就大概的講講實現思路吧,
用戶發送消息這個任務扔到MQ里面去,然后那邊就消費就可以了
- 講講定時任務
```
package taskrunner
import "time"
/**
timer
setup
start{trigger->task->runner}
*/
type Worker struct {
ticker *time.Ticker // 定時器
runner *Runner
}
func NewWorker(interval time.Duration,r *Runner) *Worker {
return &Worker{
ticker:time.NewTicker(interval * time.Second),
runner: r,
}
}
func (w *Worker) startWorker() {
for {
select {
case <- w.ticker.C://這個是阻塞的,當時間到了這里就放行了
go w.runner.StartAll()
}
}
}
func Start() {
// Start
//r :NewWor .....
}
```
定時任務就是通過<- w.ticker.C的阻塞實現的
我還是吧調度器的代碼給大家敲一遍,能夠理解的就理解下吧
```
package taskrunner
type Runner struct {
Controller controllerChan // 控制信息
Error controllerChan // 錯誤信息
Data dataChan // 數據
dataSize int // 數據大小
longlived bool // 是否長期存貨 tree不會回收資源
Dispatcher fn // 生產者
Executor fn // 消費者
}
func NewRunner(size int,longlived bool,dispatcher fn,executor fn) *Runner {
return &Runner{
Controller:make(chan string,1),// 我們這個需求是非阻塞的 所以用帶buffer的chan
Error:make(chan string,1),
Data:make(chan interface{},size),
longlived:longlived,
Dispatcher:dispatcher,
Executor:executor,
}
}
func (r *Runner) startDispatch() {
// 資源回收
defer func() {
if !r.longlived {
close(r.Controller)
close(r.Data)
close(r.Error)
}
}()
forloop:
for {
select {
case c := <-r.Controller:
if c == READY_TO_DISPATCH {
err := r.Dispatcher(r.Data)
if err != nil {
r.Error <- CLOSE
}else{
r.Controller <- READY_TO_EXECUTE
}
}
if c == READY_TO_EXECUTE {
err := r.Executor(r.Data)
if err != nil{
r.Error <- CLOSE
}else{
r.Controller <- READY_TO_DISPATCH
}
}
case e := <-r.Error:
if e == CLOSE {
return
}
default:
//如果執行這個 說明消費完了
break forloop
}
}
}
func (r *Runner) StartAll() {
r.Controller <- READY_TO_DISPATCH
r.startDispatch()
}
```
今日課程代碼
[https://github.com/dollarkillerx/GolangWebCourseware/tree/%E8%B0%83%E5%BA%A6%E5%99%A8](https://github.com/dollarkillerx/GolangWebCourseware/tree/%E8%B0%83%E5%BA%A6%E5%99%A8)
- 初認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協議
- 保證注冊中心的可靠性
- 鏈路追蹤
- 怎么實現強一致性