内容简介:cmdr 04 - simple micro-servicebased onMy ado is too much.
cmdr 04 - simple micro-service
based on cmdr
v0.2.21
My ado is too much.
所以这次直入主题,谢绝吐槽。不知道 cmdr
干嘛用的,无妨看看前文
- 另一个 go 命令行参数处理器 - cmdr
- cmdr 02 - 复刻一个 wget
- cmdr 03 - 用流式接口定义命令行参数处理选项
那么,golang适合做后端开发,无论是 gRPC 还是 RESTful 都是它的强项。
一旦我们想要开发一个微服务时,抛开核心逻辑不谈,也不论 DevOps 方面究竟是 K8s,还是 Docker,还是裸机,总要面对一个启动、调试、测试的日常问题。
cmdr
除了提供命令行参数的解释能力之外,也额外提供了一个daemon插件,它可以帮助你简化日常开发工作,也令你不必关心 pid 文件、日志、退出信号等等问题,也无需重复编排 daemon 相关的命令行指令。
下面介绍怎么使用 daemon 插件,怎么编写实际的业务逻辑。我们以 demo 为例编写一个简单的示例性微服务,并解释具体的做法。
使用 Daemon 插件
启用 Daemon 插件
启用 Daemon 插件只需一行代码:
// Entry is app main entry func Entry() { logrus.SetLevel(logrus.DebugLevel) logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) daemon.Enable(svr.NewDaemon(), nil, nil, nil) if err := cmdr.Exec(rootCmd); err != nil { logrus.Errorf("Error: %v", err) } }
实现 daemon.Daemon
接口
启用 daemon 插件,需要你实现 daemon.Daemon
接口,并编写一定的包装代码来连接 cmdr
, daemon
以及你的业务逻辑。
daemon.Daemon
接口
daemon.Daemon
接口是这样的:
// Daemon interface should be implemented when you are using `daemon.Enable()`. type Daemon interface { OnRun(cmd *cmdr.Command, args []string, stopCh, doneCh chan struct{}) (err error) OnStop(cmd *cmdr.Command, args []string) (err error) OnReload() OnStatus(cxt *Context, cmd *cmdr.Command, p *os.Process) (err error) OnInstall(cxt *Context, cmd *cmdr.Command, args []string) (err error) OnUninstall(cxt *Context, cmd *cmdr.Command, args []string) (err error) }
对于一个微服务来说,你一定要编写的是 OnRun
, OnStop
两个方法。其他的几个方法,通常是可选的,daemon插件针对 RESTful http2 完成了默认的逻辑来支持 reload,status。此外,daemon插件还针对 systemd 实现了默认的 install 和 uninstall 逻辑。
所以下面我们首先完成必须的部分:
OnRun
type daemonImpl struct {} func (*daemonImpl) OnRun(cmd *cmdr.Command, args []string, stopCh, doneCh chan struct{}) (err error) { logrus.Debugf("demo daemon OnRun, pid = %v, ppid = %v", os.Getpid(), os.Getppid()) go worker(stopCh, doneCh) return } func worker(stopCh, doneCh chan struct{}) { LOOP: for { time.Sleep(time.Second) // this is work to be done by worker. select { case <-stopCh: break LOOP default: } } doneCh <- struct{}{} }
daemon 提供两个 channels, stopCh
应该促使你的代码结束无限循环,当你的代码退出循环之后应该触发 doneCh
事件。这样的逻辑保证了整个微服务的 graceful shutdown。
至于核心的逻辑,我们的 worker
,现在仅仅是个无限循环而已,你可以根据实际业务需要对其完成替换。
下一次我们也许提供一个 RESTful micro-service 的样本。
OnStop
以及其他
func (*daemonImpl) OnStop(cmd *cmdr.Command, args []string) (err error) { logrus.Debugf("demo daemon OnStop") return } func (*daemonImpl) OnReload() { logrus.Debugf("demo daemon OnReload") } func (*daemonImpl) OnStatus(cxt *daemon.Context, cmd *cmdr.Command, p *os.Process) (err error) { fmt.Printf("%v v%v\n", cmd.GetRoot().AppName, cmd.GetRoot().Version) fmt.Printf("PID=%v\nLOG=%v\n", cxt.PidFileName, cxt.LogFileName) return } func (*daemonImpl) OnInstall(cxt *daemon.Context, cmd *cmdr.Command, args []string) (err error) { logrus.Debugf("demo daemon OnInstall") return } func (*daemonImpl) OnUninstall(cxt *daemon.Context, cmd *cmdr.Command, args []string) (err error) { logrus.Debugf("demo daemon OnUninstall") return }
其它的接口方法基本上什么也不做,因为对于我们的worker来说,不需要在 OnStop
时清理数据库连接、释放其它资源,也不需要在 OnReload
时加载新的配置文件。
测试 demo
现在我们可以将 demo
跑起来看看了。首先研究下有什么命令行指令可供使用,我们采用 --tree
来看看:
可以注意到 s, server, serve, svr, daemon
命令是新增的,它包含一组子命令以提供 daemon 相关的操作。
其中 server start
子命令的解说是这样的:
也就是说, start
子命令的两个变形允许你在前台运行微服务,这是为了便于 docker 集成,以及在 IDE 中调试微服务的目的:
# 在前台运行微服务,而不是进入 daemon 模式 demo run demo start --foreground
对于 daemon 模式,没有标准的规范定义来要求一定具备哪些要素,不过大体上还是有约定俗成的东西。daemon 在中文中常常被称作 守护进程
。
daemon 模式一般来说包含这些要素:
- 进程启动后,fork自己的一份副本在操作系统中运行,这样副本和 tty 的关联就被detach了,此外子进程也具有独立的环境和进程空间,甚至是身份,不会收到其它服务、其它 ttys 的干扰。
- 子进程在 /var/run 中保持一个 pid 文件,这指示了子进程的基本状态
- 子进程通过 syscall signals 来与前台交互,一般地说,SIGHUP信号使得子进程 reload 配置信息完成重启动、却不被关闭进程和重新启动进程;SIGTERM等信号通知子进程结束服务。等等。
- 子进程将日志输出为 /var/log/ 下的日志文件
前台运行
所以,我们运行下demo在前台:
然后按下 CTRL-C 终止它,可以看到这个”微服务“能够正常地跑起来,也能正常地自行销毁。
守护进程运行
而如果我们要运行 demo 为守护进程的话,首先你需要将它编译成可执行文件,然后才能启动为守护进程模式。
通过 vagrant 环境,我们可以看到守护进程启动了,然后被我们的 stop 指令正确地关闭了。
systemd 服务运行
在支持 systemd 的 Linux 发行版中,我们可以测试将微服务安装为 systemd 服务。
其中, sudo /vagrant/demo server install
完成安装动作,成功之后demo服务就安装就绪了,并且已经被预设为随系统启动而自动启动的模式。
然后我们依照 systemd 的规范启动它: sudo systemctl start demo@$USER.service
。
值得注意的是,我们将 demo 安装为了通配模式,因此 demo 是可以在不同用户身份下被启动的。如果你想用专用的微服务账户启动它,你可以使用: sudo systemctl start demo@msuser.service
。
然后我们通过 sudo systemctl status demo@vagrant.service
查看到 demo 已经启动成功了,其中有三个错误,然而他们是可以被忽略的,它们都是为了尝试建立几个相关文件夹的目的,所以只是预防性的指令。而 demo 的正主,也就是 ExecStart 行表示启动时成功的,而且 Active 的状态也是 running 状态。
此时,log/logrus 等日志输出也被转发到了日志文件 /var/log/demo/demo.log 中。
那么我们也可以通过 sudo systemctl stop demo@$USER.service
来停止服务。
小结
由于 systemd 在 macOS 中并不被直接支持,所以对于这个部分的测试是放在 vagrant 中完成的。
对于 Windows 来说,你只能使用 server run
前台运行的方式,我们也暂无支持 NT Service 的计划。但你可以通过前台运行的方式完成日常开发调试工作。
实际的生产环境中,你可以选择 centos,ubuntu 等发行版,部署需要的只是 sudo demo server install
一条指令。
对于容器的环境,你应该使用 demo server run
这种前台运行模式来启动。
参考
以上所述就是小编给大家介绍的《cmdr 04 - 简单微服务 (daemon)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 服务端指南 服务端概述 | 微服务架构概述
- 微服务化之服务拆分与服务发现
- 微服务化之服务拆分与服务发现
- 小白入门微服务(4) - 服务注册与服务发现
- 服务端指南 服务端概述 | SOA 对比微服务架构
- MySQL服务启动时显示本地计算机上的MySQL服务启动后停止。某些服务在未由其它服务或。。。
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JSON 在线解析
在线 JSON 格式化工具
HEX HSV 转换工具
HEX HSV 互换工具