基于hprose-golang创建RPC微服务

基于hprose-golang创建RPC微服务,第1张

概述Hprose(High Performance Remote Object Service Engine) 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。 官网:https://hprose.com/ 本文将讲解如何使用Hprose go 服务端编写一个微服务,并实现客户端调用。 本文的涉及的项目代码托管在github:https://g

Hprose(High Performance Remote Object Service Engine)
是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。

官网:https://hprose.com/

本文将讲解如何使用Hprose go 服务端编写一个微服务,并实现客户端调用。

本文的涉及的项目代码托管在github:https://github.com/52fhy/hprose-sample 。

使用Go实现服务端 初始化

git初始化:

git initecho "main" >> .gitignore echo "# hprose-sample" >> README.md

项目使用go mod管理依赖,请确保安装的Go版本支持该命令。先初始化go.mod文件:

go mod init sample

最终项目目录结构一览:

├── config│?? └── rd.ini├── dao├── main.go├── model└── util    ├── config.go    └── state.go├── service│?? └── sample.go├── go.mod├── go.sum├── clIEnt_test.go├── README.md├── PHP├── logs

golang写微服务的好处就是我们可以按照自己理想的目录结构写代码,而无需关注代码 autoload 问题。

配置项

我们使用go-ini/ini来管理配置文件。

项目地址:https://github.com/go-ini/ini
文档地址:https://ini.unknwon.io/

这个库使用起来很简单,文档完善。有2种用法,一种是直接加载配置文件,一种是将配置映射到结构体,使用面向对象的方法获取配置。这里我们采用第二种方案。

首先在conf/里建个配置文件rd.ini:

ListenAddr = 0.0.0.0:8080[MysqL]Host = localhostPort = 3306User = rootPassword =Database = sample[Redis]Host = localhostPort = 6379Auth =

编写util/config.go加载配置:

package utilimport "github.com/go-ini/ini"type MysqLCfg struct{    Host string    Port int32    User string    Password string    Database string}type RedisCfg struct{    Host string    Port int32    Auth string}type Config struct {    ListenAddr string    MysqL MysqLCfg    Redis RedisCfg}//全局变量var Cfg Config//加载配置func InitConfig(Configfile string) error {    return ini.MapTo(Cfg,Configfile)}
main.go

这里我们需要实现项目初始化、服务注册到RPC并启动一个TCP server。

