All Projects → 8treenet → Gotree

8treenet / Gotree

Licence: apache-2.0
Gotree is a vertically distributed framework. Gotree's goal is to easily develop distributed services and liberate the mental burden of developers.

Programming Languages

go
31211 projects - #10 most used programming language
golang
3204 projects

Projects that are alternatives of or similar to Gotree

Jupiter
Jupiter是一款性能非常不错的, 轻量级的分布式服务框架
Stars: ✭ 1,372 (+1407.69%)
Mutual labels:  rpc, rpc-framework, distributed-systems
Rpc Websockets
JSON-RPC 2.0 implementation over WebSockets for Node.js and JavaScript/TypeScript
Stars: ✭ 344 (+278.02%)
Mutual labels:  rpc, rpc-framework, distributed-systems
Rsf
已作为 Hasor 的子项目,迁移到:http://git.oschina.net/zycgit/hasor
Stars: ✭ 77 (-15.38%)
Mutual labels:  rpc, rpc-framework, distributed-systems
Micromono
Write microservices in monolithic style
Stars: ✭ 644 (+607.69%)
Mutual labels:  rpc, framework
Hprose Java
Hprose is a cross-language RPC. This project is Hprose 2.0 for Java
Stars: ✭ 542 (+495.6%)
Mutual labels:  rpc, rpc-framework
Grain
grain是一个极简的、组件式的RPC框架,灵活且适合渐进学习,可与任何框架整合。同时包含(系统通用多线程模型与消息通讯 || 多对多关系的分布式锁 || 基于Servlet的HTTP框架 || 基于系统通用多线程模型的Websocket框架 || 支持行级锁的多线程锁 )等组件,按需选择组件,不绑架开发者。
Stars: ✭ 577 (+534.07%)
Mutual labels:  rpc, rpc-framework
Izumi
Productivity-oriented collection of lightweight fancy stuff for Scala toolchain
Stars: ✭ 423 (+364.84%)
Mutual labels:  rpc, framework
Go Zero
go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.
Stars: ✭ 13,156 (+14357.14%)
Mutual labels:  rpc, rpc-framework
Servicetalk
A networking framework that evolves with your application
Stars: ✭ 656 (+620.88%)
Mutual labels:  rpc, framework
Spyne
A transport agnostic sync/async RPC library that focuses on exposing services with a well-defined API using popular protocols.
Stars: ✭ 992 (+990.11%)
Mutual labels:  rpc, rpc-framework
Swoft Framework
[READ ONLY] Swoft Framework, base of Swoft
Stars: ✭ 70 (-23.08%)
Mutual labels:  rpc, framework
Getty
a netty like asynchronous network I/O library based on tcp/udp/websocket; a bidirectional RPC framework based on JSON/Protobuf; a microservice framework based on zookeeper/etcd
Stars: ✭ 532 (+484.62%)
Mutual labels:  rpc, rpc-framework
Sofa Rpc Node
SOFARPC Node is a high-performance, high-extensibility, production-level Nodejs RPC framework.
Stars: ✭ 520 (+471.43%)
Mutual labels:  rpc, rpc-framework
Phpboot
☕️ 🚀 tiny & fast PHP framework for building Microservices/RESTful APIs, with useful features: IOC, Hook, ORM, RPC, Swagger, Annotation, Parameters binding, Validation, etc.
Stars: ✭ 638 (+601.1%)
Mutual labels:  rpc, framework
Simple Go Rpc
RPC explained by writing simple RPC framework in 300 lines of pure Golang.
Stars: ✭ 510 (+460.44%)
Mutual labels:  rpc, rpc-framework
Hemera
🔬 Writing reliable & fault-tolerant microservices in Node.js https://hemerajs.github.io/hemera/
Stars: ✭ 773 (+749.45%)
Mutual labels:  rpc, distributed-systems
Hprose Golang
Hprose is a cross-language RPC. This project is Hprose for Golang.
Stars: ✭ 1,143 (+1156.04%)
Mutual labels:  rpc, rpc-framework
Rpcx Java
rpcx implementation in Java for server side and client side
Stars: ✭ 71 (-21.98%)
Mutual labels:  rpc, rpc-framework
Ergo
a Framework for creating mesh networks using technologies and design patterns of Erlang/OTP in Golang
Stars: ✭ 376 (+313.19%)
Mutual labels:  framework, distributed-systems
Finagle
A fault tolerant, protocol-agnostic RPC system
Stars: ✭ 8,126 (+8829.67%)
Mutual labels:  rpc, distributed-systems

