项目需求
1. 数据库 - mysql mongodb tidb 时序性数据库
2. 缓存 - redis memcache
3. 消息处理 - mq kafka
4. 传输相关 - json protobuf grpc thrift
5. 认证相关 - cookie session token jwt
6. 日志 - elk
项目创建
1. 生成mod文件 - go mod init 包名 (注: 包名在 import 引入自定义包时替代GOPATH)
2. 安装GIN框架 - go get github.com/gin-gonic/gin
3. 安装yaml扩展 - go get gopkg.in/yaml.v2
4. 安装GORM扩展 - go get github.com/jinzhu/gorm
5. 安装mysql扩展 - go get gorm.io/driver/mysql
6. 安装Redis扩展 - go get github.com/gomodule/redigo/redis
7. 安装endless扩展 - go get github.com/fvbock/endless (优雅启动)
GRPC
Go 安装协议编译器插件(默认安装目录为home/go/pkg/mod)
1. 安装protoc 下载地址:https://github.com/protocolbuffers/protobuf/releases
2. go install google.golang.org/protobuf/cmd/protoc-gen-go@latest || go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
3. go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest || go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
安装grpc_php_plugin
1. git clone --recurse-submodules -b v1.42.0 https://github.com/grpc/grpc
2. cd grpc
3. mkdir -p cmake/build
4. pushd cmake/build
5. cmake ../.. (注:make需要升级)
6. make protoc grpc_php_plugin
7. popd
protoc命令
1. GO语言
protoc --proto_path=./ --go_out=./ --go_opt=paths=source_relative --go-grpc_out=./ --go-grpc_opt=paths=source_relative ./config/rpc/rpc.proto ./config/rpc/rpc_message.proto
2. PHP语言
# protoc --proto_path=./ --php_out=./php ./config/rpc/rpc.proto ./config/rpc/rpc_message.proto
protoc --proto_path=./ --php_out=./php --grpc_out=./php --plugin=protoc-gen-grpc=/www/wwwroot/grpc/grpc/cmake/build/grpc_php_plugin ./config/rpc/rpc.proto ./config/rpc/rpc_message.proto
GRPC使用
GO语言
1. 运行
PHP语言
1. 注意事项
安装php-grpc扩展需要gcc 4.9
升级gcc:yum install -y centos-release-scl && yum install -y devtoolset-8-gcc* && scl enable devtoolset-8 bash
2. composer安装
php-fpm - composer require grpc/grpc
swoole - composer require swoole/grpc - https://github.com/swoole/grpc
composer require google/protobuf
GO proto文件注意事项
1. Import "file_name.proto" was not found or had errors.
文件找不到,需要指定--proto_path参数,指定命令行查找目录
2. file_name.proto:7:5: "int" is not defined.
proto3没有int类型,只有int32与int64类型
3. protoc-gen-go: unable to determine Go import path for "file_name.proto"
protoc-gen-go无法确定proto路径,需要指定option go_package = "包名/路径";
常用命令
go mod (注:比较常用的是 init,tidy, edit)
1. go mod download download modules to local cache(下载依赖包)
2. go mod edit edit go.mod from tools or scripts(编辑go.mod)
3. go mod graph print module requirement graph (打印模块依赖图)
4. go mod verify initialize new module in current directory(在当前目录初始化mod)
5. go mod tidy add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
6. go mod vendor make vendored copy of dependencies(将依赖复制到vendor下)
7. go mod verify verify dependencies have expected content (验证依赖是否正确)
运行启动
pm2
1. 运行服务
代码语言:javascript复制 ~~~
r := gin.Default()
r.GET("/",func(context *gin.Context){
c.JSON(200, gin.H{
"message": "index index",
})
})
r.Run("0.0.0.0:8080")
~~~
2. 启动
代码语言:javascript复制 ~~~
go build start.go
pm2 start ./start --name app_name 或 go start ./start --watch --name app_name
~~~
3. 停止
代码语言:javascript复制 ~~~
pm2 stop app_name
~~~
4. 重启
代码语言:javascript复制 ~~~
go build start.go
pm2 reload app_name 或 pm2 reload app_name --watch
~~~
5. 查看当前运行项目
代码语言:javascript复制 ~~~
pm2 list
~~~
6. 删除当前运行项目
代码语言:javascript复制 ~~~
pm2 delete app_name
~~~
7. 查看日志
代码语言:javascript复制 ~~~
pm2 --log app_name
~~~
gin
1. 运行服务
代码语言:javascript复制 ~~~
r := gin.Default()
r.Static("/static", "./static")
r.GET("/",func(context *gin.Context){
c.JSON(200, gin.H{
"message": "index index",
})
})
r.Run("0.0.0.0:8080")
~~~
2. 启动
代码语言:javascript复制 ~~~
go build start.go
./start
~~~
3. 停止
代码语言:javascript复制 ~~~
ctrl c
~~~
endless扩展(热重启)
1. 运行服务
代码语言:javascript复制 ~~~
r := gin.Default()
r.GET("/",func(context *gin.Context){
c.JSON(200, gin.H{
"message": "index index",
})
})
s := endless.NewServer(host, r)
s.BeforeBegin = func(add string) {
fmt.Printf("Actual pid is %d", syscall.Getpid())
}
err := s.ListenAndServe()
if err != nil{
fmt.Printf("Server err is %v", err)
}
~~~
2. 启动
代码语言:javascript复制 ~~~
go build start.go
./start
~~~
3. 停止
代码语言:javascript复制 ~~~
kill -2 pid
~~~
2. 重启
代码语言:javascript复制 ~~~
go build start.go
kill -1 pid
~~~
数据库连接
mysql
1. 普通使用
代码语言:javascript复制 ~~~
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
~~~
2. 连接池
代码语言:javascript复制 ~~~
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // data source name
DefaultStringSize: 256, // default size for string fields
DisableDatetimePrecision: true, // disable datetime precision, which not supported before MySQL 5.6
DontSupportRenameIndex: true, // drop & create when rename index, rename index not supported before MySQL 5.7, MariaDB
DontSupportRenameColumn: true, // `change` when rename column, rename column not supported before MySQL 8, MariaDB
SkipInitializeWithVersion: false, // auto configure based on currently MySQL version
}), &gorm.Config{})
//设置连接池配置
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(5) // SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxOpenConns(20) // SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetConnMaxLifetime(30 * time.Second) // SetConnMaxLifetime 设置了连接可复用的最大时间。
~~~
缓存
redis
1. 普通使用
代码语言:javascript复制 ~~~
redisHost := "127.0.0.1:6379";
pool := &redis.Pool{
MaxIdle: 5,
IdleTimeout: time.Duration(5) * time.Second, //将int转换成 time.Duration
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", redisHost)
if err != nil {
return nil, err
}
return c, err
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
conn := pool.get()
defer conn.Close()
str, err := redis.Bytes(conn.Do("GET",name))
~~~
go语言注意事项
map
1. Map,对于共享变量,资源,并发写会产生竞争,相应代码如下
代码语言:javascript复制 ~~~
var lock sync.Mutex;
{
defer WaitGroup.Done();
lock.Lock();
map1[key] = value;
lock.Unlock();
}
~~~