iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0

蝦米係NoSQL

NoSQL(Not Only SQL)是對不同於傳統的關聯式資料庫的資料庫管理系統的統稱。 允許部分資料使用SQL系統儲存,而其他資料允許使用NOSQL系統儲存。 其數據儲存可以不需要固定的表格模式以及中介資料(metadata),也經常會避免使用SQL的JOIN操作,一般有水平可延伸性的特徵。

以前接觸過的db都是RDBMS,像是informix(上古時代...),MSSQL,ORACLE,MYSQL等等,
因為可以join特性,所以可以做出n階層的資料結構,一個table不夠用就再多開一個table來join就好

NoSQL的優勢:

彈性:NoSQL 資料庫整體而言提供促進更快速及更能反覆開發的彈性結構描述。具彈性的資料模型讓 NoSQL 資料庫成為半結構和非結構式資料的理想資料庫。
可擴展性:NoSQL 資料庫一般的設計都能透過硬體的分散式叢集來向外擴展,而不必藉由增加昂貴和重量級的伺服器來進行垂直擴展。有些雲端供應商背後將這些操作處理成全受管服務。
高效能:NoSQL 資料庫針對特定資料模型加以優化,並且存取比使用關聯式資料庫達到相同功能的更高效能模式。
高功能性:NoSQL 資料庫提供專為各別資料模型而建造的高功能 API 和資料。

這邊有很詳細的說明 NoSQL

關於Redis

Redis 是一個 in-memory 的 key-value database,常用於需要cache資料的情境,這樣子可以減輕rdbms db的loading
例如像寫了一件api可以撈出火車時刻表的資料,但是這個資料需要join四個table,單次執行需要超過1s的時間,可是這個火車時刻表的資料當天的異動性很低,如果有人發現這個api很吃db資源,只要狂打api就可以輕鬆吃光db資源,再強大的db也禁不起這樣子的操作。
在這種情境下,是不是可以先把query出來的資料塞到某個地方,api打過來時先判斷有沒有cache,沒cache時再去撈db,撈完db再塞到cache裡面。
照這樣子的邏輯,基本上一天只會一次api是真的去撈db,後續api都直接從cache裡面撈資料來出來,對db的loading與api的效能來說都是很效的改善

安裝Redis

$ docker run -itd --name redis-test -p 6379:6379 redis

執行成功後可以在docker的dashboard上面看到新增了一個叫redis-test的container在運行

Golang的Redis套件Redigo/go-redis

Redigo目前星星數7.8k,go-redis目前9.8k,所以就選擇go-redis為主要的執行套件

安裝go-redis

go get -u github.com/go-redis/redis/v8

實作golang使用redis

package main

import (
	"context"
	"fmt"

	"github.com/go-redis/redis/v8"
)

func main() {
    //go-redis使用context當執行參數
	var ctx = context.Background()
    //連線redis
	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
    //確認redis是否還健在
	_, err := rdb.Ping(ctx).Result()
	if err != nil {
		fmt.Println("redis ping err:", err)

	}
    //塞值,第四個參數是ttl的值,0時就永遠不會失效
	err = rdb.Set(ctx, "GG", "ininder", 0).Err()
	if err != nil {
		panic(err)
	}
    //取值
	val, err := rdb.Get(ctx, "GG").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("GG", val)

	val2, err := rdb.Get(ctx, "key2").Result()
	if err == redis.Nil {
		fmt.Println("key2 does not exist")
	} else if err != nil {
		panic(err)
	} else {
		fmt.Println("key2", val2)
	}
}

來寫個http api使用redis當cache的例子

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
)

func main() {
	var ctx = context.Background()
	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	_, err := rdb.Ping(ctx).Result()
	if err != nil {
		fmt.Println("redis ping err:", err)

	}

	r := gin.Default()
	r.GET("/imslow", func(c *gin.Context) {
		result := ""
		v, err := rdb.Get(ctx, "cache").Result()
		if v != "" {
			result = "i'm cache"
		} else {
			time.Sleep(5 * time.Second)

			result = "i'm sleep 5 second"
			err = rdb.Set(ctx, "cache", "ininder", 0).Err()
			if err != nil {
				panic(err)
			}

		}

		c.JSON(200, gin.H{
			"message": result,
		})
	})
	//defaut 8080 port
	r.Run()
}

執行結果

curl --location --request GET '127.0.0.1:8080/imslow'
//{"message":"i'm sleep 5 second"}%       
curl --location --request GET '127.0.0.1:8080/imslow'
//{"message":"i'm cache"}%               

執行速度比較

[GIN] 2020/10/01 - 23:01:52 | 200 |  5.004710825s |       127.0.0.1 | GET      "/imslow"
[GIN] 2020/10/01 - 23:01:55 | 200 |     1.74188ms |       127.0.0.1 | GET      "/imslow"

從上面的比較就可以明顯看出有無redis當cache的差距,如果真的要去擠出效能又不要讓db被打爆的話,加台redis是個不錯的解決方案


上一篇
[DAY23]Golang也是有ORM-GORM
下一篇
[DAY25]Golang的實時分佈式消息傳遞平台-NSQ
系列文
欸你這週GO了嘛30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言