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:

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/garyburd/redigo/redis"
  5. "os"
  6. "os/signal"
  7. "syscall"
  8. "time"
  9. )
  10. var (
  11. Pool *redis.Pool
  12. )
  13. func init() {
  14. redisHost := ":6379"
  15. Pool = newPool(redisHost)
  16. close()
  17. }
  18. func newPool(server string) *redis.Pool {
  19. return &redis.Pool{
  20. MaxIdle: 3,
  21. IdleTimeout: 240 * time.Second,
  22. Dial: func() (redis.Conn, error) {
  23. c, err := redis.Dial("tcp", server)
  24. if err != nil {
  25. return nil, err
  26. }
  27. return c, err
  28. },
  29. TestOnBorrow: func(c redis.Conn, t time.Time) error {
  30. _, err := c.Do("PING")
  31. return err
  32. },
  33. }
  34. }
  35. func close() {
  36. c := make(chan os.Signal, 1)
  37. signal.Notify(c, os.Interrupt)
  38. signal.Notify(c, syscall.SIGTERM)
  39. signal.Notify(c, syscall.SIGKILL)
  40. go func() {
  41. <-c
  42. Pool.Close()
  43. os.Exit(0)
  44. }()
  45. }
  46. func Get(key string) ([]byte, error) {
  47. conn := Pool.Get()
  48. defer conn.Close()
  49. var data []byte
  50. data, err := redis.Bytes(conn.Do("GET", key))
  51. if err != nil {
  52. return data, fmt.Errorf("error get key %s: %v", key, err)
  53. }
  54. return data, err
  55. }
  56. func main() {
  57. test, err := Get("test")
  58. fmt.Println(test, err)
  59. }

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:

  1. package main
  2. import (
  3. "github.com/astaxie/goredis"
  4. "fmt"
  5. )
  6. func main() {
  7. var client goredis.Client
  8. // Set the default port in Redis
  9. client.Addr = "127.0.0.1:6379"
  10. // string manipulation
  11. client.Set("a", []byte("hello"))
  12. val, _ := client.Get("a")
  13. fmt.Println(string(val))
  14. client.Del("a")
  15. // list operation
  16. vals := []string{"a", "b", "c", "d", "e"}
  17. for _, v := range vals {
  18. client.Rpush("l", []byte(v))
  19. }
  20. dbvals,_ := client.Lrange("l", 0, 4)
  21. for i, v := range dbvals {
  22. println(i,":",string(v))
  23. }
  24. client.Del("l")
  25. }

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.

5.6. NoSQL database - 图1

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:

  1. go get gopkg.in/mgo.v2

Here is the example:

  1. package main
  2. import (
  3. "fmt"
  4. "gopkg.in/mgo.v2"
  5. "gopkg.in/mgo.v2/bson"
  6. "log"
  7. )
  8. type Person struct {
  9. Name string
  10. Phone string
  11. }
  12. func main() {
  13. session, err := mgo.Dial("server1.example.com,server2.example.com")
  14. if err != nil {
  15. panic(err)
  16. }
  17. defer session.Close()
  18. // Optional. Switch the session to a monotonic behavior.
  19. session.SetMode(mgo.Monotonic, true)
  20. c := session.DB("test").C("people")
  21. err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
  22. &Person{"Cla", "+55 53 8402 8510"})
  23. if err != nil {
  24. log.Fatal(err)
  25. }
  26. result := Person{}
  27. err = c.Find(bson.M{"name": "Ale"}).One(&result)
  28. if err != nil {
  29. log.Fatal(err)
  30. }
  31. fmt.Println("Phone:", result.Phone)
  32. }

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.