5.6 NoSQL database

A NoSQL database provides a mechanism for the storage and retrieval of data that uses looser consistency models than typical relational databases in order to achieve horizontal scaling and higher availability. Some authors refer to them as "Not only SQL" to emphasize that some NoSQL systems do allow SQL-like query languages to be used.

As the C language of the 21st century, Go has good support for NoSQL databases, including the popular redis, mongoDB, Cassandra and Membase NoSQL databases.

redis

redis is a key-value storage system like Memcached, that supports the string, list, set and zset(ordered set) value types.

There are some Go database drivers for redis:

Let's see how to use the driver that redigo to operate on a database:


    package main

    import (
        "fmt"
        "github.com/garyburd/redigo/redis"
        "os"
        "os/signal"
        "syscall"
        "time"
    )

    var (
        Pool *redis.Pool
    )

    func init() {
        redisHost := ":6379"
        Pool = newPool(redisHost)
        close()
    }

    func newPool(server string) *redis.Pool {

        return &redis.Pool{

            MaxIdle:     3,
            IdleTimeout: 240 * time.Second,

            Dial: func() (redis.Conn, error) {
                c, err := redis.Dial("tcp", server)
                if err != nil {
                    return nil, err
                }
                return c, err
            },

            TestOnBorrow: func(c redis.Conn, t time.Time) error {
                _, err := c.Do("PING")
                return err
            },
        }
    }

    func close() {
        c := make(chan os.Signal, 1)
        signal.Notify(c, os.Interrupt)
        signal.Notify(c, syscall.SIGTERM)
        signal.Notify(c, syscall.SIGKILL)
        go func() {
            <-c
            Pool.Close()
            os.Exit(0)
        }()
    }

    func Get(key string) ([]byte, error) {

        conn := Pool.Get()
        defer conn.Close()

        var data []byte
        data, err := redis.Bytes(conn.Do("GET", key))
        if err != nil {
            return data, fmt.Errorf("error get key %s: %v", key, err)
        }
        return data, err
    }

    func main() {
        test, err := Get("test")
        fmt.Println(test, err)
    }

I forked the last of these packages, fixed some bugs, and used it in my short URL service (2 million PV every day).

Let's see how to use the driver that I forked to operate on a database:

    package main

    import (
        "github.com/astaxie/goredis"
        "fmt"
    )

    func main() {
        var client goredis.Client

        // Set the default port in Redis
        client.Addr = "127.0.0.1:6379"

        // string manipulation
        client.Set("a", []byte("hello"))
        val, _ := client.Get("a")
        fmt.Println(string(val))
        client.Del("a")

        // list operation
        vals := []string{"a", "b", "c", "d", "e"}
        for _, v := range vals {
            client.Rpush("l", []byte(v))
        }
        dbvals,_ := client.Lrange("l", 0, 4)
        for i, v := range dbvals {
            println(i,":",string(v))
        }
        client.Del("l")
    }

We can see that it is quite easy to operate redis in Go, and it has high performance. It's client commands are almost the same as redis' built-in commands.

mongoDB

mongoDB (from "humongous") is an open source document-oriented database system developed and supported by 10gen. It is part of the NoSQL family of database systems. Instead of storing data in tables as is done in a "classical" relational database, MongoDB stores structured data as JSON-like documents with dynamic schemas (MongoDB calls the format BSON), making the integration of data in certain types of applications easier and faster.

Figure 5.1 MongoDB compared to Mysql

The best driver for mongoDB is called mgo, and it is possible that it will be included in the standard library in the future.

Install mgo:

    go get gopkg.in/mgo.v2

Here is the example:


    package main

    import (
        "fmt"
        "gopkg.in/mgo.v2"
        "gopkg.in/mgo.v2/bson"
        "log"
    )

    type Person struct {
        Name  string
        Phone string
    }

    func main() {
        session, err := mgo.Dial("server1.example.com,server2.example.com")
        if err != nil {
            panic(err)
        }
        defer session.Close()

        // Optional. Switch the session to a monotonic behavior.
        session.SetMode(mgo.Monotonic, true)

        c := session.DB("test").C("people")
        err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
            &Person{"Cla", "+55 53 8402 8510"})
        if err != nil {
            log.Fatal(err)
        }

        result := Person{}
        err = c.Find(bson.M{"name": "Ale"}).One(&result)
        if err != nil {
            log.Fatal(err)
        }

        fmt.Println("Phone:", result.Phone)
    }

We can see that there are no big differences when it comes to operating on mgo or beedb databases; they are both based on structs. This is the Go way of doing things.

results matching ""

    No results matching ""