Golang常用的中間件使用總結

從接觸go到現(xiàn)在大概接近一年時間了吧,主要用它來開發(fā)GPU集群管理的client端以及一些小的工具差凹,例如:服務端mock測試瘦材、ID生成器等厅须,給我的感覺就是高性能、低消耗食棕、夠輕量朗和,所以在目前容器化、微服務化火熱的今天簿晓,其扮演著重要角色眶拉,如:docker、k8s憔儿、istio忆植、prometheus等都是基于go開發(fā),國內(nèi)很多一線大廠都開始主推go作為他們的服務端開發(fā)語言谒臼,如:頭條朝刊、B站、流利說等蜈缤,其生態(tài)也在不斷的發(fā)展拾氓,今天主要將我之前用到過的常用組件和中間件總結分享一下,便于后續(xù)快速搭建開發(fā)環(huán)境底哥。

  1. Gin(github.com/gin-gonic/gin):web開發(fā)框架咙鞍,適合api接口房官、微服務開發(fā),相較于其他框架(iris续滋、beego)更輕量級和更好的性能翰守。其路由功能很強大提供分組功能,非常適合做api開發(fā)吃粒,具體demo如下:
    route := gin.Default()
    // get method
    route.GET("/testGet", func(c *gin.Context) {
        name := c.Query("name")
        c.String(http.StatusOK, "hello " + name)
    })

    // post method
    route.POST("/testPost", func(c *gin.Context) {
        param := Param{}
        if err := c.BindJSON(&param); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{
                "code": 1,
                "msg" : "error",
            })
            return
        }
        s := fmt.Sprintf("name:%s, age:%s", param.Name, param.Age)
        c.JSON(http.StatusOK, gin.H{
            "code": 0,
            "msg": s,
        })
    })

    // route group
    v1 := route.Group("/v1")
    {
        v1.POST("/getInfo", func(c *gin.Context) {
            name := c.PostForm("name")
            c.JSON(http.StatusOK, gin.H{"msg": "hello " + name})
        })
    }

    v2 := route.Group("/v2")
    {
        v2.POST("/getInfo", func(c *gin.Context) {
            name := c.PostForm("name")
            age := c.PostForm("age")
            s := fmt.Sprintf("hello %s, i'm %s", name, age)
            c.JSON(http.StatusOK, gin.H{"msg": s})
        })
    }

    route.Run(":8080")
  1. Mysql(github.com/go-sql-driver/mysql):mysql第三方開源庫的實現(xiàn)潦俺,提供原生sql功能,喜歡框架的童鞋可以去看看國人寫的Gorm徐勃,挺不錯的一個orm框架(我還是比較習慣寫原生sql ^ _ ^ )事示。
    // init
    dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:3306)/iray_proxy?charset=utf8mb4", "root", "root123", "127.0.0.1")
    conn, err := sql.Open("mysql", dataSourceName)
    if err != nil {
        panic(err)
    }
    db.SetMaxOpenConns(30)
    db.SetMaxIdleConns(10)
    db.SetConnMaxLifetime(10 * time.Minute)
    db.Ping()

    // select
    rows, err1 := conn.Query("select name, age from t_user where age > ? and age < ?", 20, 30)
    defer rows.Close()
    if err1 != nil {
        panic(err1)
    }
    result := make([]map[string] interface{}, 0)
    for rows.Next() {
        var name string
        var age  int

        err1 = rows.Scan(&name, &age)
        if err1 != nil {
            log.Printf("row scan error: %s", err1.Error())
        } else {
            record := make(map[string] interface{}, 1)
            record["name"] = name
            record["age"]  = age
            result = append(result, record)
        }
    }

    // insert
    stmt, err2 := conn.Prepare("insert into t_user (name, age) values (?, ?)")
    if err2 != nil {
        panic(err2)
    }
    rs, err3 := stmt.Exec("jack", 25)
    if err3 != nil {
        log.Printf("insert row error: %s", err3.Error())
    } else {
        rowCount, _ := rs.RowsAffected()
        log.Printf("insert row count: %s", strconv.FormatInt(rowCount, 10))
    }

    // update
    stm1, err4 := conn.Prepare("update t_user set age = ? where name = ?")
    if err4 != nil {
        panic(err4)
    }
    rs1, err5 := stm1.Exec(30, "jack")
    if err5 != nil {
        log.Printf("update row error: %s", err5.Error())
    } else {
        rowCount, _ := rs1.RowsAffected()
        log.Printf("update row count: %s", strconv.FormatInt(rowCount, 10))
    }

    // delete
    rs2, err6 := conn.Exec("delete from t_user where name = ?", "jack")
    if err6 != nil {
        panic(err6)
    }
    rowCount, _ := rs2.RowsAffected()
    log.Printf("delete row count: %s", strconv.FormatInt(rowCount, 10))
  1. Redis(github.com/go-redis/redis):redis客戶端的第三方開源庫,比較出名兩個中的一個僻肖,還有個是redigo(github.com/garyburd/redigo/redis)肖爵,喜歡誰就用誰,我使用的是go-redis臀脏,具體操作如下:
    // Init
    redisClient := redis.NewClient(&redis.Options{
        Addr:     "127.0.0.1:6379",
        Password: "123456",
        DB:       1,
        PoolSize: 50,
    })

    // Hash
    err := redisClient.HSet("hash_key", "name", "jason statham").Err()
    if err != nil {
        log.Printf("hset error: %s", err)
    }
    resp := redisClient.HGet("hash_key", "name").Val()
    log.Printf("hget result: %s", resp)

    // List
    err = redisClient.RPush("list_key", "adam levin").Err()
    if err != nil {
        log.Printf("right push error: %s", err)
    }
    rs, err := redisClient.LPop("list_key").Result()
    log.Printf("left pop : %s", rs)

    // Set
    err = redisClient.SAdd("set_key", "harry kane").Err()
    if err != nil {
        log.Printf("add error: %s", err)
    }
    resultSet, err := redisClient.SMembers("set_key").Result()
    if err != nil {
        log.Printf("smembers error : %s", err)
    } else {
        for i, item := range resultSet {
            log.Printf("smembers item[%s] : %s", strconv.Itoa(i), item)
        }
    }

    // SortSet
    item := redis.Z{Score: float64(time.Now().Unix()), Member: "jet brains"}
    count, err := redisClient.ZAdd("sortset_key", item).Result()
    if err != nil {
        log.Printf("zadd error : %s", err)
    } else {
        log.Printf("zadd count : %s", strconv.FormatInt(count, 10))
    }
    results, err := redisClient.ZRangeByScore("sortset_key", redis.ZRangeBy{Max: strconv.FormatInt(time.Now().Unix(), 10)}).Result()
    if err != nil {
        log.Printf("zrangeByScore error : %s", err)
    } else {
        for i, item := range results {
            log.Printf("zrangeByScore item[%s] : %s", strconv.Itoa(i), item)
        }
    }
  1. Zookeeper(github.com/samuel/go-zookeeper/zk):分布式協(xié)作服務客戶端第三方開源庫的實現(xiàn)劝堪,具體代碼如下:
    // watch
    option := zk.WithEventCallback(func(event zk.Event) {
        eventType := event.Type.String()
        log.Printf("event name : %s", eventType)
    })
    // acl
    acl := zk.WorldACL(zk.PermAll)
    // root path
    path := "/go/zookeeper"

    conn,_,err := zk.Connect([]string{"127.0.0.1:2181"}, 5 * time.Second, option)
    if err != nil {
        panic(err)
    }

    // create znode
    _, err = conn.Create(path, []byte("duang"), 0, acl)
    if err != nil {
        log.Printf("create znode error : %s", err)
    }

    // set
    _, err = conn.Set(path, []byte("duang duang"), 1)
    if err != nil {
        log.Printf("set error : %s", err)
    }

    // get node and set watch
    data, stat, _, _ := conn.GetW(path)
    if data != nil {
        log.Println("zk get response:", string(data), ", stat:", stat.Version)
    }

    // exist znode
    exist, _, _, existErr := conn.ExistsW(path)
    if existErr != nil {
        log.Printf("exist znode error: %s", existErr)
        return
    }
    log.Printf("exist znode response : %s", strconv.FormatBool(exist))

    // watch children
    children, _, _, err := conn.ChildrenW(path)
    if err != nil {
        log.Printf("watch children error: %s", err)
    }
    if len(children) > 0 {
        for item := range children {
            log.Printf("watch children : %s", item)
        }
    }
  1. Kafka(github.com/Shopify/sarama):kafka的第三方客戶端實現(xiàn),生產(chǎn)者和消費者實現(xiàn)如下:
    // producer
    config := sarama.NewConfig()
    config.Producer.RequiredAcks = sarama.WaitForAll
    config.Producer.Partitioner = sarama.NewRandomPartitioner
    config.Producer.Return.Successes = true

    producer, err := sarama.NewSyncProducer([]string{"127.0.0.1:9092"}, config)
    if err != nil {
        panic(err)
    }
    defer producer.Close()

    // send msg
    param := make(map[string]string)
    param["name"] = "jack"
    param["sex"] = "male"

    js, err := json.Marshal(param)
    if err != nil {
        log.Printf("json err: %s", err.Error())
    } else {
        msg := &sarama.ProducerMessage{}
        msg.Topic = "kafka_test"
        msg.Value = sarama.ByteEncoder(js)

        partition, offset, err := producer.SendMessage(msg)
        if err != nil {
            log.Printf("failed to produce message :%s", err.Error())
        }
        log.Printf("partition:%d, offset: %d", partition, offset)
    }

    // consumer
    var wg sync.WaitGroup
    consumer, err := sarama.NewConsumer([]string{"127.0.0.1:9092"}, nil)
    if err != nil{
        panic(err)
    }
    defer consumer.Close()

    partitionList, err := consumer.Partitions("kafka_test")  // get topic all partitions
    if err != nil{
        log.Println("Failed to get the list of partition: ",err)
        return
    }
    // recieve msg
    for partition := range partitionList{
        pc, err := consumer.ConsumePartition("kafka_test", int32(partition), sarama.OffsetNewest)
        if err != nil{
            log.Printf("Failed to start consumer for partition %d: %s", partition, err)
            return
        }
        wg.Add(1)
        go func(sarama.PartitionConsumer) {
            for msg := range pc.Messages(){
                log.Printf("Partition:%d, Offset:%d, key:%s, value:%s", msg.Partition, msg.Offset, string(msg.Key),string(msg.Value))
            }
            defer pc.AsyncClose()
            wg.Done()
        }(pc)
    }
    wg.Wait()
  1. ElasticSearch(github.com/olivere/elastic):ES的第三方客戶端開源庫揉稚,主要提供增秒啦、刪、改搀玖、查和搜索的實現(xiàn)余境。
    // init
    esClient, err := elastic.NewClient(
        elastic.SetURL("http://127.0.0.1:9200"),
        elastic.SetScheme("http"),
        // health check
        elastic.SetHealthcheck(true),
        elastic.SetHealthcheckTimeoutStartup(5*time.Second),
        elastic.SetHealthcheckTimeout(2*time.Second),
        elastic.SetHealthcheckInterval(60*time.Second),
        // sniffer
        elastic.SetSniff(true),
        elastic.SetSnifferInterval(15*time.Minute),
        elastic.SetSnifferTimeoutStartup(5*time.Second),
        elastic.SetSnifferTimeout(2*time.Second),
        elastic.SetSendGetBodyAs("GET"),
    )
    if err != nil {
        panic(err)
    }

    // create
    param := `{"first_name":"jason","last_name":"kid","age":40}`
    resp, err := esClient.Index().
        Index("es_test").
        Type("employee").
        Id("1").
        BodyJson(param).
        Do(context.Background())
    if err != nil {
        log.Printf("create error: %s", err)
    } else {
        log.Printf("Indexed tweet %s to index s%s, type %s", resp.Id, resp.Index, resp.Type)
    }

    // update
    res, err := esClient.Update().
        Index("es_test").
        Type("employee").
        Id("1").
        Doc(map[string]interface{}{"age": 88}).
        Do(context.Background())
    if err != nil {
        log.Printf("update error: %s", err)
    } else {
        log.Printf("update age %s\n", res.Result)
    }

    // delete
    resDel, err := esClient.Delete().
        Index("es_test").
        Type("employee").
        Id("1").
        Do(context.Background())
    if err != nil {
        log.Printf("delete error: %s", err)
    } else {
        log.Printf("delete result %s", resDel.Result)
    }

    // get
    resGet, err := esClient.Get().
        Index("es_test").
        Type("employee").
        Id("1").
        Do(context.Background())
    if err != nil {
        log.Printf("get error: %s", err)
    } else if resGet.Found {
        log.Printf("Get document %s in version %d from index %s, type %s", resGet.Id, resGet.Version, resGet.Index, resGet.Type)
    }

    // search
    resQuery, err := esClient.Search("es_test").
        Type("employee").
        Query(elastic.NewQueryStringQuery("first_name:jason")).
        Do(context.Background())
    if err != nil {
        log.Printf("query error: %s", err)
    } else if resQuery.Hits.TotalHits > 0 {
        for _, hit := range resQuery.Hits.Hits {
            b,_ := hit.Source.MarshalJSON()
            log.Printf("employee item : %s ", string(b))
        }
    }
  1. Cron(github.com/robfig/cron):定時任務第三方庫,支持克隆表達式灌诅,很強大芳来。
    c := cron.New()
    c.AddFunc("*/30 * * * * ?", func() {
        // to do something
        log.Println("run task ...")
    })
    c.Start()
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市猜拾,隨后出現(xiàn)的幾起案子即舌,更是在濱河造成了極大的恐慌,老刑警劉巖挎袜,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顽聂,死亡現(xiàn)場離奇詭異,居然都是意外死亡宋雏,警方通過查閱死者的電腦和手機芜飘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磨总,“玉大人嗦明,你說我怎么就攤上這事◎窖啵” “怎么了娶牌?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵奔浅,是天一觀的道長。 經(jīng)常有香客問我诗良,道長汹桦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任鉴裹,我火速辦了婚禮舞骆,結果婚禮上,老公的妹妹穿的比我還像新娘径荔。我一直安慰自己督禽,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布总处。 她就那樣靜靜地躺著狈惫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹦马。 梳的紋絲不亂的頭發(fā)上胧谈,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音荸频,去河邊找鬼菱肖。 笑死,一個胖子當著我的面吹牛旭从,可吹牛的內(nèi)容都是我干的蔑滓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼遇绞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了燎窘?” 一聲冷哼從身側響起摹闽,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎褐健,沒想到半個月后付鹿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蚜迅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年舵匾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谁不。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡坐梯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出刹帕,到底是詐尸還是另有隱情吵血,我是刑警寧澤谎替,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蹋辅,受9級特大地震影響钱贯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜侦另,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一秩命、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧褒傅,春花似錦弃锐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碌尔,卻和暖如春浇辜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唾戚。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工柳洋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叹坦。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓熊镣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親募书。 傳聞我的和親對象是個殘疾皇子绪囱,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • # Python 資源大全中文版 我想很多程序員應該記得 GitHub 上有一個 Awesome - XXX 系列...
    小邁克閱讀 2,963評論 1 3
  • 一切皆因簡書而起。 簡書用戶設置里有語言設置這一項莹捡,可以自定義選擇簡體中文鬼吵、繁體中文、英文三種語言選項篮赢,不同的用戶...
    黃楊ME閱讀 404評論 0 1
  • 今天去教室學習齿椅,進去教室的時候,我的直覺告訴我有點奇怪启泣,然后看看學習的同學就覺得更詭異了涣脚, 因為平時學習的時...
    杰克是機長閱讀 251評論 0 1
  • 簡介 一本關于閑聊的正經(jīng)書。作者區(qū)分了談話的兩類:閑聊與重點專題會談寥茫,指出閑聊雖然沒有實質(zhì)性內(nèi)容遣蚀,但仍然很有意義,...
    淺薄123閱讀 860評論 0 5
  • “災難無情射富,人有情;在災難面前粥帚,一切眾生的愛都會無限放大胰耗。我們堅信,愛與支持芒涡,是最最有力量的柴灯。希望大家都可以用心為...
    可愛的派大星星閱讀 155評論 0 0