-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b0ca22e
Showing
10 changed files
with
1,017 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# neptune 一个 redis 连接池 GRPC 服务端 | ||
|
||
#### 介绍 | ||
不管项目是大是小,名字一定要响;对这个项目就是 “海王星”; | ||
本项目可以提供大家学习 GRPC 服务的编写与熟悉,了解连接池的实现; | ||
至于本项目能解决多少问题,其实并不能解决太多问题;如果大家对改项目感兴趣,欢迎大胆尝试; | ||
|
||
|
||
#### 客户端说明 | ||
这里有个 php-neptune客户端,可以在php下使用该连接池服务; | ||
大家都了解,在php下调用redis使用短连接会反复的创建连接/关闭连接,并发请求过大时会产生大量 TIME_WAIT 文件句柄数一旦达到上限,新的请求就无法被处理了; | ||
使用长连接时,redis 长连接托管给 php-fpm ;这里只要php-fpm不死,连接就不会消失,这里缺少了动态管理的支持; | ||
|
||
连接池则可以解决这个问题,但是,但是... GRPC也是TCP连接,悲伤了;所以该项目的存在似乎只能是学习了; | ||
如果想解决php短连接的问题,似乎有两种方案 1.换其他语言;2.利用 swoole 搭建http服务使php项目已一个常驻进程运行; | ||
|
||
|
||
#### 安装教程 | ||
依赖安装,项目中用到了一些包,直接安装即可; | ||
|
||
被墙了百度下好多方法安装; | ||
``` | ||
go get google.golang.org/grpc | ||
go get golang.org/x/net | ||
``` | ||
|
||
|
||
#### 使用说明 | ||
直接到项目目录下 | ||
``` | ||
go run main.go --host=127.0.0.1:50033 | ||
``` | ||
|
||
#### 说明 | ||
如果你不想过多了解源码细节,可以直接到 Release 中下载编译好的程序,windows/linux |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package conf | ||
|
||
import ( | ||
"fmt" | ||
"github.com/BurntSushi/toml" | ||
) | ||
|
||
type tomlConfig struct { | ||
Pool pool `toml:"pool"` | ||
RedisMaster masterLink `toml:"redis-master"` | ||
RedisSlave slaveLink `toml:"redisslave"` | ||
} | ||
|
||
type pool struct { | ||
InitCap int | ||
MaxCap int | ||
IdleTimeout int | ||
} | ||
type masterLink struct{ | ||
Server string `toml:"server"` | ||
Port int `toml:"port"` | ||
Auth string `toml:"auth"` | ||
} | ||
type slaveLink struct{ | ||
Server []string `toml:"server"` | ||
Port int `toml:"port"` | ||
Auth string `toml:"auth"` | ||
} | ||
|
||
|
||
var Config tomlConfig | ||
|
||
func init(){ | ||
fmt.Println("start conf") | ||
|
||
|
||
toml.DecodeFile("conf/config.toml", &Config) | ||
|
||
fmt.Println(Config) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[pool] | ||
InitCap = 5 | ||
MaxCap = 30 | ||
IdleTimeout = 30 | ||
[redis-master] | ||
server = "192.168.137.100" | ||
port = 6379 | ||
auth = "123456" | ||
[redisslave] | ||
server = ["192.168.137.100","192.168.137.101"] | ||
port = 6379 | ||
auth = "123456" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package connect | ||
|
||
import ( | ||
"github.com/gomodule/redigo/redis" | ||
"time" | ||
"fmt" | ||
"github.com/zhuCheer/pool" | ||
"github.com/zhuCheer/neptune/helper" | ||
"errors" | ||
"log" | ||
"sync" | ||
) | ||
|
||
|
||
var GlobalRedisHandler = &redisHandler{PoolMap:make(map[string]pool.Pool)} | ||
|
||
// 连接池全局存储变量 | ||
type redisHandler struct { | ||
mu sync.Mutex | ||
PoolMap map[string]pool.Pool | ||
} | ||
|
||
// 连接池注册节点 | ||
type RegistCnf struct { | ||
Address string | ||
Auth string | ||
InitialCap int | ||
MaxCap int | ||
IdleTimeout time.Duration | ||
DBNum int | ||
} | ||
|
||
// 连接信息节点 | ||
type ConnItem struct{ | ||
PoolHashId string | ||
Conn redis.Conn | ||
} | ||
|
||
// 获取一个连接对象 | ||
func (rs *redisHandler) GetConn(poolHashId string) (item ConnItem, err error){ | ||
poolItem, ok := rs.PoolMap[poolHashId] | ||
if ok == false{ | ||
log.Println("[error] redis pool is not found") | ||
return item, errors.New("redis pool is not found") | ||
} | ||
poolConn, err := poolItem.Get() | ||
if err != nil{ | ||
log.Println("[error] get conn have an error in redis pool") | ||
return item, errors.New("get conn have an error in redis pool") | ||
} | ||
conn := poolConn.(redis.Conn) | ||
item = ConnItem{ | ||
poolHashId, | ||
conn, | ||
} | ||
|
||
return item,nil | ||
} | ||
|
||
// 将一个连接放回连接池 | ||
func (rs *redisHandler) PutConn(item ConnItem) (err error){ | ||
poolHashId := item.PoolHashId | ||
poolItem, ok := rs.PoolMap[poolHashId] | ||
if ok == false{ | ||
log.Println("[error] redis pool is not found") | ||
return errors.New("redis pool is not found") | ||
} | ||
err = poolItem.Put(item.Conn) | ||
if err != nil{ | ||
log.Println("[error] put conn have an error in redis pool") | ||
return errors.New("put conn have an error in redis pool") | ||
} | ||
return nil | ||
} | ||
|
||
// 释放一个连接池 | ||
func (rs *redisHandler) ReleasePool(poolHashId string) (err error){ | ||
poolItem, ok := rs.PoolMap[poolHashId] | ||
|
||
if ok == false{ | ||
log.Println("[warning] redis pool is not found, do not anything") | ||
return | ||
} | ||
poolItem.Release() | ||
delete(rs.PoolMap, poolHashId) | ||
|
||
return | ||
} | ||
|
||
|
||
// 注册一个池 | ||
func Regist(cnf *RegistCnf) (poolHashId string, err error){ | ||
poolHashId = "QI:"+helper.String2md5(cnf.Address) | ||
GlobalRedisHandler.mu.Lock() | ||
defer GlobalRedisHandler.mu.Unlock() | ||
|
||
if _, ok := GlobalRedisHandler.PoolMap[poolHashId]; ok { | ||
log.Println("pool has exists:"+poolHashId) | ||
return poolHashId, nil | ||
} | ||
fmt.Println(cnf) | ||
|
||
//factory 创建连接的方法 | ||
factory := func() (interface{}, error) { | ||
fmt.Println("open link" + poolHashId) | ||
c, err := redis.Dial("tcp", cnf.Address) | ||
if cnf.Auth != ""{ | ||
if _, err := c.Do("AUTH", cnf.Auth); err != nil { | ||
c.Close() | ||
return nil, fmt.Errorf("[factory]redis auth error: %s", err) | ||
} | ||
} | ||
if cnf.DBNum > 0 { | ||
if _, err := c.Do("SELECT", cnf.DBNum); err != nil { | ||
c.Close() | ||
return nil, fmt.Errorf("[factory]redis select db num error: %s", err) | ||
} | ||
fmt.Println("select db num:",cnf.DBNum) | ||
} | ||
|
||
return c, err | ||
} | ||
|
||
//close 关闭连接的方法 | ||
close := func(v interface{}) error { | ||
fmt.Println("close link " + poolHashId) | ||
return v.(redis.Conn).Close() | ||
} | ||
|
||
poolCnf := &pool.Config{ | ||
InitialCap: cnf.InitialCap, | ||
MaxCap: cnf.MaxCap, | ||
Factory: factory, | ||
Close: close, | ||
//Ping: ping, | ||
IdleTimeout: cnf.IdleTimeout * time.Second, | ||
} | ||
pool, err := getPool(poolCnf) | ||
if err !=nil { | ||
log.Println("[error]regist pool error: ", err) | ||
return poolHashId, fmt.Errorf("regist pool error: %s", err) | ||
} | ||
|
||
GlobalRedisHandler.PoolMap[poolHashId] = pool | ||
return poolHashId,nil | ||
} | ||
|
||
|
||
func getPool(poolConfig *pool.Config)(pool.Pool, error){ | ||
fmt.Println("create a new pool") | ||
|
||
//factory 创建连接的方法 | ||
p, err := pool.NewChannelPool(poolConfig) | ||
if err != nil { | ||
log.Println("[error]create pool have an error", err) | ||
return nil, fmt.Errorf("create pool have an error: %s", err) | ||
} | ||
return p, nil | ||
} |
Oops, something went wrong.