gotree

License Go Report Card Build Status GoDoc QQ群

gotree 是一个垂直分布式框架。 gotree 的目标是轻松开发分布式服务,解放开发者心智负担。

特性

  • 熔断
  • fork 热更新
  • rpc 通信(c50k)
  • 定时器
  • SQL 慢查询监控
  • SQL 冗余监控
  • 分层
  • 强制垂直分库
  • 基于 gseq 串行的全网日志
  • 单元测试
  • 督程
  • 一致性哈希、主从、随机、均衡等负载方式
  • oop
  • ioc 服务定位器和依赖注入

介绍

快速使用

  1. 获取安装 gotree。
# windows 用户请使用 cygwin
$ go get -u github.com/8treenet/gotree/gotree
  1. 创建 learning 项目。
$ gotree new learning
  1. learning 项目数据库安装、数据库用户密码配置。使用 source 或工具安装 learning.sql。
$ mysql > source $GOPATH/src/learning/learning.sql
# 编辑 db 连接信息,Com = Order、用户名 = root、密码 = 123123、地址 = 127.0.0.1、端口 = 3306、数据库 = learning_order
# Order = "root:[email protected](127.0.0.1:3306)/learning_order?charset=utf8"
$ vi $GOPATH/src/learning/dao/conf/dev/db.conf
  1. 启动 dao服务、 app 服务。
$ cd $GOPATH/src/learning/dao
$ go run main.go
$ command + t #开启新窗口
$ cd $GOPATH/src/learning/app
$ go run main.go
  1. 模拟网关执行调用,请查看代码。 代码位于 $GOPATH/src/learning/app/unit/gateway_test.go
$ go test -v -count=1 -run TestUserRegister $GOPATH/src/learning/app/unit/gateway_test.go
$ go test -v -count=1 -run TestStore $GOPATH/src/learning/app/unit/gateway_test.go
$ go test -v -count=1 -run TestShopping $GOPATH/src/learning/app/unit/gateway_test.go
$ go test -v -count=1 -run TestUserOrder $GOPATH/src/learning/app/unit/gateway_test.go
  1. qps 压测
# 每秒 1w 请求
$ go run $GOPATH/src/learning/app/unit/qps_press/main.go 10000

快速入门

描述

  • App 主要用于逻辑功能处理等。均衡负载部署多台,为网关提供服务。 目录结构在 learning/app。
  • Dao 主要用于数据功能处理,组织低级数据提供给上游 App。Dao 基于容器设计,开发 Com 挂载不同的 Dao 容器上。负载均衡方式较多,可根据数据分布来设计。可通过配置来开启 Com(Component Object Model)。目录结构在 learning/dao。
  • Protocol 通信协议 app_cmd/value 作用于 Api网关和 App 通信。 dao_cmd/value 作用于 App 和 Dao 通信。 目录结构在 learning/protocol。

3台网关、2台app、3台dao 组成的集群

服务器 服务器 服务器
APIGateway-1 APIGateway-2 TcpGateway-1
App-1 App-2
Dao-1 Dao-2 Dao-3

分层

架构主要分为4层。第一层基类 AppController,作为 App 的入口控制器, 主要职责有组织和协调Service、逻辑处理。 第二层基类 AppService, 作为 AppController 的下沉层, 主要下沉的职责有拆分、治理、解耦、复用服务,使用Dao。 第三层基类 ComController ,作为 Dao 的入口控制器,主要职责有组织数据、解耦数据和逻辑、抽象数据源、使用数据源。 第四层多种基类 ComModel 数据库表模型基类、 ComMemory 内存基类、 ComCache redis基类、 ComApi Http数据基类。

gateway

/*  
    1. 模拟api网关调用,等同 beego、gin 等api gateway, 以及 tcp 网关项目.
    2. 实际应用中 app 分布在多个物理机器. AppendApp 因填写多机器的内网ip.
*/
    func main() {
        gate := gateway.Sington()
        gate.AppendApp("192.168.1.1:3000")
        gate.AppendApp("192.168.1.2:3001")
        gate.AppendApp("192.168.1.3:3002")
        gate.Run()
        
        //创建 app 调用命令
        cmd := new(app_cmd.Store).Gotree([]int64{1, 2})
        //创建 app 返回数据
        value := app_value.Store{}
        
        //设置自定义头,透传数据
        cmd.SetHeader("", "")
        //可直接设置http头
        cmd.SetHttpHeader(head) 
        gate.CallApp(cmd, &value)
        //response value ....
    }

