最近发现golang社区里出了一个新星的微服务框架,来自好未来,光看这个名字,就很有奔头,之前,也只是玩过go-micro,其实真正的还没有在项目中运用过,只是觉得 微服务,grpc 这些很高大尚,还没有在项目中,真正的玩过,我看了一下官方提供的工具真的很好用,只需要定义好,舒适文件jia结构 都生成了,只需要关心业务,
加上最近 有个投票的活动,加上最近这几年中台也比较火,所以决定玩一下,
先聊聊中台架构思路吧,look 先看架
中台的概念大概就是把一个一个的app 统一起来,反正我是这样理解的
先聊用户服务吧,现在一个公司有很多的公众号,小程序,微信的,支付宝的,还有xxx xxx ,很多的平台,每次开发的时候,我们总是需要做用户登陆的服务,不停的复制代码,然后我们就在思考能不能有一套独立的用户服务,
只需要告诉我你需要传个你要登陆的平台(比如微信),微信登陆,需要的是客户端返回给服务端一个code ,然后服务端拿着这个code去微信获取用户信息,反正大家都明白,
我们决定,将所有的信息 弄到 配置公共服务中去,里面在存,微信,支付宝,以及其它平台的 appid ,appkey,还有支付的appid,appkey,
这样就写一套
--------------------------------------------------------------------------------------------
go-zerio: https://github.com/tal-tech/go-zero
最后说说实现吧,整个就一个repo
网关,我们用的是: go-zero的Api服务
其它它的是服务,我们就是用的go-zero的rpc服务
看下目录结构
整个项目完成,我一个人操刀, 写了1个来星期,我就实现了上面的中台系统;
go-zero作者私聊我说,可不可以写得丰富点,所以我决定把我的源码也加到文章里面
先看官方文档https://www.yuque.com/tal-tech/go-zero/yaoehb
我们先把网关搭建起来
创建datacenter-api服务
➜ blogs mkdir datacenter && cd datacenter
➜ datacenter go mod init datacenter
go: creating new go.mod: module datacenter
➜ datacenter
查看book目录
1
2
3
4
|
➜ datacenter tree . └── go.mod 0 directories, 1 file |
二、创建api文件
1
2
3
4
5
6
|
➜ datacenter goctl api -o datacenter.api Done. ➜ datacenter tree . ├── datacenter.api └── go.mod |
三、定义api服务 分别包含了上面的 公共服务,用户服务,和 投票活动服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
|
info( title: "中台系统"// TODO: add title desc: "中台系统"// TODO: add description author: "jackluo" email: "net.webjoy@gmail.com" ) //获取 应用信息 type Beid struct { Beid int64 `json:"beid"` } type Token struct{ Token string `json:"token"` } type WxTicket struct{ Ticket string `json:"ticket"` } type Application struct { Sname string `json:"Sname"` //名称 Logo string `json:"logo"` // login Isclose int64 `json:"isclose"` //是否关闭 Fullwebsite string `json:"fullwebsite"` // 全站名称 } type SnsReq struct{ Beid Ptyid int64 `json:"ptyid"` //对应平台 BackUrl string `json:"back_url"` //登陆返回的地址 } type SnsResp struct{ Beid Ptyid int64 `json:"ptyid"` //对应平台 Appid string `json:"appid"` //sns 平台的id Title string `json:"title"` //名称 LoginUrl string `json:"login_url"` //微信登陆的地址 } type WxShareResp struct { Appid string `json:"appid"` Timestamp int64 `json:"timestamp"` Noncestr string `json:"noncestr"` Signature string `json:"signature"` } @server( group: common ) service datacenter-api { @doc( summary: "获取站点的信息" ) @handler votesVerification get /MP_verify_NT04cqknJe0em3mT.txt (SnsReq) returns (SnsResp) @handler appInfo get /common/appinfo (Beid) returns (Application) @doc( summary: "获取站点的社交属性信息" ) @handler snsInfo post /common/snsinfo (SnsReq) returns (SnsResp) //获取分享的 @handler wxTicket post /common/wx/ticket (SnsReq) returns (WxShareResp) } //上传需要登陆 @server( jwt: Auth group: common ) service datacenter-api { @doc( summary: "七牛上传凭证" ) @handler qiuniuToken post /common/qiuniu/token (Beid) returns (Token) } //注册请求 type RegisterReq struct { // TODO: add members here and delete this comment Mobile string `json:"mobile"` //基本一个手机号码就完事 Password string `json:"password"` Smscode string `json:"smscode"` //短信码 } //登陆请求 type LoginReq struct{ Mobile string `json:"mobile"` Type int64 `json:"type"` //1.密码登陆,2.短信登陆 Password string `json:"password"` } //微信登陆 type WxLoginReq struct { Beid int64 `json:"beid"` //应用id Code string `json:"code"` //微信登陆密钥 Ptyid int64 `json:"ptyid"` //对应平台 } //返回用户信息 type UserReply struct { Auid int64 `json:"auid"` Uid int64 `json:"uid"` Beid int64 `json:"beid"` //应用id Ptyid int64 `json:"ptyid"` //对应平台 Username string `json:"username"` Mobile string `json:"mobile"` Nickname string `json:"nickname"` Openid string `json:"openid"` Avator string `json:"avator"` JwtToken } //返回APPUser type AppUser struct{ Uid int64 `json:"uid"` Auid int64 `json:"auid"` Beid int64 `json:"beid"` //应用id Ptyid int64 `json:"ptyid"` //对应平台 Nickname string `json:"nickname"` Openid string `json:"openid"` Avator string `json:"avator"` } type LoginAppUser struct{ Uid int64 `json:"uid"` Auid int64 `json:"auid"` Beid int64 `json:"beid"` //应用id Ptyid int64 `json:"ptyid"` //对应平台 Nickname string `json:"nickname"` Openid string `json:"openid"` Avator string `json:"avator"` JwtToken } type JwtToken struct { AccessToken string `json:"access_token,omitempty"` AccessExpire int64 `json:"access_expire,omitempty"` RefreshAfter int64 `json:"refresh_after,omitempty"` } type UserReq struct{ Auid int64 `json:"auid"` Uid int64 `json:"uid"` Beid int64 `json:"beid"` //应用id Ptyid int64 `json:"ptyid"` //对应平台 } type Request { Name string `path:"name,options=you|me"` } type Response { Message string `json:"message"` } @server( group: user ) service user-api { @handler ping post /user/ping () @handler register post /user/register (RegisterReq) returns (UserReply) @handler login post /user/login (LoginReq) returns (UserReply) @handler wxlogin post /user/wx/login (WxLoginReq) returns (LoginAppUser) @handler code2Session get /user/wx/login () returns (LoginAppUser) } @server( jwt: Auth group: user middleware: Usercheck ) service user-api { @handler userInfo get /user/dc/info (UserReq) returns (UserReply) } // 投票活动api type Actid struct { Actid int64 `json:"actid"` //活动id } type VoteReq struct { Aeid int64 `json:"aeid"` // 作品id Actid } type VoteResp struct { VoteReq Votecount int64 `json:"votecount"` //投票票数 Viewcount int64 `json:"viewcount"` //浏览数 } // 活动返回的参数 type ActivityResp struct { Actid int64 `json:"actid"` Title string `json:"title"` //活动名称 Descr string `json:"descr"` //活动描述 StartDate int64 `json:"start_date"` //活动时间 EnrollDate int64 `json:"enroll_date"` //投票时间 EndDate int64 `json:"end_date"` //活动结束时间 Votecount int64 `json:"votecount"` //当前活动的总票数 Viewcount int64 `json:"viewcount"` //当前活动的总浏览数 Type int64 `json:"type"` //投票方式 Num int64 `json:"num"` //投票几票 } //报名 type EnrollReq struct { Actid Name string `json:"name"` // 名称 Address string `json:"address"` //地址 Images []string `json:"images"` //作品图片 Descr string `json:"descr"` // 作品描述 } // 作品返回 type EnrollResp struct { Actid Aeid int64 `json:"aeid"` // 作品id Name string `json:"name"` // 名称 Address string `json:"address"` //地址 Images []string `json:"images"` //作品图片 Descr string `json:"descr"` // 作品描述 Votecount int64 `json:"votecount"` //当前活动的总票数 Viewcount int64 `json:"viewcount"` //当前活动的总浏览数 } @server( group: votes ) service votes-api { @doc( summary: "获取活动的信息" ) @handler activityInfo get /votes/activity/info (Actid) returns (ActivityResp) @doc( summary: "活动访问+1" ) @handler activityIcrView get /votes/activity/view (Actid) returns (ActivityResp) @doc( summary: "获取报名的投票作品信息" ) @handler enrollInfo get /votes/enroll/info (VoteReq) returns (EnrollResp) @doc( summary: "获取报名的投票作品列表" ) @handler enrollLists get /votes/enroll/lists (Actid) returns(EnrollResp) } @server( jwt: Auth group: votes middleware: Usercheck ) service votes-api { @doc( summary: "投票" ) @handler vote post /votes/vote (VoteReq) returns (VoteResp) @handler enroll post /votes/enroll (EnrollReq) returns (EnrollResp) } |
上面基本上写就写的API及文档的思路
四、生成datacenter api服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
➜ datacenter goctl api go -api datacenter.api -dir . Done. ➜ datacenter tree . ├── datacenter.api ├── etc │ └── datacenter-api.yaml ├── go.mod ├── internal │ ├── config │ │ └── config.go │ ├── handler │ │ ├── common │ │ │ ├── appinfohandler.go │ │ │ ├── qiuniutokenhandler.go │ │ │ ├── snsinfohandler.go │ │ │ ├── votesverificationhandler.go │ │ │ └── wxtickethandler.go │ │ ├── routes.go │ │ ├── user │ │ │ ├── code2sessionhandler.go │ │ │ ├── loginhandler.go │ │ │ ├── pinghandler.go │ │ │ ├── registerhandler.go │ │ │ ├── userinfohandler.go │ │ │ └── wxloginhandler.go │ │ └── votes │ │ ├── activityicrviewhandler.go │ │ ├── activityinfohandler.go │ │ ├── enrollhandler.go │ │ ├── enrollinfohandler.go │ │ ├── enrolllistshandler.go │ │ └── votehandler.go │ ├── logic │ │ ├── common │ │ │ ├── appinfologic.go │ │ │ ├── qiuniutokenlogic.go │ │ │ ├── snsinfologic.go │ │ │ ├── votesverificationlogic.go │ │ │ └── wxticketlogic.go │ │ ├── user │ │ │ ├── code2sessionlogic.go │ │ │ ├── loginlogic.go │ │ │ ├── pinglogic.go │ │ │ ├── registerlogic.go │ │ │ ├── userinfologic.go │ │ │ └── wxloginlogic.go │ │ └── votes │ │ ├── activityicrviewlogic.go │ │ ├── activityinfologic.go │ │ ├── enrollinfologic.go │ │ ├── enrolllistslogic.go │ │ ├── enrolllogic.go │ │ └── votelogic.go │ ├── middleware │ │ └── usercheckmiddleware.go │ ├── svc │ │ └── servicecontext.go │ └── types │ └── types.go └── datacenter.go 14 directories, 43 files |
我们打开etc/datacenter-api.yaml 把必要的配置信息加上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
Name: datacenter-api Log: Mode: console Host: 0.0.0.0 Port: 8857 Auth: AccessSecret: 你的jwtwon Secret AccessExpire: 86400 CacheRedis: - Host: 127.0.0.1:6379 Pass: 密码 Type: node UserRpc: Etcd: Hosts: - 127.0.0.1:2379 Key: user.rpc CommonRpc: Etcd: Hosts: - 127.0.0.1:2379 Key: common.rpc VotesRpc: Etcd: Hosts: - 127.0.0.1:2379 Key: votes.rpc |
上面的UserRpc,和CommonRpc ,还有VotesRpc 这些我先写上,后面再来慢慢加
我们先来写CommonRpc的服务
新建项目目录
1
|
➜ datacenter mkdir -p common/rpc && cd common/rpc |
直接就新建在了,datacenter目录中,因为common 里面,可能以后会不只会提供rpc服务,可能还有api的服务,所以又加了rpc目录
goctl创建模板
1
2
3
|
➜ rpc goctl rpc template -o=common.proto ➜ rpc ls common.proto |
往里面填入内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
➜ rpc cat common.proto syntax = "proto3"; package common; message BaseAppReq{ int64 beid=1; } message BaseAppResp{ int64 beid=1; string logo=2; string sname=3; int64 isclose=4; string fullwebsite=5; } //请求的api message AppConfigReq { int64 beid=1; int64 ptyid=2; } //返回的值 message AppConfigResp { int64 id=1; int64 beid=2; int64 ptyid=3; string appid=4; string appsecret=5; string id="codetool">
gotcl生成rpc服务
基本上,就把所有的目录规范和结构的东西都生成了,就不用纠结项目目录了,怎么放了,怎么组织了 看一下,配置信息,里面可以写入mysql和其它redis的信息
我们再来加上数据库的服务
这样基本的一个rpc就写完了,然后我们将rpc 和model 还有api串连起来,这个官方的文档已经很详细了,这里就只是贴一下代码
再在svc中修改
上面的代码已经将rpc 和 model 数据库关联起来了,我们现在再将rpc 和 api关联起来
加入svc服务中
这样基本上,我们就可以在logic的文件目录中调用了
这样,基本就连接起来了,其它基本上就不用改了,UserRPC,和VotesRPC类似,这里就不在写了 下面我说说使用心得吧 go-zero 的确香,因为它有一个goctl 的工具,他可以自动的把代码结构全部的生成好,我们就不再去纠结,目录结构 ,怎么组织,没有个好几年的架构能力是不好实现的,有什么规范那些,并发,熔断,完全不用,考滤其它的,专心的实现业务就好,像微服务,还要有服务发现,一系列的东西,都不用关心,因为go-zero内部已经实现了,我写代码也写了有10多年了,之前一直用的php,比较出名的就 laravel,thinkphp,基本上就是模块化的,像微服那些实现直来真的有成本,但是你用上go-zero,你就像调api接口一样简单的开发,其它什么服务发现,那些根本就不用关注了,只需要关注业务。一个好的语言,框架,他们的底层思维,永远都是效率高,不加班的思想,我相信go-zero会提高你和你团队或是公司的效率。go-zero的作者说,他们有个团队专门整理go-zero框架,目的也应该很明显,那就是提高,他们自己的开发效率,流程化,标准化,是提高工作效率的准则,像我们平时遇到了问题,或是遇到了bug,我第一个想到的不是怎么去解决我的bug,而是在想我的流程是不是有问题,我的哪个流程会导致bug,最后我相信go-zero 能成为 微服务开发 的首选框架 最后说说遇到的坑吧: grpc 本人第一次用,然后就遇到了,有些字符为空时,字段值不显示的问题:
通过grpc官方库中的 跨域问题: go-zero的设置了,感觉没有效果,大佬说通过nginx 设置,后面发现还是不行,最近 ,强行弄到了一个域名下,后面有时间再解决 go-zero的sqlx 问题,这个真的费了很长的时间,
其次就是这个Conversion from collation utf8_general_ci into utf8mb4_unicode_ci,这个导致的大概原因是,现在都喜欢用emj表情了,mysql数据识别不了 最后发现是数据连接问题:
mysql这边照样按照原始的方式,将配置文件修改编码格式 --------------------------------- mark 到此这篇关于如何用go-zero 实现中台系统的文章就介绍到这了,更多相关go-zero中台系统 内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家! 原文链接:https://www.cnblogs.com/jackluo/p/14148518.html 延伸 · 阅读
精彩推荐
|