package mainimport (    "flag"    "fmt"    "github.com/hprose/hprose-golang/rpc"    "sample/service"    "sample/util")func hello(name string) string {    return "Hello " + name + "!"}func main() {    //解析命令行参数    configfile := flag.String("c","config/rd.ini","config file")    flag.Parse()    err := util.InitConfig(*configfile)    if err != nil {        fmt.Printf("load config file fail,err:%v\n",err)        return    }    fmt.Printf("server is running at %s\n",util.Cfg.ListenAddr)    //tcp,推荐    server := rpc.NewTcpserver("tcp4://" + util.Cfg.ListenAddr + "/")    //注册func    server.AddFunction("hello",hello)    //注册struct,命名空间是Sample    server.AddInstanceMethods(&service.SampleService{},rpc.Options{nameSpace: "Sample"})    err = server.Start()    if err != nil {        fmt.Printf("start server fail,err)        return    }}

我们看到,RPC里注册了一个函数hello,还注册了service.SampleService里的所有方法。

注:这里注册服务的时候使用了nameSpace选项从而支持命名空间,这个在官方的WIKI里没有示例说明,很容易忽略。

其中SampleService是一个结构体,定义在service/sample.go文件里:

sample.go

package serviceimport (    "sample/model"    "sample/util")//定义服务type SampleService struct {}//服务里的方法func (this *SampleService) GetUserInfo(uID int64) util.State {    var state util.State    if uID <= 0 {        return state.SetErrCode(1001).SetErrMsg("uID不正确").End()    }    var user model.User    user.ID = uID    user.name = "test"    return state.SetData(user).End()}
日志

作为一个线上项目,我们需要在业务代码里打印一些日志辅助我们排查问题。日志这里直接使用 beego的日志库logs

package utilimport (    "errors"    "fmt"    "github.com/astaxIE/beego/logs")var Logger *logs.BeeLoggerfunc InitLog() error {    Logger = logs.NewLogger(10)    err := Logger.SetLogger(logs.AdapterMultifile,fmt.Sprintf(`{"filename":"/work/git/hprose-sample/logs/main.log","daily":true,"maxdays":7,"rotate":true}`))    if err != nil {        return errors.New("init beego log error:" + err.Error())    }    Logger.Async(1000)    return nil}

这里定义里全局变量Logger,之后可以在项目任意地方使用。

日志选项里filename最好是动态配置,这里为了演示,直接写的固定值。

使用示例:

if uID <= 0 {    util.Logger.DeBUG("uID error. uID:%d",uID)}
Go测试用例

每个项目都应该写测试用例。下面的用例里,我们将测试上面注册的服务是否正常。

package mainimport (    "github.com/hprose/hprose-golang/rpc"    "sample/util"    "testing")//stub:申明服务里拥有的方法type clIEntStub struct {    Hello       func(string) string    GetUserInfo func(uID int64) util.State}//获取一个客户端func GetClIEnt() *rpc.TCPClIEnt {    return rpc.NewTCPClIEnt("tcp4://127.0.0.1:8050")}//测试服务里的方法func TestSampleService_GetUserInfo(t *testing.T) {    clIEnt := GetClIEnt()    defer clIEnt.Close()    var stub clIEntStub    clIEnt.UseService(&stub,"Sample") //使用命名空间    rep := stub.GetUserInfo(10001)    if rep.ErrCode > 0 {        t.Error(rep.ErrMsg)    } else {        t.Log(rep.Data)    }}//测试普通方法func TestHello(t *testing.T) {    clIEnt := GetClIEnt()    defer clIEnt.Close()    var stub clIEntStub    clIEnt.UseService(&stub)    rep := stub.Hello("func")    if rep == "" {        t.Error(rep)    } else {        t.Log(rep)    }}

运行:

$ go test -v=== RUN   TestSampleService_GetUserInfo--- PASS: TestSampleService_GetUserInfo (0.00s)    clIEnt_test.go:31: map[name:test ID:10001]=== RUN   TestHello--- PASS: TestHello (0.00s)    clIEnt_test.go:47: Hello func!PASSok      sample  0.016s
PHP调用 PHP-clIEnt

需要先下载hprose/hprose

composer config repo.packagist composer https://packagist.PHPcomposer.comcomposer require "hprose/hprose:^2.0"

clIEnt.PHP

<?PHPinclude "vendor/autoload.PHP";try{    $TcpserverAddr = "tcp://127.0.0.1:8050";    $clIEnt = \Hprose\Socket\ClIEnt::create($TcpserverAddr,false);    $service = $clIEnt->useService('','Sample');    $rep = $service->GetUserInfo(10);    print_r($rep);} catch (Exception $e){    echo $e->getMessage();}

运行:

$ PHP PHP/clIEnt.PHP stdClass Object(    [errCode] => 0    [errMsg] =>     [data] => stdClass Object        (            [ID] => 10            [name] => test        ))

实际使用时最好对该处调用的代码做进一步的封装,例如实现异常捕获、返回码转换、日志打印等等。

编写codetips

本节不是必须的,但是在多人合作的项目上,可以提高沟通效率。

hprose 不支持一键生成各语言的客户端代码(没有IDL支持),在写代码的时候PHP编译器没法提示。我们可以写一个类或者多个类,主要是Model类和Service类:

Model类定义字段属性,当传参或者读取返回对象里内容的是,可以使用Get/Set方法; Service类类似于抽象类,仅仅是把go服务端里的方法用PHP定义一个空方法,包括参数类型、返回值类型,这个类并不会真正引入,只是给IDE作为代码提示用的。

示例:

class SampleService{    /**     * 获取用户信息     * @param int $uID     * @return State     */    public function GetUserInfo(int $uID): State    {    }}

调用的地方(请使用PHPStorm查看提示效果):

/** * @return SampleService * @throws Exception */function getClIEnt(){    $TcpserverAddr = "tcp://127.0.0.1:8050";    $clIEnt = \Hprose\Socket\ClIEnt::create($TcpserverAddr,'Sample');    return $service;}try {    $clIEnt = getClIEnt();    $rep = $clIEnt->GetUserInfo(10);    echo $rep->errCode . PHP_Eol;    print_r($rep);} catch (Exception $e) {    echo $e->getMessage();}

方法getClIEnt返回的注释里加了@return SampleService,下面调用的$rep->errCode就会有代码提示了。详见:https://github.com/52fhy/hprose-sample/tree/master/PHP 。

部署

线上微服务需要后台长期稳定运行,可以使用supervisord工具。

如果还没有安装,请餐参考:Supervisor使用教程。

新增一个常驻任务,需要新建配置。

以上述sample为例,新建配置:go_hprose_sample.ini:

[program:go_hprose_sample]command=/usr/local/bin/go  /work/git/hprose-sample/mainpriority=999                ; the relative start priority (default 999)autostart=true              ; start at supervisord start (default: true)autorestart=true            ; retstart at unexpected quit (default: true)startsecs=10                ; number of secs prog must stay running (def. 10)startretrIEs=3              ; max # of serial start failures (default 3)exitcodes=0,2               ; 'expected' exit codes for process (default 0,2)stopsignal=QUIT             ; signal used to kill process (default TERM)stopwaitsecs=10             ; max num secs to wait before SIGKILL (default 10)user=root                 ; setuID to this UNIX account to run the programlog_stdout=truelog_stderr=true             ; if true,log program stderr (def false)logfile=/work/git/hprose-sample/logs/supervisor/go_hprose_sample.loglogfile_maxbytes=1MB        ; max # logfile bytes b4 rotation (default 50MB)logfile_backups=10          ; # of logfile backups (default 10)stdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默认 50MBstdout_logfile_backups=20     ; stdout 日志文件备份数stdout_logfile=/work/git/hprose-sample/logs/supervisor/go_hprose_sample.stdout.log

注:上述配置仅供参考,请务必理解配置的含义。

然后启动任务:

supervisorctl rereadsupervisorctl updatesupervisorctl start go_hprose_sample

线上部署最少要2台机器,组成负载均衡。这样当升级的时候,可以一台一台的上线,避免服务暂停。

Hprose 总结

优点:

轻量级、跨语言、跨平台 更少的网络传输量,使用二进制传输协议 简单,跟着官方提供的例子很快就能掌握基本的使用 文档完善

缺点:

不支持IDL(接口描述语言),所以无法一键生成客户端调用代码,需要手动维护 参考

1、Supervisor使用教程 - 飞鸿影 - 博客园 https://www.cnblogs.com/52fhy/p/10161253.HTML 2、Home · hprose/hprose-golang Wiki https://github.com/hprose/hprose-golang/wiki 3、go-ini/ini: 超赞的 Go 语言 INI 文件 *** 作 https://ini.unknwon.io/ 4、golang中os/exec包用法 https://www.cnblogs.com/vijayfly/p/6102470.HTML

总结

以上是内存溢出为你收集整理的基于hprose-golang创建RPC微服务全部内容,希望文章能够帮你解决基于hprose-golang创建RPC微服务所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1264984.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-08
下一篇2022-06-08

发表评论

登录后才能评论

评论列表(0条)

    保存