Skip to content

Latest commit

 

History

History
202 lines (153 loc) · 4.95 KB

File metadata and controls

202 lines (153 loc) · 4.95 KB

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, zset(ordered set) and hash 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.

Links