app_controller

    /* 
         learning/app/controllers/product_controller.go
    */
    func init() {
        //注册 ProductController 控制器
        gotree.App().RegController(new(ProductController).Gotree())
    }

    //定义一个电商的商品控制器。控制器命名 `Name`Controller
    type ProductController struct {
        //继承 app 控制器的基类
        gotree.AppController

        ProductSer *service.Product //依赖注入
        UserSer    *service.User    //依赖注入
    }

    //这个是 gotree 风格的构造函数,底层通过指针原型链,可以实现多态,和基础类的支持。
    func (this *ProductController) Gotree() *ProductController {
        this.AppController.Gotree(this)
        return this
    }

    //每一个 APIGateway 触发的 rpc 动作调用,都会创造一个 ProductController 对象,并且调用 OnCreate。
    func (this *ProductController) OnCreate(method string, argv interface{}) {
        //调用父类 OnCreate
        this.AppController.OnCreate(method, argv)
        helper.Log().Notice("OnCreate:", method, argv)
    }

    //每一个 APIGateway 触发的 rpc 动作调用结束 都会触发 OnDestory。
    func (this *ProductController) OnDestory(method string, reply interface{}, e error) {
        this.AppController.OnDestory(method, reply, e)
        //打印日志
        helper.Log().Notice("OnDestory:", method, fmt.Sprint(reply), e)
    }

    /*
        这是一个查看商品列表的 Action,cmd 是入参,result 是出参,在 protocol中定义,下文详细介绍。
    */
    func (this *ProductController) Store(cmd app_cmd.Store, result *app_value.Store) (e error) {
        *result = app_value.Store{}
        productSer = new(service.Product).Gotree()

        //使用 service 的 Store 方法 读取出商品数据, 并且赋值给出参 result 
        result.List, e = this.ProductSer.Store()
        return
    }

app_service

    /* 
         learning/app/service/product.go
    */

    func init() {
        // 注册 Product 对象
        // 如果 Controller 有成员变量的类型是*Product,会做依赖注入。
        gotree.App().RegisterService(new(Product).Gotree())
    }

    type Product struct {
        //继承 AppService 基类
        app.AppService
    }

    // gotree 风格构造
    func (this *Product) Gotree() *Product {
        this.AppService.Gotree(this)
        return this
    }

    // 读取商品服务 返回一个商品信息匿名结构体数组。
    func (this *Product) Store() (result []struct {
        Id    int64 //商品 id
        Price int64 //商品价格
        Desc  string //商品描述
    }, e error) {

        //创建 dao调用命令
        cmdPt := new(dao_cmd.ProductGetList).Gotree([]int64{1, 2})
        //创建 dao返回数据
        store := dao_value.ProductGetList{}

        //CallDao 调用 Dao 服务器的 Com 入参cmdPt 出参store
        e = this.CallDao(cmdPt, &store)
        if e == helper.ErrBreaker {
            //熔断处理
            helper.Log().Notice("Store ErrBreaker")
            return
        }
        result = store.List
        return
    }

app_cmd

    /* 
        learning/protocol/app_cmd/product.go
    */
    func init() {
        //Store 加入熔断 条件:15秒内 %50超时, 60秒后恢复
        rc.RegisterBreaker(new(Store), 15, 0.5, 60)
    }

    // 定义访问 app product 控制器的命令基类, 所有的 app.product 动作调用,继承于这个基类
    type productCmdBase struct {
        rc.CallCmd //所有远程调用的基类
    }

    // Gotree 风格构造,因为是基类,参数需要暴露 child
    func (this *productCmdBase) Gotree(child ...interface{}) *productCmdBase {
        this.CallCmd.Gotree(this)
        this.AddChild(this, child...)
        // this.AddChild 继承原型链, 用于以后实现多态。
        return this
    }

    // 多态方法重写 Control。用于定位该命令,要访问的控制器。 这里填写 "Product" 控制器
    func (this *productCmdBase) Control() string {
        return "Product"
    }


    // 定义一个 product 的动作调用
    type Store struct {
        productCmdBase  //继承productCmdBase
        Ids            []int64
        TestEmpty     int `opt:"null"` //如果值为 []、""、0,加入此 tag ,否则会报错!
    }

    func (this *Store) Gotree(ids []int64) *Store {
        //调用父类 productCmdBase.Gotree 传入自己的对象指针
        this.productCmdBase.Gotree(this)
        this.Ids = ids
        return this
    }

    // 多态方法 重写 Action。用于定位该命令,要访问控制器里的 Action。 这里填写 "Store" 动作
    func (this *Store) Action() string {
        return "Store"
    }

