Go語言(十 八)context&日誌項目

context&日誌項目

context

一般場景下取消goroutine的方法

var wg sync.WaitGroup
var exit bool

func worker(exitChan chan struct{})  {
   LOOP:
   for {
      fmt.Printf("work\n")
      time.Sleep(time.Second)
      /*if exit {
         break
      }
       */
      select {
      case <- exitChan:
         break LOOP
      default:

      }
   }
   wg.Done()
}

func main()  {
   var exitChan chan struct{} = make(chan struct{},1)
   wg.Add(1)
   go worker(exitChan)
   time.Sleep(time.Second*3)
   exitChan <- struct{}{}
   //exit = true
   wg.Wait()
}
  • 場景:
    • 返回一個cancel函數,調用cancel函數的時候,會觸發context.Done()函數 [優雅退出線程]
var wg sync.WaitGroup
func worker(ctx context.Context) {
   LOOP:
   for {
      fmt.Printf("work\n")
      time.Sleep(time.Second)
      select {
      case <- ctx.Done():
         break LOOP
      default:

      }
   }
   wg.Done()
}
func main() {
   cxt := context.Background()
   cxt,cancel := context.WithCancel(cxt)
   wg.Add(1)
   go worker(cxt)
   time.Sleep(time.Second*3)
   cancel()    //取消goroutine
   wg.Wait()
}
  • trace 實例
var wg sync.WaitGroup
func worker(cxt context.Context)  {
   traceCode,ok := cxt.Value("TRACE_CODE").(string)
   if ok {
      fmt.Printf("traceCode=%s\n",traceCode)
   }
    LOOP:
   for {
      fmt.Printf("worker\n")
      time.Sleep(time.Millisecond)
      select {
      case <- cxt.Done():
         break LOOP
      default:
      }
   }
   fmt.Printf("worker Done,trace_Code:%s\n",traceCode)
   wg.Done()
}
func main()  {
   ctx := context.Background()
   ctx,cancel := context.WithTimeout(ctx,time.Millisecond*50)
   ctx = context.WithValue(ctx,"TRACE_CODE","212334121")
   wg.Add(1)
   go worker(ctx)
   time.Sleep(time.Second*3)
   cancel()     //釋放contex資源
   wg.Wait()
}

日誌項目(一)

日誌收集系統設計

  • 項目背景

    • 每個系統都有日誌,當系統出現問題的時候,需要通過日誌解決問題
    • 當系統及其比較少的時候,登陸到服務器上即可查看滿足
    • 當系統及其規模巨大,逐個登陸機器查看日誌幾乎不現實
  • 解決方案

    • 把機器上的日誌實時收集,統一存儲到中心繫統
    • 然後對這些日誌建立索引,通過搜索找到對應的日誌
    • 通過提供友好的web界面,通過web界面完成日誌搜索
  • 面臨的問題

    • 實時的日質量非常大,每天幾十億條
    • 日誌準實時收集,延遲控制在分鐘級別
    • 能夠水平拓展
  • 業界方案ELK
    • 存在的問題
      • 運維成本較高,每增加一個日誌收集,都需要手動去配置
      • 監控缺失,無法準確獲取logstash的狀態
      • 無法做定製化的開發以及維護
        Go語言(十 八)context&日誌項目

日誌收集系統設計

Go語言(十 八)context&日誌項目

  • 組件介紹
    • Log Agent: 日誌採集客戶端,用來收集服務器上的日誌
    • kafka: 高吞吐的分佈式消息隊列,linkin開發,apache頂級開源項目
    • ES: 開源的搜索引擎,基於http restful風格的web接口
    • Hadoop:分佈式計算框架

kafka的應用場景

高可用kafka集羣部署:https://blog.51cto.com/navyaijm/2429959?source=drh

  • 異步處理,把非關鍵流程異步化,提高系統響應時間和健壯性
    Go語言(十 八)context&日誌項目
  • 應用解耦
    Go語言(十 八)context&日誌項目
  • 流量削峯:高併發場景
    Go語言(十 八)context&日誌項目

zookeeper應用場景

  • 服務註冊與發現
    Go語言(十 八)context&日誌項目
  • 配置中心
    Go語言(十 八)context&日誌項目
  • 分佈式鎖
    • zookeeper是強一致的
    • 多個客戶端同事在zookeeper上創建相同的znode,只有一個創建成功

日誌客戶端開發

  • logAgent 設計
    Go語言(十 八)context&日誌項目

  • logagent的流程
    Go語言(十 八)context&日誌項目

kafka的使用

  • 導入的庫: go get github.com/Shopify/sarama
  • 使用代碼
import (
   "fmt"
   "github.com/Shopify/sarama"
   "time"
)

func main() {
   //初始化配置
   config := sarama.NewConfig()
   config.Producer.RequiredAcks = sarama.WaitForAll
   config.Producer.Partitioner = sarama.NewRandomPartitioner
   config.Producer.Return.Successes = true
   //消息配置
   msg := &sarama.ProducerMessage{}
   msg.Topic = "nginx_log"
   msg.Value = sarama.StringEncoder("this is a test,messsage transfer ok")
   //連接配置
   client,err := sarama.NewSyncProducer([]string{"192.168.56.11:9092"},config)
   if err != nil {
      fmt.Printf("send message faild,error:%v\n",err)
      return
   }

   defer client.Close()
   for   {
      pid,offset,err := client.SendMessage(msg)
      if err != nil {
         fmt.Printf("send message faild,err:%v\n",err)
         return
      }
      fmt.Printf("pid:%v,offset:%v\n",pid,offset)
      time.Sleep(time.Second)
   }
}

tailf 組件的使用

  • 導入的庫: go get github.com/hpcloud/tail
  • 使用代碼
import (
   "fmt"
   "github.com/hpcloud/tail"
   "time"
)

func main() {
   filename := "./my.log"
   tails,err := tail.TailFile(filename,tail.Config{
      Location:    &tail.SeekInfo{
         Offset: 0,
         Whence: 2,
      },
      ReOpen:      true,
      MustExist:   false,
      Poll:        true,
      Follow:      true,
   })

   if err != nil {
      fmt.Printf("tail file error:%v\n",err)
      return
   }

   var msg *tail.Line
   var ok bool
   for true {
      msg,ok = <- tails.Lines
      if !ok {
         fmt.Printf("tail file close reopen,filename:%s\n",filename)
         time.Sleep(100*time.Millisecond)
         continue
      }
      fmt.Printf("msg=%v\n",msg)
   }
}
  • kafka消費日誌命令參考
[root@centos7-node1 ~]# cd /opt/application/kafka/bin/
[root@centos7-node1 bin]# ./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic nginx_log --from-beginning
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章