從0實現分佈式任務調度系統--etcd基礎操作

  1. 下載: etcd-v3.3.18-linux-amd64.tar.gz  ;解壓: tar -zxvf etcd-v3.3.18-linux-amd64.tar.gz

解壓後的情況如下:

其中etcd是服務端程序,etcdctl是客戶端程序。

 

    2. 啓動etcd服務(後臺啓動,並監聽公網IP,默認只監聽localhost):

nohup ./etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379  &

使用less nohup.out 命令可以查看nohup.out 中的日誌輸出。

 

    3. 設置環境變量,將etcd的接口版本切換到V3

export ETCDCTL_API=3

 

    4. 下載etcd  go語言客戶端代碼:

https://github.com/etcd-io/etcd

使用go get 下載速度很慢,可以去golang中國下載相應的包。

將GitHub中項目代碼對應的路徑複製到“導入路徑”這一欄目中(不能有HTTP前綴,不然會報錯)。

    5. 調整etcdclientv3的目錄,導入時如下所示:

GoWorks\src\go.etcd.io\etcd  (etcd爲下載後解壓的代碼)

完成前面5步後,就可以開始使用etcd 的go語言接口進行編程操作了。

 

獲取指定目錄下的內容:

func main() {
   var (
      config clientv3.Config
      client *clientv3.Client
      err error
      kv clientv3.KV
      //putResp *clientv3.PutResponse
      getResp *clientv3.GetResponse
   )

   config = clientv3.Config{
      Endpoints:[]string{"11.32.225.63:2379"},  // 集羣列表
      DialTimeout:5 * time.Second,
   }

   // 建立一個客戶端
   if client,err = clientv3.New(config); err != nil{
      fmt.Println(err)
      return
   }
   defer client.Close()

   // 讀寫etcd的鍵值對
   kv = clientv3.NewKV(client)

   // 讀取/cron/jobs/爲前綴的所有key
   if getResp, err = kv.Get(context.TODO(), "/corn/jobs/", clientv3.WithPrefix()); err != nil{
      fmt.Println(err)
   }else{
      // 獲取成功,遍歷所有的kvs
      fmt.Println(getResp.Kvs)
   }
}

clientv3.KV下的操作包括最基礎的Get/Put/Delete,分別用於獲取/存入/刪除一個鍵值對。

 

租約和事務操作:

func main() {

   var (
      config clientv3.Config
      client *clientv3.Client
      err error
      kv clientv3.KV
      lease clientv3.Lease
      leaseGrantResp *clientv3.LeaseGrantResponse
      leaseID clientv3.LeaseID
      keepResp *clientv3.LeaseKeepAliveResponse
      keepRespChan <-chan *clientv3.LeaseKeepAliveResponse
      ctx context.Context
      cancelFunc context.CancelFunc
      txn clientv3.Txn
      txnResp *clientv3.TxnResponse
   )

   config = clientv3.Config{
      Endpoints:[]string{"11.32.225.63:2379"},  // 集羣列表
      DialTimeout:5 * time.Second,
   }

   // 建立一個客戶端
   if client,err = clientv3.New(config); err != nil{
      fmt.Println(err)
      return
   }
   defer client.Close()

   //lease 實現鎖自動過期
   //op操作
   //txn事務: if else then

   // 申請一個租約lease
   lease = clientv3.NewLease(client)

   // 申請一個5s的租約
   if leaseGrantResp, err = lease.Grant(context.TODO(), 5);err != nil{
      fmt.Println(err)
      return
   }

   // 拿到租約的ID
   leaseID = leaseGrantResp.ID

   // 準備一個用於取消自動續租的context
   ctx, cancelFunc = context.WithCancel(context.TODO())

   // 確保函數退出後,自動續租會停止
   defer cancelFunc()
   defer lease.Revoke(context.TODO(), leaseID)

   // 自動續約,5s後取消自動續約
   if keepRespChan,err = lease.KeepAlive(ctx, leaseID);err != nil{
      fmt.Println(err)
      return
   }

   // 處理續約的應答協程
   go func() {
      for{
         select {
         case keepResp = <-keepRespChan:
            if keepResp == nil{
               fmt.Println("租約已經失效了")
               goto END
            }else{
               fmt.Println("收到自動續約應答:", keepResp.ID)
            }

         }
      }
   END:
   }()

   // if 不存在key, then設置它,else搶鎖失敗
   kv = clientv3.NewKV(client)

   // 1 創建事務
   txn = kv.Txn(context.TODO())

   //定義事務

   // 如果key不存在
   txn.If(clientv3.Compare(clientv3.CreateRevision("/cron/lock/job9"), "=", 0)).
      Then(clientv3.OpPut("/cron/lock/job9", "XXX", clientv3.WithLease(leaseID))).
      Else(clientv3.OpGet("/cron/lock/job9")) // 搶鎖失敗

   // 提交事務
   if txnResp,err = txn.Commit();err!=nil{
      fmt.Println(err)
      return
   }

   // 判斷是否搶到鎖
   if !txnResp.Succeeded{
      fmt.Println("鎖被佔用:", string(txnResp.Responses[0].GetResponseRange().Kvs[0].Value))
      return
   }

   // 2 處理業務
   fmt.Println("處理任務")
   time.Sleep(5 * time.Second)

   // 3 釋放鎖(取消自動續租,釋放租約)
   // defer會把租約釋放掉,關聯的KV就會被刪除
}

接口函數有很多,不能一一舉例了,自己試着調用一下,感覺學起來也還是挺快的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章