dao_cmd

    /* 
        learning/protocol/dao_cmd/product.go
    */

    // 定义访问 dao product 控制器的命令基类, 所有的 dao.product 动作调用,继承于这个基类
    type productCmdBase struct {
        rc.CallCmd
    }

    func (this *productCmdBase) Gotree(child ...interface{}) *productCmdBase {
        this.CallCmd.Gotree(this)
        this.AddChild(this, child...)
        return this
    }

    // 上文已介绍
    func (this *productCmdBase) Control() string {
        return "Product"
    }

    // 多态方法重写 ComAddr 用于多 Dao节点 时的分布规则,当前返回随机节点
    func (this *productCmdBase) ComAddr(rn rc.ComNode) string {
        //分布于com.conf配置相关
        //rn.RandomAddr() 随机节点访问
        //rn.BalanceAddr() 负载均衡节点访问
        //rn.DummyHashAddr(this.productId) 一致性哈希节点访问
        //rn.AllCom() 获取全部节点,自定义方式访问
        //rn.SlaveAddr()  //返回随机从节点  主节点:节点id=1,当只有主节点返回主节点
        //rn.MasterAddr() //返回主节点 主节点:节点id=1
        return rn.RandomAddr()
    }

    // 定义一个 ProductGetList 的动作调用
    type ProductGetList struct {
        productCmdBase //继承productCmdBase
        Ids            []int64
    }

    func (this *ProductGetList) Gotree(ids []int64) *ProductGetList {
        this.productCmdBase.Gotree(this)
        this.Ids = ids
        return this
    }

    // 多态方法 重写 Action。
    func (this *ProductGetList) Action() string {
        return "GetList"
    }

com_controller

    /* 
         learning/dao/controllers/product_controller.go
         1. 定义Com控制器,控制器对象命名 `Com`Controller
         2. 必须使用同 Com 下的数据源
         3. Dao 进程分布在多机器下,挂载不同的 Com
         4. Com 控制开启和关闭  conf/com.conf
         5. 控制器 cmd 参数 关联 dao_cmd, protocol/dao_cmd
    */
    func init() {
        // 注册 Product 数据控制器入口
        gotree.Dao().RegController(new(ProductController).Gotree())
    }

    type ProductController struct {
        //继承控制器基类 gotree.ComController
        gotree.ComController
    }

    func (this *ProductController) Gotree() *ProductController {
        this.ComController.Gotree(this)
        return this
    }

    // 实现动作 GetList
    func (this *ProductController) GetList(cmd dao_cmd.ProductGetList, result *dao_value.ProductGetList) (e error) {
        var (
            //创建一个 sources.models 包里的 Product 对象指针, sources.models : 数据库表模型
            mProduct *product.Product
        )
        *result = dao_value.ProductGetList{}
        // 服务定位器获取 product.Product 实例
        this.Model(&mProduct)
        // 取数据库数据赋值给出参 result.List
        result.List, e = mProduct.Gets(cmd.Ids)
        return
    }

    // 实现动作 Add, 事务示例
    func (this *ProductController) Add(cmd dao_cmd.ProductAdd, result *helper.VoidValue) (e error) {
        var (
            mProduct *product.Product
        )
        *result = helper.VoidValue{}
        this.Model(&mProduct)

        // Transaction 执行事务,如果返回 不为 nil,触发回滚。 
        this.Transaction(func() error {
           _, e := mProduct.Add(cmd.Desc, cmd.Price)
           if e != nil {
               return
           }
           _, e = mProduct.Add(cmd.Desc, cmd.Price)
           return e
        })

        return
    }

