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的狀態
- 無法做定製化的開發以及維護
- 存在的問題
日誌收集系統設計
- 組件介紹
- Log Agent: 日誌採集客戶端,用來收集服務器上的日誌
- kafka: 高吞吐的分佈式消息隊列,linkin開發,apache頂級開源項目
- ES: 開源的搜索引擎,基於http restful風格的web接口
- Hadoop:分佈式計算框架
kafka的應用場景
高可用kafka集羣部署:https://blog.51cto.com/navyaijm/2429959?source=drh
- 異步處理,把非關鍵流程異步化,提高系統響應時間和健壯性
- 應用解耦
- 流量削峯:高併發場景
zookeeper應用場景
- 服務註冊與發現
- 配置中心
- 分佈式鎖
- zookeeper是強一致的
- 多個客戶端同事在zookeeper上創建相同的znode,只有一個創建成功
日誌客戶端開發
-
logAgent 設計
- logagent的流程
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