1、Go  连接redis的方法:

package que

import (
	"fmt"
	"time"

	"github.com/gomodule/redigo/redis"
)

var (
	pool      *redis.Pool
	localhost = "" // 127.0.0.1
	port      = "6379"
	addr      = localhost + ":" + port
	Password  = ""
)

func init() {
	initRides()
	// InitReceiver()
}

func initRides() {
	pool = &redis.Pool{
		IdleTimeout: 180 * time.Second,
		Dial: func() (redis.Conn, error) {
			conn, err := redis.Dial("tcp", addr, redis.DialPassword(Password))
			if err != nil {
				return nil, err
			}
			return conn, nil
		},
	}
}

其中如果没有 redis.DialPassword(Password),则连接redis时可能会报错:NOAUTH Authentication required.

或者可以使用下面这种设置方式解决认证问题:

func initRides() {
	pool = &redis.Pool{
		IdleTimeout: 180 * time.Second,
		Dial: func() (redis.Conn, error) {
			conn, err := redis.Dial("tcp", addr)
			if err != nil {
				return nil, err
			}
			if _, err := conn.Do("AUTH", Password); err != nil {
				conn.Close()
				return nil, err
			}
			return conn, nil
		},
	}
}

2、根据业务需求,在main的init里面调用InitReceiver方法,当需要处理大量数据的时候,接口不能做出及时反馈,这时就需要类似的模型来解决该问题了:

func init() {
	initRides()
	InitReceiver()
}

func InitReceiver() {
	go func() {
		for {
			var conn = pool.Get()
			defer conn.Close()

			// Do some thing
			conn.Do("set", "test", "test1111")
			line, _ := redis.String(conn.Do("get", "test"))

			fmt.Println(line)
		}
	}()
}

3、代码跑起来之后,使用命令:

netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

查看TCP的状态信息,其中ESTABLISHED状态的存在1万多个:

CLOSE_WAIT       1
ESTABLISHED      10015
SYN_SENT         1
TIME_WAIT        15

下面是 TCP正常连接建立和终止所对应的状态图:

redis establish redis established_go语言

相关TCP状态解释:

LISTEN:       侦听来自远方的TCP端口的连接请求;

SYN_SENT:     在发送连接请求后等待匹配的连接请求;

SYN_RECV: 在收到和发送一个连接请求后等待对方对连接请求的确认;

ESTABLISHED:  代表一个打开的连接;

FIN_WAIT1:   等待远程TCP连接中断请求, 或先前的连接中断请求的确认;

FIN_WAIT2:   从远程TCP等待连接中断请求;

CLOSE_WAIT:   等待从本地用户发来的连接中断请求;

CLOSING:      等待远程TCP对连接中断的确认;

LAST_ACK:     等待原来的发向远程TCP的连接中断请求的确认;

TIME_WAIT:    等待足够的时间以确保远程TCP接收到连接中断请求的确认;

CLOSE:        没有任何连接状态;

注(参考出处:)

4、当我们推出程序之后:

[root ~]# netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
CLOSE_WAIT       1
ESTABLISHED      15
SYN_SENT         1
TIME_WAIT        10013

ESTABLISHED状态的连接被中断了,会通过TIME_WAIT的状态保留一段时间,这段时间过了才会释放这个端口,但是如果再这段时间内还有大量的请求的时候,就会产生大量的TIME_WAIT状态的连接,这些连接占着端口,也会占用大量的资源。

5、解决方法,增加 MaxIdle 和 MaxActive :

func initRides() {
	pool = &redis.Pool{
        MaxIdle:     30,
		MaxActive:   30,
		IdleTimeout: 180 * time.Second,
		Dial: func() (redis.Conn, error) {
			conn, err := redis.Dial("tcp", addr, redis.DialPassword(Password))
			if err != nil {
				return nil, err
			}
			return conn, nil
		},
	}
}

maxIdle,最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连
接将被标记为不可用,然后被释放。设为0表示无限制。
MaxActive,连接池的最大数据库连接数。设为0表示无限制。

maxActive是最大激活连接数,这里取值为30,表示同时最多有30个数据库连接。

maxIdle是最大的空闲连接数,这里取值为30,表示即使没有数据库连接时依然可以保持30空闲的

连接,而不被清除,随时处于待命状态。

 

设置了之后效果显著:

[root ~]# netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
CLOSE_WAIT       2
ESTABLISHED      25
TIME_WAIT        67