com_model

    /* 
         learning/dao/sources/models/product/product.go
         数据库表模型示例,与 db 配置文件 Com 相关, learning/dao/conf/dev/db.conf   
    */
    func init() {
        //注册 Product 模型
        gotree.Dao().RegModel(new(Product).Gotree())
    }

    // 定义一个模型 Product 继承模型基类 ComModel
    type Product struct {
        gotree.ComModel
    }

    func (this *Product) Gotree() *Product {
        this.ComModel.ComModel(this)
        return this
    }

    // 1. 多态方法 重写 主要用于绑定 Com
    // 2. 只有 ProductController 可以使用
    func (this *Product) Com() string {
        return "Product"
    }

    func (this *Product) Gets(productId []int64) (list []struct {
        Id    int64
        Price int64
        Desc  string
    }, e error) {
        /*
            FormatPlaceholder()  :处理转数组为 ?,?,?
            FormatIn() : 处理数组为 value,value,value
            this.Conn().Raw : 获取连接执行sql语句
            QueryRows() : 获取多行数据
        */
        sql := fmt.Sprintf("SELECT id,price,`desc` FROM `product` where id in(%s)", this.FormatPlaceholder(productId))
        _, e = this.Conn().Raw(sql, this.FormatIn(productId)...).QueryRows(&list)
        return
    }

高级教程

进阶使用

$ vi $GOPATH/src/learning/dao/conf/dev/cache.conf
# 编辑 redis 配置,Com = Feature、 服务器地址 = 127.0.0.1、端口 = 6379 密码 = 、db = 0
# Feature = "server=127.0.0.1:6379;password=;database=0"

$ vi $GOPATH/src/learning/dao/conf/dev/com.conf
# 开启 Feature = 1,1代表组件ID, 如果要负载多台dao,在其他机器递增ID

$ vi $GOPATH/src/learning/app/conf/dev/timer.conf
# 开启 Open = "Feature"

$ cd $GOPATH/src/learning/dao
$ go run main.go
$ cd $GOPATH/src/learning/app
$ go run main.go

# 观察日志和查阅相关 Feature 代码

timer

    /* 
         learning/app/timer/feature.go
         定时器示例 learning/app/conf/dev/timer.conf -> Open,控制定期的开启和关闭
    */
    func init() {
        // RegTimer 注册定时器
        gotree.App().RegTimer(new(Feature).Gotree())
    }

    type Feature struct {
        gotree.AppTimer     //继承
        /*
            依赖注入
            注入的成员变量必须为大写开头
            FeatureSer: 注入实体对象
            Simple: 使用接口接收, 注意 `impl:"simple"` 在servic/feature.go 中注册
        */
        FeatureSer *service.Feature
        Simple     ExampleImpl `impl:"simple"`
    }

    func (this *Feature) Gotree() *Feature {
        this.AppTimer.Gotree(this)
        //注册触发定时器 5000毫秒
        this.RegTick(5000, this.CourseTick)

        //注册每日定时器 3点 1分
        this.RegDay(3, 1, this.CourseDay)
        return this
    }

    // 依赖注入接口示例, 由 service/feature.go 实现和注册
    type ExampleImpl interface {
        Simple() ([]struct {
            Id    int
            Value string
            Pos   float64
        }, error)
    }

    func (this *Feature) CourseDay() {
        simpleData, err := this.Simple.Simple()
    }

    func (this *Feature) CourseTick() {
        /*
            1. 全局禁止使用go func(), 请使用Async。
            2. 底层做了优雅关闭和热更新, hook了 async。 保证会话请求的闭环执行, 防止造成脏数据。
            3. async 做了 recover 和 栈传递,可以有效的使用同gseq
        */
        this.Async(func(ac gotree.AppAsync) {
            this.FeatureSer.Course()
        })
    }

