Skip to content

Commit

Permalink
上线
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuCheer committed Feb 1, 2019
0 parents commit b0ca22e
Show file tree
Hide file tree
Showing 10 changed files with 1,017 additions and 0 deletions.
36 changes: 36 additions & 0 deletions README.md
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
40 changes: 40 additions & 0 deletions conf/config.go
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)
}
12 changes: 12 additions & 0 deletions conf/config.toml
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"
159 changes: 159 additions & 0 deletions connect/redis.go
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
}
Loading

0 comments on commit b0ca22e

Please sign in to comment.