helper

    /* 
         learning/app/service/feature.go
         展示 Helper 的使用, 包含了一些辅助函数。
         展示了依赖注入的接口使用方式。
    */
    type Feature struct {
	    gotree.AppService
    }

    func (this *Feature) Gotree() *Feature {
        this.AppService.Gotree(this)
        //如果 Controller 和 Timer 的成员变量使用接口接收,使用 InjectImpl 注入接口名。
        //使用 tag `impl:"simple"` 接收
        this.InjectImpl("simple", this)
        return this
    }

    func (this *Feature) Simple() (result []struct {
        Id    int
        Value string
        Pos   float64
    }, e error) {
        var mapFeature map[int]struct {
            Id    int
            Value string
        }
        //使用 NewMap 函数,创建匿名结构体的 map
        helper.NewMap(&mapFeature)

        var newFeatures []struct {
            Id    int
            Value string
        }
        //使用 NewSlice 函数,创建匿名结构体的数组
        if e = helper.NewSlice(&newFeatures, 2); e != nil {
            return
        }
        for index := 0; index < len(newFeatures); index++ {
            newFeatures[index].Id = index + 1
            newFeatures[index].Value = "hello"

            //匿名数组结构体赋值赋值给 匿名map结构体
            mapFeature[index] = newFeatures[index]
        }

        //内存拷贝,支持数组,结构体。
        if e = helper.Memcpy(&result, newFeatures); e != nil {
            return
        }

        //反射升序排序
        helper.SliceSortReverse(&result, "Id")
        //反射降序排序
        helper.SliceSort(&result, "Id")

        //group go并发
        group := helper.NewGroup()
        group.Add(func() error {
            //配置文件读取 域名::key名
            mode := helper.Config().String("sys::Mode")
            helper.Log().Notice("Notice", mode)
            return nil
        })
        group.Add(func() error {
            //配置文件读取 域名::key名
            len := helper.Config().DefaultInt("sys::LogWarnQueueLen", 512)
            helper.Log().Warning("Warning", len)
            return nil
        })
        group.Add(func() error {
            helper.Log().Debug("Debug")
            return nil
        })

        //等待以上3个并发结束
        group.Wait()
        return
    }

cache

    /* 
        代码文件  learning/dao/sources/cache/course.go
        配置文件  learning/dao/conf/dev/cache.conf
        展示 redis 缓存数据源的使用
    */
    func init() {
        gotree.Dao().RegCache(new(Course).Gotree())
    }

    type CourseCache struct {
        gotree.ComCache            // 继承缓存基类
    }

    func (this *Course) Gotree() *Course {
        this.ComCache.Gotree(this)
        return this
    }

    // 1. 多态方法 重写 主要用于绑定 Com
    // 2. 只有 ProductController 可以使用
    func (this *Course) Com() string {
        return "Feature"
    }

    func (this *Course) TestGet() (result struct {
        CourseInt    int
        CourseString string
    }, err error) {

        // this.do 函数,调用redis
        strData, err := redis.Bytes(this.Do("GET", "Feature"))
        if err != nil {
            return
        }
        err = json.Unmarshal(strData, &result)
        return
    }    

memory

    /* 
        代码文件  learning/dao/sources/memory/course.go
        展示内存数据源的使用
    */
    func init() {
        // RegMemory 注册
        gotree.Dao().RegMemory(new(Course).Gotree())
    }

    type Course struct {
       gotree.ComMemory    //继承内存基类
    }

    func (this *Course) Gotree() *Course {
        this.ComMemory.Gotree(this)
        return this
    }

    func (this *Course) Com() string {
        return "Feature"
    }

    func (this *Course) TestSet(i int, s string) {
        var data struct {
            CourseInt    int
            CourseString string
        }
        data.CourseInt = i
        data.CourseString = s
        if this.Setnx("Feature", data) {
            //如果 "Feature" 不存在
            this.Expire("Feature", 5)   //Expire 设置生存时间
        }
        this.Set("Feature", data) //直接覆盖

        //Get 存在返回true, 不存在反回false
        exists := this.Get("Feature", &data)
    }

api

    /* 
        代码文件  learning/dao/sources/api/tao_bao_ip.go
        配置文件  learning/dao/conf/api.conf
        展示 http 数据源的使用
    */
    func init() {
        // RegApi 注册
        gotree.Dao().RegApi(new(TaoBaoIp).Gotree())
    }

    type TaoBaoIp struct {
        gotree.ComApi
    }

    func (this *TaoBaoIp) Gotree() *TaoBaoIp {
        this.ComApi.Gotree(this)
        return this
    }

    // 绑定配置文件[api]域下的host地址, conf/dev/api.conf
    func (this *TaoBaoIp) Api() string {
        return "TaoBaoIp"
    }

    // GetIpInfo
    func (this *TaoBaoIp) GetIpInfo(ip string) (country string, err error) {
        //doc http://ip.taobao.com/instructions.html
        
        //get post postjson
        data, err := this.HttpGet("/service/getIpInfo.php", map[string]interface{}{"ip": ip})
        //data, err := this.HttpPost("/service/getIpInfo.php", map[string]interface{}{"ip": ip})
        //data, err := this.HttpPostJson("/service/getIpInfo.php", map[string]interface{}{"ip": ip})
    }

unit

    /*
        dao 单元测试
        代码目录  learning/dao/unit
        Testing 函数内部有引用框架,初始化、建立 redis、mysql 连接等。
        执行命令 go test -v -count=1 -run TestFeature $GOPATH/src/learning/dao/unit/feature_test.go
    */
    func TestFeature(t *testing.T) {
        // 四种数据源对象的单元测试
        api := new(api.TaoBaoIp).Gotree()
        cache := new(cache.Course).Gotree()
        memory := new(memory.Course).Gotree()
        model := new(product.Product).Gotree()

        //开启单元测试
        api.Testing()
        cache.Testing()
        memory.Testing()
        model.Testing()

        t.Log(api.GetIpInfo("49.87.27.95"))
        t.Log(cache.TestGet())
        t.Log(memory.TestGet())
        t.Log(model.Gets([]int64{1, 2, 3, 4}))
    }
    
    /* 
        app 单元测试
        代码目录  learning/app/unit
        测试service对象,请在本机开启dao 进程。 Testing : "Com组件名字:id"
        Testing 函数内部有引用框架,初始化、建立连接等。填写Com 即可使用。
        执行命令 go test -v -count=1 -run TestProduct $GOPATH/src/learning/app/unit/service_test.go
    */
    func TestProduct(t *testing.T) {
        service := new(service.Product).Gotree()
        //开启单元测试 填写 com
        service.Testing("Product:1", "User:1", "Order:1")
        
        t.Log(service.Store())
        t.Log(service.Shopping(1, 1))
    }

command

./dao telnet 该命令尝试连接数据库、redis。用来检验防火墙和密码。
./dao start 该命令会以督程的方式启动 dao。
./dao stop 该命令以优雅关闭的方式停止 dao, 会等待 dao 执行完当前未完成的请求。
./dao restart 该命令以热更新的方式重启 dao。
./app start 该命令会以督程的方式启动 app。
./app stop 该命令以优雅关闭的方式停止 app, 会等待 app 执行完当前未完成的请求。
./app restart 该命令以热更新的方式重启 app。
./app qps 该命令查看当前 app 调用 dao 的 qps 信息, -t 实时刷新。
./app status 该命令查看当前 app 状态信息
    $ cd $GOPATH/src/learning/dao
    $ go build
    $ ./dao start
    $ cd $GOPATH/src/learning/app
    $ go build
    $ ./app start
    
    #执行一个单元测试
    $ go test -v -count=1 -run TestUserRegister $GOPATH/src/learning/app/unit/gateway_test.go
    
    #查看qps,实时加 -t ./app qps -t
    $ ./app qps
    
    #查看状态
    $ ./app status

    #关闭
    $ ./app stop
    $ cd $GOPATH/src/learning/dao
    $ ./dao stop

dispersed

    # dao 实例 1
    $ cd $GOPATH/src/learning/dao
    $ go build
    $ vi $GOPATH/src/learning/dao/conf/dev/dispersed.conf
    # 修改为 AppAddrs = "127.0.0.1:3000,127.0.0.1:13000"
    $ ./dao start #启动 dao 实例1

    # dao 实例 2 
    $ vi $GOPATH/src/learning/dao/conf/dev/dispersed.conf
    # 修改为
    # BindAddr = "127.0.0.1:14000"
    $ vi $GOPATH/src/learning/dao/conf/dev/com.conf
    # 修改为
    # Order = 2
    # User = 2
    # Product = 2
    $ ./dao start #启动 dao 实例2

    # app 实例 1
    $ cd $GOPATH/src/learning/app
    $ go build
    $ ./app start

    # app 实例 2
    $ vi $GOPATH/src/learning/app/conf/dev/dispersed.conf
    # 修改为
    # BindAddr = "0.0.0.0:13000"
    $ ./app start
    $ ps


    # 单元测试 多实例
    $ vi $GOPATH/src/learning/app/unit/gateway_test.go
    # 加入新实例
    # gateway.AppendApp("127.0.0.1:8888")
    # gateway.AppendApp("127.0.0.1:18888")
    $ go test -v -count=1 -run TestStore $GOPATH/src/learning/app/unit/gateway_test.go
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].