??xml version="1.0" encoding="utf-8" standalone="yes"?>ս:C++博客-金庆的专?/title><link>//www.pppqb.icu/jinq0123/</link><description /><language>zh - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2019/09/20/216848.html金庆金庆Fri, 20 Sep 2019 06:45:00 GMT//www.pppqb.icu/jinq0123/archive/2019/09/20/216848.html//www.pppqb.icu/jinq0123/comments/216848.html//www.pppqb.icu/jinq0123/archive/2019/09/20/216848.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/216848.html//www.pppqb.icu/jinq0123/services/trackbacks/216848.html
(金庆的专?2019.9)

svn rename 某个文gq更改内容后提交Q历史就会丢失?br />如果 svn rename 后不改内容,立即提交Q就可以延箋原有历史?br />所以改名这L操作应该独立提交一ơ?br />
git 改名强大多了,会比较内容确定其原来的文件。但更改太多也会判断出错?br />

金庆 2019-09-20 14:45 发表评论
]]>
golang net Windows q不支持自定义dns - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2019/04/20/216361.html金庆金庆Sat, 20 Apr 2019 02:52:00 GMT//www.pppqb.icu/jinq0123/archive/2019/04/20/216361.html//www.pppqb.icu/jinq0123/comments/216361.html//www.pppqb.icu/jinq0123/archive/2019/04/20/216361.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/216361.html//www.pppqb.icu/jinq0123/services/trackbacks/216361.html
(金庆的专?2019.4)

See: https://github.com/golang/go/issues/29621

使用 consul 注册服务Q可使用 consul ?DNS 解析到服务的地址?br />但是 golang 直到 1.12 仍然?Windows 上无法用自定义?DNS 服务Qƈ且没有计划支持?br />
例如本机 127.0.0.1 开 consul, 注册 myservice:8888 服务?br />consul DNS 的默认端口ؓ 8600.

grpc ?Dial() 允许输入一?dns 地址Q以?grpc.Dial() ?Linux Z成功Q但?Windows 上失败:

conn, err := grpc.Dial("dns://127.0.0.1:8600/myservice.service.consul:8888", ...)


金庆 2019-04-20 10:52 发表评论
]]>
用赋g?protobuf CopyFrom() - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2019/04/04/216338.html金庆金庆Thu, 04 Apr 2019 09:57:00 GMT//www.pppqb.icu/jinq0123/archive/2019/04/04/216338.html//www.pppqb.icu/jinq0123/comments/216338.html//www.pppqb.icu/jinq0123/archive/2019/04/04/216338.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/216338.html//www.pppqb.icu/jinq0123/services/trackbacks/216338.html
CZQ[Replace protobuf CopyFrom with assignment](https://github.com/tensorflow/tensorflow/commit/9501c4104125fb8c2c2d2e837fc2dd8a24034d52)

protobuf 生成?C++ 代码中,因ؓ CopyFrom() 可以接受M Message 作ؓ参数Q?br />所以有可能?个不同类型的消息之间复制?br />
```
  void CopyFrom(const ::google::protobuf::Message& from) final;
  void CopyFrom(const PlayerData& from);
```

而赋值操作可以保证类型正?br />
```
class PlayerData : public ::google::protobuf::Message {
 public:
  ...
  inline PlayerData& operator=(const PlayerData& from) {
    CopyFrom(from);
    return *this;
  }
  #if LANG_CXX11
  inline PlayerData& operator=(PlayerData&& from) noexcept {
    ...
  }
  #endif
```

cd不一致时~译会报错:
```
error: no match for ‘operator=’ (operand types are ‘a::PlayerData’ and ‘a::HeroInfo’)
```

发现自己用了多年?CopyFrom() 都是错误的用?img src ="//www.pppqb.icu/jinq0123/aggbug/216338.html" width = "1" height = "1" />

金庆 2019-04-04 17:57 发表评论
]]>
open-match匚w程 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2019/01/31/216228.html金庆金庆Thu, 31 Jan 2019 02:21:00 GMT//www.pppqb.icu/jinq0123/archive/2019/01/31/216228.html//www.pppqb.icu/jinq0123/comments/216228.html//www.pppqb.icu/jinq0123/archive/2019/01/31/216228.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/216228.html//www.pppqb.icu/jinq0123/services/trackbacks/216228.html

ս:# open-match匚w程


(金庆的专?2019.1)

https://github.com/GoogleCloudPlatform/open-match

open-match 是一个通用的游戏匹配框架?br />由游戏提供自定义的匹配算法(以docker镜像的方式提供)?br />
分ؓ多个q程Q各q程之间׃n一?redis.

* 前端, 接收玩家加入 redisQ成功后通知玩家戉K服地址
* 后端Q设|一局游戏的匹配规则,讄戉K服地址
* MMFOrcQ启动匹配算?MMF)
* MMF, 自定义匹配算法,d redis 获取玩家Q匹配成功就结果写?redis. 仅匹配一局退出?br />
游戏服中q接 open-match 的前端与后端的进E,分别UCؓ frontendclient ?Director?br />输入?部䆾Q一是玩家信息,二是对局信息?br />Director 向后端输入对局信息Q就会收C个接一个的对局人员列表.
Director 需要ؓ每个对局开戉KQ然后通知后端戉K地址?br />后端房间地址写入 redis, 然后前端d到房间地址Q就通知 frontendclientQ让玩家q入戉K?br />

## test/cmd/frontendclient


模拟大厅服或l队服,q接前端API, h匚w玩家/队伍。成功后收到房间服(DGS)的地址(Assignment)?br />
Player 实际上是一个队伍,其中ID字段是用I格分隔的多个ID.
虽然参数cd都是 Player, CreatePlayer() 参数为整个队伍,?GetUpdates() 参数是单个玩家?br />
main() 中创建多个玩Ӟ每个玩家调用 GetUpdates() 以获取结果,go waitForResults() 中处理结果?br />waitForResult() d中的匹配结果,压入 resultsChanQ但好像 resultsChan 仅用于打华ͼ?br />所有玩家合q到 g 实例中,然后调用 CreatePlayer() h匚w?br />
cleanup() 调用 DeletePlayer() 来删除匹配请求,不仅需删除整个队伍Q也需要删除单个玩家?br />
好像最后取l果没取对地方,应该?resultChan 中获?Assignment, q用该地址 udpClient().

看了该示例就可以理解 frontend.proto

## examples/backendclient


MatchObject.Properties 是从 testprofile.json d的,应该改名?Profile 是否更好点?
pbProfile ?MatchObjectQProfile {同?MatchObject?
Profile 的定义是 MMF 所需的所有参数?br />`pbProfile.Properties = jsonProfile` 重复?遍?br />
ListMatches()列出q个Profile的所有匹配?br />收到一个匹配后Q须用CreateAssignments()房间服地址, UCؓ Assignment, 发送到所有游戏客L?br />

## cmd/frontendapi


CreatePlayer() ?Player 对象写入 redis, 键gؓ Player.Id, cd?HSET?br />?Player 的每?attributeQ添加到 ZSET 中去?br />此处 Player 是一l玩家?br />
GetUpdates() 每隔2sdredis, Player数据有变化时发送。此?Player 是单个玩家?br />
如果CreatePlayer()中队伍只有一个玩Ӟ
则写入的Player与GetUpdates()中读取的玩家是同一个redis键?br />

## cmd/backendapi


CreateMatch() ?profile cd?MatchObject, 是一个比赛的限制条g?br />profile 先写?redis, 键ؓ profile.Id.
`requestKey := xid() + "." + profile.Id`,
q将 requestKey 加入 redis 集合 "profileq"?br />然后?s查询 redis, 看是否有 requestKey 键出玎ͼq返回该倹{?br />
ListMatch() ?s调用一?CreateMatch().

DeleteMatch() 仅仅删除 Id q个键?br />
CreateAssignments() 为多个队伍设|Assignment, x间地址?br />遍历所有Roster中的Player对象Q在redis中设|Assignment.
(Assignment 更改后,会触发前端更新?
所?Player.Id ?"proposed" Ud "deindexed"Q这两个?ZSET, 分gؓ加入旉?br />Roster 应该是比赛中的阵营,如红方,蓝方Q每个阵营中可有多个队伍?br />
DeleteAssignments() 仅仅遍历所?Player 对象来删?Assignment 字段?br />

## cmd/mmforc


匚w程是由 mmforc (matchmaking function orchestrator) 控制的?br />
mmforc 每秒?redis ?profileq 中取?100 个成? 其中 profileq 是个setcdQ?br />使用命o为`SPOP profileq 100`.

Ҏ?profile, 创徏一?k8s dQ?br />
```
    // Kick off the job asynchrnously
    go mmfunc(ctx, profile, cfg, defaultMmfImages, clientset, &pool)
```

每隔10s, q有所有匹配Q务都完成后,需?`checkProposals`, 卛_?evaluator d?br />
profileq 中的元素 profile 为字W串QmatchObjectID.profileID?br />?profileID 为键Q可以从 redis d profile 的内? profile 是个 MatchObject 对象?br />
profile 的内容ؓ json Ԍ其中 "jsonkeys.mmfImages" ?mmf (matchmaking function) 镜像?br />
如果profiledp|Q或?mmfImages 为空Q则使用默认的镜像。mmfImages 未来会支持多个镜像?br />
通过 MMF_* 环境变量传入各种参数.

## mmf


CZQexamples\functions\golang\manual-simple

从环境变?"MMF_PROFILE_ID" 解析?profileID, q向 redis 查询(HGETALL) profileQHSET cd?br />
?profile 中取 pools 字段Q即匚w条g?br />pools 分ؓ多个 pool, 每个 pool 中有多个 filter, 每个 filter ?redis 取符合的 Player.

profile 用到以下字段Q?br />
* "properties.playerPool"
  jsonԌ是一些过滤条Ӟ?#8220;mmr: 100-999”
* "properties.roster"
  json? 是多个队伍大,?“red: 4”

CZ见:`examples\backendclient\profiles\testprofile.json`

### 单匹配过E?/h3>
simple mmf 的匹配过E如下:

1. ?redis 查询 profileQ获取过滤条件和各队伍大?br />1. 每个qo条g?redis 查询Q所有结果的交集为可选成?br />1. 去除 ignoreList, xq?800s 内已匚w成功的成员,?proposal ?deindexed ZSET 列表?br />1. 如果可选成员个数太,?insufficient_players q?br />1. 分配各个队伍成员
1. ?redis 记录l果

### l果


profile 中添?rosterQ即各阵营成员名单,存入 prososalKey.
保存不分队伍的成员名单?br />然后?"proposalq" d prososalKey

### l节


poolRosters ?(pool? filter attribute) 为键Qgؓ Player ID 列表.
保存?redis 查询的符合条件的 Player ID.

overlaps ?pool 名ؓ键,保存W合该pool中所有filter?Player ID 列表Q去?ignore list.

rosters ?profile 中的 "properties.rosters" 字段。不知何用?
遍历 rosters, 为每个阵营的每个player扑ֈ对应pool的PlayerID, 保存?mo.Rosters.
其中 profileRosters 好像没用?br />


金庆 2019-01-31 10:21 发表评论
]]>
试用 go mod - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/12/26/216141.html金庆金庆Wed, 26 Dec 2018 02:07:00 GMT//www.pppqb.icu/jinq0123/archive/2018/12/26/216141.html//www.pppqb.icu/jinq0123/comments/216141.html//www.pppqb.icu/jinq0123/archive/2018/12/26/216141.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/216141.html//www.pppqb.icu/jinq0123/services/trackbacks/216141.html试用 go mod
(金庆的专?2018.12)

Go 1.11 支持 module.

代码不需要在 GOPATH/src 目录下?br />
先初始化模块Q生?`go.mod`

E:\temp
λ mkdir -p testmod\hello

E:\temp
λ cd testmod\hello\

E:\temp\testmod\hello
λ go mod init github.com/jinq0123/hello
go: creating new go.mod: module github.com/jinq0123/hello


创徏 `hello.go`

package main

import (
    "fmt"
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}


构徏时报 `golang.org/x/text` q不上:

E:\temp\testmod\hello
λ go build
go: golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c: unrecog
nized import path "golang.org/x/text" (https fetch: Get https://g
olang.org/x/text?go-get=1: dial tcp 216.239.37.1:443: connectex:
A socket operation was attempted to an unreachable network.)
go: error loading module requirements


`go.mod` d

replace golang.org/x/text => github.com/golang/text v0.3.0


然后构徏成功了Q?br />
E:\temp\testmod\hello
λ go build
go: finding github.com/golang/text v0.3.0
go: downloading rsc.io/sampler v1.3.0
go: downloading github.com/golang/text v0.3.0

E:\temp\testmod\hello
λ hello.exe
Hello, world.


如果不加版本P则会报错Q?br />
go.mod:9: replacement module without version must be directory path (rooted or starting with ./ or ../)


Go 1.11.1 replace q有问题Q仍会试图连接原地址。目前版?1.11.4 可以用?br />
参考:
https://github.com/golang/go/wiki/Modules


金庆 2018-12-26 10:07 发表评论
]]>
grpc加TLS加密和o牌认?/title><link>//www.pppqb.icu/jinq0123/archive/2018/11/26/216081.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 26 Nov 2018 02:39:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/11/26/216081.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/216081.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/11/26/216081.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/216081.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/216081.html</trackback:ping><description><![CDATA[<div class="dpun"><h1 class="dpun">grpc加TLS加密和o牌认?/h1><br />(金庆的专?2018.11)<br /><br />?golang 创徏 grpc 服务Q开?TLS 加密Qƈ采用令牌认证?br />然后?C++ ?golang 分别创徏客户端连接服务器?br /><br />参考:<br />https://segmentfault.com/a/1190000007933303<br /><br /><h2 class="dpun">服务?/h2><br /><span style="color: #800000; font-family: Courier;">import (</span><br /><span style="color: #800000; font-family: Courier;">    ...</span><br /><span style="color: #800000; font-family: Courier;">    grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"</span><br /><span style="color: #800000; font-family: Courier;">    "google.golang.org/grpc"</span><br /><span style="color: #800000; font-family: Courier;">    "google.golang.org/grpc/credentials"</span><br /><span style="color: #800000; font-family: Courier;">)</span><br /><br /><span style="color: #800000; font-family: Courier;">func main() {</span><br /><span style="color: #800000; font-family: Courier;">    listen, err := net.Listen("tcp", ":12345")</span><br /><span style="color: #800000; font-family: Courier;">    if err != nil {</span><br /><span style="color: #800000; font-family: Courier;">        grpclog.Fatalf("failed to listen: %v", err)</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br />    <br /><span style="color: #800000; font-family: Courier;">    // TLS认证</span><br /><span style="color: #800000; font-family: Courier;">    creds, err := credentials.NewServerTLSFromFile("keys/server.crt", "keys/server.key")</span><br /><span style="color: #800000; font-family: Courier;">    if err != nil {</span><br /><span style="color: #800000; font-family: Courier;">        grpclog.Fatalf("Failed to generate credentials %v", err)</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br />    <br /><span style="color: #800000; font-family: Courier;">    // 实例化grpc Server, q开启TLS认证</span><br /><span style="color: #800000; font-family: Courier;">    s := grpc.NewServer(grpc.Creds(creds),</span><br /><span style="color: #800000; font-family: Courier;">        grpc_auth.UnaryServerInterceptor(auth.Authenticate),</span><br /><span style="color: #800000; font-family: Courier;">        grpc_auth.StreamServerInterceptor(auth.Authenticate))</span><br />    <br /><span style="color: #800000; font-family: Courier;">    // 注册HelloService</span><br /><span style="color: #800000; font-family: Courier;">    pb.RegisterHelloServer(s, HelloService)</span><br /><span style="color: #800000; font-family: Courier;">    grpclog.Println("Listen on " + Address + " with TLS")</span><br /><span style="color: #800000; font-family: Courier;">    s.Serve(listen)</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />其中 server.key 是私钥,server.crt 是自{֐证书Q如下生成:<br /><br /><span style="color: #0000ff;">$ openssl genrsa -out server.key 2048</span><br /><span style="color: #0000ff;">$ openssl req -new -x509 -sha256 -key server.key \</span><br /><span style="color: #0000ff;"> -out server.crt -days 36500 \</span><br /><span style="color: #0000ff;"> -subj /C=CN/ST=Shanghai/L=Songjiang/O=ztgame/OU=tech/CN=mydomain.ztgame.com/emailAddress=myname@ztgame.com</span><br /><br />查看证书文g<br /><span style="color: #0000ff;">$ openssl x509 -in server.crt -noout -text</span><br /><br /><br />`auth.Authenticate` 如下Q作?interceptor, Ҏ个请求进行o牌验证?br /><br /><span style="color: #800000; font-family: Courier;">package auth</span><br /><br /><span style="color: #800000; font-family: Courier;">import (</span><br /><span style="color: #800000; font-family: Courier;">    "context"</span><br /><span style="color: #800000; font-family: Courier;">    "sync"</span><br /><br /><span style="color: #800000; font-family: Courier;">    "google.golang.org/grpc/codes"</span><br /><span style="color: #800000; font-family: Courier;">    "google.golang.org/grpc/metadata"</span><br /><span style="color: #800000; font-family: Courier;">    "google.golang.org/grpc/status"</span><br /><span style="color: #800000; font-family: Courier;">)</span><br /><br /><span style="color: #800000; font-family: Courier;">// from token.yaml file</span><br /><span style="color: #800000; font-family: Courier;">var tokenToAppName = &sync.Map{}</span><br /><br /><span style="color: #800000; font-family: Courier;">func init() {</span><br /><span style="color: #800000; font-family: Courier;">    tokenToAppName.Store("test", "test")</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">// XXX load tokenToAppName from file</span><br /><br /><span style="color: #800000; font-family: Courier;">// Authenticate checks that a token exists and is valid.</span><br /><span style="color: #800000; font-family: Courier;">// It removes the token from the context and</span><br /><span style="color: #800000; font-family: Courier;">//  stores the app name of the token in the returned context</span><br /><span style="color: #800000; font-family: Courier;">func Authenticate(ctx context.Context) (context.Context, error) {</span><br /><span style="color: #800000; font-family: Courier;">    token, err := extractHeader(ctx, "authorization-token")</span><br /><span style="color: #800000; font-family: Courier;">    if err != nil {</span><br /><span style="color: #800000; font-family: Courier;">        return ctx, err</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br /><span style="color: #800000; font-family: Courier;">    // Remove token from headers from here on</span><br /><span style="color: #800000; font-family: Courier;">    ctx = purgeHeader(ctx, "authorization-token")</span><br /><br /><span style="color: #800000; font-family: Courier;">    valAppName, ok := tokenToAppName.Load(token)</span><br /><span style="color: #800000; font-family: Courier;">    if !ok {</span><br /><span style="color: #800000; font-family: Courier;">        return ctx, status.Errorf(codes.Unauthenticated, "no app for token '%s'", token)</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br /><span style="color: #800000; font-family: Courier;">    appName := valAppName.(string)</span><br /><span style="color: #800000; font-family: Courier;">    return context.WithValue(ctx, keyAppName{}, appName), nil</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">func extractHeader(ctx context.Context, header string) (string, error) {</span><br /><span style="color: #800000; font-family: Courier;">    md, ok := metadata.FromIncomingContext(ctx)</span><br /><span style="color: #800000; font-family: Courier;">    if !ok {</span><br /><span style="color: #800000; font-family: Courier;">        return "", status.Error(codes.Unauthenticated, "no headers in request")</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br /><br /><span style="color: #800000; font-family: Courier;">    authHeaders, ok := md[header]</span><br /><span style="color: #800000; font-family: Courier;">    if !ok {</span><br /><span style="color: #800000; font-family: Courier;">        return "", status.Error(codes.Unauthenticated, "no header in request")</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br /><br /><span style="color: #800000; font-family: Courier;">    if len(authHeaders) != 1 {</span><br /><span style="color: #800000; font-family: Courier;">        return "", status.Error(codes.Unauthenticated, "more than 1 header in request")</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br /><br /><span style="color: #800000; font-family: Courier;">    return authHeaders[0], nil</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">func purgeHeader(ctx context.Context, header string) context.Context {</span><br /><span style="color: #800000; font-family: Courier;">    md, _ := metadata.FromIncomingContext(ctx)</span><br /><span style="color: #800000; font-family: Courier;">    mdCopy := md.Copy()</span><br /><span style="color: #800000; font-family: Courier;">    mdCopy[header] = nil</span><br /><span style="color: #800000; font-family: Courier;">    return metadata.NewIncomingContext(ctx, mdCopy)</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">type keyAppName struct{}</span><br /><br /><span style="color: #800000; font-family: Courier;">// GetAppName can be used to extract app name stored in a context.</span><br /><span style="color: #800000; font-family: Courier;">func GetAppName(ctx context.Context) string {</span><br /><span style="color: #800000; font-family: Courier;">    // Authenticate()之后必然存在app name</span><br /><span style="color: #800000; font-family: Courier;">    return ctx.Value(keyAppName{}).(string)</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />`tokenToAppName` 是一个map, 合法的令牌映射为应用名?br />每个应用Q即用户Q分配一个o牌,Ҏ令牌可查到该用户是否合法Q以及用L其他信息?br />q里只需要应用名?br /><br />每个h调?`Authenticate()`, 该方法将?http 头获取请求的令牌Q查扑֯应的应用名,<br />ctx 中将删除令牌Q替换成应用名?br /><br />`GetAppName()`从 ctx 中获取应用名?br /><br />服务Ҏ实现如下Q?br /><br /><span style="color: #800000; font-family: Courier;">func (s MailServer) Get(ctx context.Context, r *pb.GetRequest) (*pb.GetResponse, error) {</span><br /><span style="color: #800000; font-family: Courier;">    app := auth.GetAppName(ctx)</span><br /><span style="color: #800000; font-family: Courier;">    body, err := db.NewGetter(app).GetMailBody(r.MailIndex)</span><br /><span style="color: #800000; font-family: Courier;">    return &pb.GetResponse{</span><br /><span style="color: #800000; font-family: Courier;">        Result: getResult(err),</span><br /><span style="color: #800000; font-family: Courier;">        Body:   body,</span><br /><span style="color: #800000; font-family: Courier;">    }, nil</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />先获取应用名Q然后根据应用名获取相应的数据返回?br /><br /><h2 class="dpun">客户?/h2><br /><h3>golang</h3><br /><span style="color: #800000; font-family: Courier;">    // Create the client TLS credentials</span><br /><span style="color: #800000; font-family: Courier;">    creds, err := credentials.NewClientTLSFromFile("key/server.crt", "mydomain.ztgame.com")</span><br /><span style="color: #800000; font-family: Courier;">    if err != nil {</span><br /><span style="color: #800000; font-family: Courier;">        panic(fmt.Errorf("could not load tls cert: %s", err))</span><br /><span style="color: #800000; font-family: Courier;">    }</span><br /><br /><span style="color: #800000; font-family: Courier;">    // We don't need to error here, as this creates a pool and connections</span><br /><span style="color: #800000; font-family: Courier;">    // will happen later</span><br /><span style="color: #800000; font-family: Courier;">    conn, _ := grpc.Dial(</span><br /><span style="color: #800000; font-family: Courier;">        serviceURL,</span><br /><span style="color: #800000; font-family: Courier;">        grpc.WithTransportCredentials(creds),</span><br /><span style="color: #800000; font-family: Courier;">        grpc.WithPerRPCCredentials(auth.TokenAuth{</span><br /><span style="color: #800000; font-family: Courier;">            Token: "test",</span><br /><span style="color: #800000; font-family: Courier;">        }))</span><br /><br /><span style="color: #800000; font-family: Courier;">    cli := pb.NewMailClient(conn)</span><br /><br />客户端只需?server.crt, 其中包含服务器的公钥?br />NewClientTLSFromFile() 的第2个参数是个域名,?server.crt 中的域名?br />目前试阶段q没有正式域名设|,所以输入一个指定域名用于验?server.crt 中的域名?br />生环境q行Ӟ应该不需要这个域名,可以直接查询 DNS q行验证?br /><br />Dial() 输入一?WithPerRPCCredentials 用于令牌验证?br /><br />auth.TokenAuth 需要实?PerRPCCredentials 接口Q?br /><br /><span style="color: #800000; font-family: Courier;">package auth</span><br /><br /><span style="color: #800000; font-family: Courier;">import (</span><br /><span style="color: #800000; font-family: Courier;">    "context"</span><br /><span style="color: #800000; font-family: Courier;">)</span><br /><br /><span style="color: #800000; font-family: Courier;">type TokenAuth struct {</span><br /><span style="color: #800000; font-family: Courier;">    Token string</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">func (t TokenAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) {</span><br /><span style="color: #800000; font-family: Courier;">    return map[string]string{</span><br /><span style="color: #800000; font-family: Courier;">        "authorization-token": t.Token,</span><br /><span style="color: #800000; font-family: Courier;">    }, nil</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">func (TokenAuth) RequireTransportSecurity() bool {</span><br /><span style="color: #800000; font-family: Courier;">    return true</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />"authorization-token" 是客L和服务器U定好的http认证头字W串?br /><br /><h3>C++</h3><br />C++ 端的客户端代码比golang的稍复杂Q因?grpc C++ 库没?grpc-go 成熟?br /><br />代码参照 grpc CZ greeter_async_client2.cc:<br /><br /><span style="color: #800000; font-family: Courier;">int main(int argc, char** argv) {</span><br /><span style="color: #800000; font-family: Courier;">    grpc::SslCredentialsOptions ssl_options;</span><br /><span style="color: #800000; font-family: Courier;">    ssl_options.pem_root_certs = SERVER_CRT;</span><br /><span style="color: #800000; font-family: Courier;">    // Create a default SSL ChannelCredentials object.</span><br /><span style="color: #800000; font-family: Courier;">    auto channel_creds = grpc::SslCredentials(ssl_options);</span><br /><span style="color: #800000; font-family: Courier;">    grpc::ChannelArguments cargs;</span><br /><span style="color: #800000; font-family: Courier;">    cargs.SetSslTargetNameOverride("gamemail.ztgame.com");  // 如果加了 DNS ׃用这个了</span><br /><br /><span style="color: #800000; font-family: Courier;">    auto call_creds = grpc::MetadataCredentialsFromPlugin(</span><br /><span style="color: #800000; font-family: Courier;">        std::unique_ptr<grpc::MetadataCredentialsPlugin>(new TokenAuthenticator(TOKEN)));</span><br /><br /><span style="color: #800000; font-family: Courier;">    auto compsited_creds = grpc::CompositeChannelCredentials(channel_creds, call_creds);</span><br /><br /><span style="color: #800000; font-family: Courier;">    // Create a channel using the credentials created in the previous step.</span><br /><span style="color: #800000; font-family: Courier;">    auto channel = grpc::CreateCustomChannel("1.2.3.4:8000", compsited_creds, cargs);</span><br /><br /><span style="color: #800000; font-family: Courier;">    // Instantiate the client.</span><br /><span style="color: #800000; font-family: Courier;">    MailClient tester(channel);</span><br /><span style="color: #800000; font-family: Courier;">    ...</span><br /><br /><span style="color: #800000; font-family: Courier;">    return 0;</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />因ؓ C++ 没有提供从文件读?server.crt 的接口,所以在此直接用了一个常量字W串Q?br /><br /><span style="color: #800000; font-family: Courier;">    ssl_options.pem_root_certs = SERVER_CRT;</span><br /><br />SERVER_CRT 定义如下Q?br /><br /><span style="color: #800000; font-family: Courier;">// server.crt 的内?/span><br /><span style="color: #800000; font-family: Courier;">const char SERVER_CRT[] = R"(</span><br /><span style="color: #800000; font-family: Courier;">-----BEGIN CERTIFICATE-----</span><br /><span style="color: #800000; font-family: Courier;">TjERMA8GA1UECAwIU2hhbmdoYWkxEjAQBgNVBAcMCVNvbmdqaWFuZzEPMA0GA1UE</span><br /><span style="color: #800000; font-family: Courier;">...</span><br /><span style="color: #800000; font-family: Courier;">E6v50RCQgtWGmna+oy1I2UTVABdjBFnyKPEuz106mBfOhT6cg80hBHVgrV7sLHq8</span><br /><span style="color: #800000; font-family: Courier;">76QolJm8yzZPL1qpiO4dKHHsCP6R</span><br /><span style="color: #800000; font-family: Courier;">-----END CERTIFICATE-----</span><br /><span style="color: #800000; font-family: Courier;">)";</span><br /><br />TokenAuthenticator 定义如下Q是个自定义认证插gQ?br /><br /><span style="color: #800000; font-family: Courier;">// TokenAuthenticator 用来支持令牌认证</span><br /><span style="color: #800000; font-family: Courier;">// https://grpc.io/docs/guides/auth.html</span><br /><span style="color: #800000; font-family: Courier;">class TokenAuthenticator : public grpc::MetadataCredentialsPlugin {</span><br /><span style="color: #800000; font-family: Courier;">public:</span><br /><span style="color: #800000; font-family: Courier;">  TokenAuthenticator(const std::string& token) : token_(token) {}</span><br /><br /><span style="color: #800000; font-family: Courier;">  grpc::Status GetMetadata(</span><br /><span style="color: #800000; font-family: Courier;">      grpc::string_ref service_url, grpc::string_ref method_name,</span><br /><span style="color: #800000; font-family: Courier;">      const grpc::AuthContext& channel_auth_context,</span><br /><span style="color: #800000; font-family: Courier;">      std::multimap<grpc::string, grpc::string>* metadata) override {</span><br /><span style="color: #800000; font-family: Courier;">    metadata->insert(std::make_pair("authorization-token", token_));</span><br /><span style="color: #800000; font-family: Courier;">    return grpc::Status::OK;</span><br /><span style="color: #800000; font-family: Courier;">  }</span><br /><br /><span style="color: #800000; font-family: Courier;">private:</span><br /><span style="color: #800000; font-family: Courier;">  std::string token_;</span><br /><span style="color: #800000; font-family: Courier;">};</span><br /> </div><img src ="//www.pppqb.icu/jinq0123/aggbug/216081.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-11-26 10:39 <a href="//www.pppqb.icu/jinq0123/archive/2018/11/26/216081.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vs2017 linux ~译输出Ҏ vs 格式 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/11/21/216073.html金庆金庆Wed, 21 Nov 2018 02:57:00 GMT//www.pppqb.icu/jinq0123/archive/2018/11/21/216073.html//www.pppqb.icu/jinq0123/comments/216073.html//www.pppqb.icu/jinq0123/archive/2018/11/21/216073.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/216073.html//www.pppqb.icu/jinq0123/services/trackbacks/216073.htmlvs2017 linux ~译输出Ҏ vs 格式
(金庆的专?2018.11)
 1 #!/usr/bin/python 
 2 # -*- coding: utf-8 -*-  
 3 
 4 '''
 5 gcc2vs.py
 6 
 7 功能Q?br /> 8 剪切板中gcc的编译输出格式{成vs格式Q用于vs跌{到错误行?br /> 9 vs2017 linux ~译输出?nbsp;gcc 格式Q无法点击蟩转,如:
10 /var/tmp/src/dbe/Linux-Debug/Src/Team.cpp:16:1: 错误Q?#8216;x’不是一个类型名
11 {为vs格式, ?br />12 /var/tmp/src/dbe/Linux-Debug/Src/Team.cpp(16):1: 错误Q?#8216;x’不是一个类型名
13 
14 如何使用Q?br />15 
16 首先d?nbsp;python, q安?nbsp;pyperclip
17 pip install pyperclip
18 
19 假设本文件ؓ d:/tools/gcc2vs.py,
20 vs讄外部工具Q工?>外部工具->d
21   标题Qgcc2vs(&V)
22   命oQpython.exe
23   参数Qd:/tools/gcc2vs.py
24   选中"使用输出H口"
25 
26 参考:VS2010手动d外部工具和快捷键  
27 https://www.cnblogs.com/ChinaHook/p/4698733.html
28 
29 当Linux构徏输出后,点击输出H口Qctrl-A 选择全部Qctrl-C 复制输出到剪切板Q?br />30 然后 alt-T,V q行d的外部工?nbsp;gcc2vs(&V), 更改输出格式Q然后就可以点击错误跌{了?br />31 '''
32 
33 import re
34 import pyperclip
35 
36 # 待替换的格式
37 pattern = re.compile(r'/var/tmp/src/..-.-.-.-/Linux-Debug/(.*):([0-9]*):([0-9]*): ')
38 
39 test_lines_src = '''
40 /var/tmp/src/db71a8ec-90bb-2838-98df-2dd35e71166e/Linux-Debug/003_servers/103_LobbyServer/Src/Team.cpp:16:1: 错误Q?#8216;x’不是一个类型名
41 生成p|?br />42 '''
43 test_lines_dst = '''
44 003_servers/103_LobbyServer/Src/Team.cpp(16):1: 错误Q?#8216;x’不是一个类型名
45 生成p|?br />46 '''
47 assert test_lines_dst == re.sub(pattern, r'\1(\2):\3: ', test_lines_src)
48 
49 # 剪切板中的gcc格式输出
50 src = pyperclip.paste()
51 # 转成vs格式
52 dst = re.sub(pattern, r'\1(\2):\3: ', src)
53 print(dst)
54 


金庆 2018-11-21 10:57 发表评论
]]>
解决vs2017无法安装问题 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/11/12/216052.html金庆金庆Mon, 12 Nov 2018 02:19:00 GMT//www.pppqb.icu/jinq0123/archive/2018/11/12/216052.html//www.pppqb.icu/jinq0123/comments/216052.html//www.pppqb.icu/jinq0123/archive/2018/11/12/216052.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/216052.html//www.pppqb.icu/jinq0123/services/trackbacks/216052.html解决vs2017无法安装问题

(金庆的专?2018.11)

从官|下载了 vs_community__1600125377.1541561546.exeQ但是运行安装时无法出现产品选择界面?br />
查看 Temp 目录下的日志Q没有发现错误?br />
搜烦一下,发现有大量的同类错误Q?br />
* VS : How to fix stuck Visual Studio Community installation problem
    https://www.howtosolutions.net/2015/08/solving-installation-is-stuck-problem-in-visual-studio-community-edition/
* Resolving Installation Issues with Visual Studio 2017
    //rion.io/2017/02/17/resolving-installation-issues-with-visual-studio-2017/
* Unable to start vs_installer.exe to install VS2017 Community
    https://social.msdn.microsoft.com/Forums/vstudio/en-US/fc8f5a04-8687-48dd-987e-1cfac67566a1/unable-to-start-vsinstallerexe-to-install-vs2017-community?forum=vssetup
* VS 2017 Installer quits before starting
    https://developercommunity.visualstudio.com/content/problem/8993/vs-2017-installer-quits-before-starting.html
* VS2017无法q入安装界面问题的解x?- 厚积薄发Q持之以?- CSDN博客
    https://blog.csdn.net/qq951127336/article/details/71036868
* VS2017安装时自动退出_yanggy_新浪博客
    //blog.sina.com.cn/s/blog_702b606a0102y6n3.html

但是都没有用?br />
从以上方案中了解刎ͼ`C:\Program Files (x86)\Microsoft Visual Studio\Installer`可能存在坏文Ӟ所以无法安装?br />但是清理之后重新下蝲Q仍然是同样情况?br />
试着q行了其中的 vs_installer.exeQ弹出界面说有兼Ҏ错误,可以选择修复?br />修复之后Qvs_installer.exe 出C品选择界面了?br />
然后再运?vs_community__1600125377.1541561546.exeQ就可以出现产品选择界面了?br />
问题可能是这?Installer 安装不对Q可能是选择了错误的版本Q删除后重新下蝲q是一Pq好可以手动修复一下?br />
现在正在安装 vs2017.


金庆 2018-11-12 10:19 发表评论
]]>
gotest 是有~存?/title><link>//www.pppqb.icu/jinq0123/archive/2018/10/29/216026.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 29 Oct 2018 10:47:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/10/29/216026.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/216026.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/10/29/216026.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/216026.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/216026.html</trackback:ping><description><![CDATA[<div class="dpun">gotest 是有~存?br /><br />(金庆的专?2018.10)<br /><br />?gotest q行一个测试,往 mongodb 中插入一条,发现有时灵,有时不灵?br /><br />因ؓ错误地怀?mgo 用错了,耗费了不时间?br />最l发现是因ؓ gotest 是有~存的,输出的是上次q行的结果,但是q没有实际运行代码?br /><br />q行有效是因Z码刚改过Q测试时会实际运行?br /><br />最l也是无意间发现的。给 mgo 开启了调试日志Q然后比?ơ运行,发现输出是一LQ?br />只有一行不同:<br /><br /><span style="color: #0000ff;">ok      mail-server/server      0.519s</span><br /><span style="color: #0000ff;">ok      mail-server/server      (cached)</span><br /><br />明确昄了第2ơ是~存。前面运行了几十ơ都忽略?cached q个输出?br /><br />Z止~存Q可加上 -count=1 参数Q?br /><span style="color: #800000;">go test -count=1</span><br /><br /></div><img src ="//www.pppqb.icu/jinq0123/aggbug/216026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-10-29 18:47 <a href="//www.pppqb.icu/jinq0123/archive/2018/10/29/216026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>open-match的redis数据 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/09/28/215964.html金庆金庆Fri, 28 Sep 2018 06:01:00 GMT//www.pppqb.icu/jinq0123/archive/2018/09/28/215964.html//www.pppqb.icu/jinq0123/comments/215964.html//www.pppqb.icu/jinq0123/archive/2018/09/28/215964.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215964.html//www.pppqb.icu/jinq0123/services/trackbacks/215964.html

open-match的redis数据


(金庆的专?2018.9)

open-match 是Google的开源游戏匹配服框架?br />
https://github.com/GoogleCloudPlatform/open-match

匚w中所用到的玩家数据会保存?redis 中。查?br />`open-match\internal\statestorage\redis\playerq\playerq.go`
可以了解redis保存的数据?br />
redis中有以下键倹{?br />

playerID


玩家ID形如Q`bfd09c94d646493f834a4abe83a5a68c`, cd?hash. 有以下字D:

playerID.properties


保存玩家数据的json丌Ӏ如Q?br />
{
    "char.paladin": 1538102377,
    "map.eastworld": 1538102377,
    "mmr.rating": 1740,
    "mode.ctf": 1538102377,
    "timestamp.enter": 1538102377
}


玩家数据的每值都要求为整?

indices


set cdQ保存所有玩家数据键。如Q?br />
127.0.0.1:6379> smembers indices
1) "timestamp.enter"
2) "map.eastworld"
3) "mmr.rating"
4) "mode.ctf"
5) "char.paladin"

好像没用到?br />

玩家数据?/h2>
?`timestamp.enter`, cd?zset.
每个玩家数据键都建立了一个排序集Q按该玩家数据值排序,成员?playerID?br />
例如Q?br />
127.0.0.1:6379> zrange mmr.rating 1 3 WITHSCORES
1) "ef3736ef2f7941f1a159f279703d5f58"
2) "746"
3) "17ca3bf3a2134c2c90cbe48ebc29f9cb"
4) "891"
5) "b6450b311f3f413595e824897015c462"
6) "891"


金庆 2018-09-28 14:01 发表评论
]]>docker build 讄代理 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/09/26/215949.html金庆金庆Wed, 26 Sep 2018 09:37:00 GMT//www.pppqb.icu/jinq0123/archive/2018/09/26/215949.html//www.pppqb.icu/jinq0123/comments/215949.html//www.pppqb.icu/jinq0123/archive/2018/09/26/215949.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215949.html//www.pppqb.icu/jinq0123/services/trackbacks/215949.htmldocker build 讄代理

(金庆的专?2018.9)

Dockerfile.frontendapi 中有 `RUN go get`, 需要设|代理?br />
docker build . -f Dockerfile.frontendapi \
    -t registry.cn-shanghai.aliyuncs.com/jinq0123/openmatch-frontendapi:dev \
    --network host \
    --build-arg HTTP_PROXY=//127.0.0.1:1080 \
    --build-arg HTTPS_PROXY=//127.0.0.1:1080

因ؓ docker build 会在一个容器内执行Q所以须指定 network ?host, 使之可以q接本机的代理?br />
参考:
https://stackoverflow.com/questions/22179301/how-do-you-run-apt-get-in-a-dockerfile-behind-a-proxy

[root@pppdc9prda2y java]# docker build
  --build-arg https_proxy=$HTTP_PROXY --build-arg http_proxy=$HTTP_PROXY
  --build-arg HTTP_PROXY=$HTTP_PROXY --build-arg HTTPS_PROXY=$HTTP_PROXY
  --build-arg NO_PROXY=$NO_PROXY  --build-arg no_proxy=$NO_PROXY -t java .


金庆 2018-09-26 17:37 发表评论
]]>
K8s获取NodePort - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/09/04/215903.html金庆金庆Tue, 04 Sep 2018 07:17:00 GMT//www.pppqb.icu/jinq0123/archive/2018/09/04/215903.html//www.pppqb.icu/jinq0123/comments/215903.html//www.pppqb.icu/jinq0123/archive/2018/09/04/215903.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215903.html//www.pppqb.icu/jinq0123/services/trackbacks/215903.htmlK8s获取NodePort

(金庆的专?2018.9)

服务用NodePort暴露到外|,为避免端口冲H,不指定NodePort,
 而是让k8s自动选择一个端口?br /> 
$ cat get_node_port.yaml
kind: Service
apiVersion: v1
metadata:
  name: jq-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80

$ kubectl apply -f get_node_port.yaml
service "jq-service" configured
$ kubectl describe svc/jq-service
Name:                     jq-service
Namespace:                default
Labels:                   <none>
Annotations:              kubectl...
Selector:                 app=MyApp
Type:                     NodePort
IP:                       10.104.228.187
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  32115/TCP
Endpoints:                <none>
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>


可以看到k8s分配了NodePort 32115?br />
然后需要获取这个动态的NodePortQ以通知客户端连接该端口?br />
package main

import (
    "context"
    "fmt"
    "log"
    "io/ioutil"

    "github.com/ghodss/yaml"
    "github.com/ericchiang/k8s"
    corev1 "github.com/ericchiang/k8s/apis/core/v1"
)

func main() {
    data, err := ioutil.ReadFile("config")
    if err != nil {
        panic(err)
    }

    // Unmarshal YAML into a Kubernetes config object.
    var config k8s.Config
    if err := yaml.Unmarshal(data, &config); err != nil {
        panic(err)
    }

    client, err := k8s.NewClient(&config)
    // client, err := k8s.NewInClusterClient()
    if err != nil {
        log.Fatal(err)
    }

    var svc corev1.Service
    if err := client.Get(context.Background(), "default", "jq-service", &svc); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d\n", *svc.Spec.Ports[0].NodePort)
}

q行旉要复制config: `cp ~/.kube/config .`


金庆 2018-09-04 15:17 发表评论
]]>
删除隐性的git submodule - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/08/30/215889.html金庆金庆Thu, 30 Aug 2018 02:58:00 GMT//www.pppqb.icu/jinq0123/archive/2018/08/30/215889.html//www.pppqb.icu/jinq0123/comments/215889.html//www.pppqb.icu/jinq0123/archive/2018/08/30/215889.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215889.html//www.pppqb.icu/jinq0123/services/trackbacks/215889.html删除隐性的git submodule

(金庆的专?2018.8)

正常的submodule会在 .gitmodule 文g中,TortoiseGit 会有 Submodule Update 菜单?br />q有一U隐性的 submodule, .gitmodule 文g中看不到它,无法 update.
golang开发中的vendor目录下经怼不小心添加一个带 .git 的目录,变成了一个假的submodule.
?Repo-browser 看这个目录是个submodule链接, clone 出来只有一个空目录?br />
删除q个submodule不能?git delete, 提交时会报错Q?br />
git.exe add -f [...]

fatal: pathspec 'src/vendor/github.com/grpc-ecosystem/grpc-opentracing' did not match any files

git did not exit cleanly (exit code 128)

git delete 父目录也无法提交?br />
但是可以直接删除Q不用git deleteQ? 然后提交qPush. 好像只有q个办法?br />




金庆 2018-08-30 10:58 发表评论
]]>
grpc中的dns负蝲均衡 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/08/29/215886.html金庆金庆Wed, 29 Aug 2018 02:59:00 GMT//www.pppqb.icu/jinq0123/archive/2018/08/29/215886.html//www.pppqb.icu/jinq0123/comments/215886.html//www.pppqb.icu/jinq0123/archive/2018/08/29/215886.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215886.html//www.pppqb.icu/jinq0123/services/trackbacks/215886.htmlgrpc中的dns负蝲均衡

(金庆的专?2018.8)

grpc-go 中如下连接服务器Q请求将在多个IP之间轮{?br />
    conn, err := grpc.Dial(
        "dns:///rng-headless:8081",
        grpc.WithBalancerName(roundrobin.Name),
        grpc.WithInsecure())

标准的目标名应该是这LQ`"dns://authority/endpoint_name"`,
此处 authority 为空Q详见:https://github.com/grpc/grpc/blob/master/doc/naming.md

服务器开3个实例,所有请求在3个实例上轮{Q?br />
[jinqing@host-10-2-3-4 RoundRobin]$ kubectl run -it --rm jinqing-roundrobin --image=jinq0123/roundrobin:4
If you don't see a command prompt, try pressing enter.
2018/08/28 10:18:01 request 7754383576636566559
2018/08/28 10:18:02 request 2543876599219675746
2018/08/28 10:18:03 request 927204261937181213
2018/08/28 10:18:04 request 7754383576636566559
2018/08/28 10:18:05 request 2543876599219675746
2018/08/28 10:18:06 request 927204261937181213
...

服务器返回一个随机数Q不同实例的随机C同。代码是?br />https://github.com/kcollasarundell/balancing-on-k8s 修改的?br />
...
const (
        port = ":8081"
)

type server struct{}

var r int64

func init(){
    rand.Seed(time.Now().UnixNano())
    r = rand.Int63()
}

func (s *server) Rng(context.Context, *rng.Source) (*rng.RN, error) {
        return &rng.RN{RN: r}, nil
}

func main() {
        lis, err := net.Listen("tcp", port)
        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }
        s := grpc.NewServer()
        rng.RegisterRngServer(s, &server{})
        // Register reflection service on gRPC server.
        reflection.Register(s)

        if err := s.Serve(lis); err != nil {
                log.Fatalf("failed to serve: %v", err)
        }
}

先编译,打包成镜像,然后?`balancing-on-k8s\backend\kube.yaml` q行Q?br />kubectl apply -f kube.yaml

`backend\kube.yaml` 创徏了一?ClusterIP 服务和一?Headless 服务Q部|了 3 个服务器实例?br />[jinqing@host-10-2-3-4 RoundRobin]$ kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP             93d
rng-cluster    ClusterIP   10.111.30.205   <none>        8081/TCP            4h
rng-headless   ClusterIP   None            <none>        8081/TCP,8080/TCP   4h

客户端是一个简单的grpc, 定时发送请求,打印q回的随机数?br />`balancing-on-k8s\clientSideBalancer\RoundRobin\main.go`中的地址需要添加端口,
不然grpc会去q接 443 端口而失败?br />
扩容后,到大概3分钟后才看到负蝲转移。羃容后会立即生效?br />kubectl scale --replicas=5 deployment/rng

如果?ClusterIP 服务, 则服务名对应一个ClusterIP;
如果?Headless 服务Q则服务名对应各个Pod的IP:

/ # nslookup rng-headless
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   rng-headless.default.svc.cluster.local
Address: 10.244.3.27
Name:   rng-headless.default.svc.cluster.local
Address: 10.244.0.108
Name:   rng-headless.default.svc.cluster.local
Address: 10.244.2.66

/ # nslookup rng-cluster
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   rng-cluster.default.svc.cluster.local
Address: 10.111.30.205

/ #

如果去除 "dns:///", 仅仅是域名加端口Q?br />
conn, err := grpc.Dial(
        "rng-headless:8081",
        grpc.WithBalancerName(roundrobin.Name),
        ...

则只会请求同一个实例。只有当该实例pod被删除后才会切换到另一个实例?br />使用~容时发C优先删除没有客户端连接的实例?br />?个客Lq接C同服务器实例Q然后羃容ؓ1实例Q就可以看到h切换?br />
如果客户端和服务器数量很大,q个dns负蝲均衡׃合适了Q因为客L会连接每个服务器实例?br />
参考:
Exploring Kubernetes Service Discovery and loadbalancing ( https://kca.id.au/post/k8s_service/ )


金庆 2018-08-29 10:59 发表评论
]]>
手机q行 Unity Grpc - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/08/12/215842.html金庆金庆Sun, 12 Aug 2018 04:24:00 GMT//www.pppqb.icu/jinq0123/archive/2018/08/12/215842.html//www.pppqb.icu/jinq0123/comments/215842.html//www.pppqb.icu/jinq0123/archive/2018/08/12/215842.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215842.html//www.pppqb.icu/jinq0123/services/trackbacks/215842.html手机q行 Unity Grpc

(金庆的专?2018.8)

* 安装 Unit2018, 支持 .NET 4.x
* 创徏一个项目,开?.NET 4.x
    Edit->Project Settings->Player->Other Settings
      ->Configuration->Script Runtime Version->.Net 4.x Equivalent
* ?https://packages.grpc.io/ ?Daily Builds 下蝲最新的
    grpc-protoc_windows_x86-VERSION.zip
    grpc_unity_package.VERSION.zip
* grpc_unity_package.VERSION.zip
    解压?Assets 目录?br />* ?github grpc 复制 examples/protos/helloworld.proto ?Assets/protos/helloworld.proto
* 创徏 Assets/Scripts/Greeter/, q在该目录下q行
    protoc.exe -I../../../protos --csharp_out=. ../../../protos/helloworld.proto --grpc_out=. --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe
    + 需要先?grpc-protoc_windows_x86-VERSION.zip 解压 protoc.exeQgrpc_csharp_plugin.exe
    + 生成 Helloworld.cs HelloworldGrpc.cs
* 客户端代?br />    + 创徏Channelq接服务?br />    channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
    + 创徏客户端ƈ发出h
    var client = new Greeter.GreeterClient(channel);
    HelloReply reply = client.SayHello(new HelloRequest { Name = "Jin Qing" });
* 完整代码见:https://gitee.com/jinq0123/unity-grpc-sample
* 最后打包安装到手机试通过


金庆 2018-08-12 12:24 发表评论
]]>
k8s集群外go客户端示?/title><link>//www.pppqb.icu/jinq0123/archive/2018/07/22/215796.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 22 Jul 2018 03:14:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/07/22/215796.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215796.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/07/22/215796.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215796.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215796.html</trackback:ping><description><![CDATA[<div class="dpun">k8s集群外go客户端示?br /><br />(金庆的专?2018.7)<br /><br />集群内客L需要打包成docker镜像Q上传镜像,然后?kubectl run q行Q?br />q要讄用户角色Q太ȝQ还是用集群外客L试比较方便?br /><br />客户端库使用 ericchiang/k8s, 比官方的 client-go 要简单许多?br /><br />集群内客L使用`k8s.NewInClusterClient()`创徏Q?br />集群外客L使用 `NewClient(config *Config)`, 需要输入配|,<br />配置是?~/.kube/config d的?br />参?https://github.com/ericchiang/k8s/issues/79<br /><br />代码如下Q?br /><br /><span style="font-family: Courier; color: #800000;">package main</span><br /><br /><span style="font-family: Courier; color: #800000;">import (</span><br /><span style="font-family: Courier; color: #800000;">    "context"</span><br /><span style="font-family: Courier; color: #800000;">    "fmt"</span><br /><span style="font-family: Courier; color: #800000;">    "log"</span><br /><span style="font-family: Courier; color: #800000;">    "io/ioutil"</span><br /><br /><span style="font-family: Courier; color: #800000;">    "github.com/ghodss/yaml"</span><br /><span style="font-family: Courier; color: #800000;">    "github.com/ericchiang/k8s"</span><br /><span style="font-family: Courier; color: #800000;">    corev1 "github.com/ericchiang/k8s/apis/core/v1"</span><br /><span style="font-family: Courier; color: #800000;">)</span><br /><br /><span style="font-family: Courier; color: #800000;">func main() {</span><br /><span style="font-family: Courier; color: #800000;">    data, err := ioutil.ReadFile("config")</span><br /><span style="font-family: Courier; color: #800000;">    if err != nil {</span><br /><span style="font-family: Courier; color: #800000;">        panic(err)</span><br /><span style="font-family: Courier; color: #800000;">    }</span><br /><br /><span style="font-family: Courier; color: #800000;">    // Unmarshal YAML into a Kubernetes config object.</span><br /><span style="font-family: Courier; color: #800000;">    var config k8s.Config</span><br /><span style="font-family: Courier; color: #800000;">    if err := yaml.Unmarshal(data, &config); err != nil {</span><br /><span style="font-family: Courier; color: #800000;">        panic(err)</span><br /><span style="font-family: Courier; color: #800000;">    }</span><br /><br /><span style="font-family: Courier; color: #800000;">    client, err := k8s.NewClient(&config)</span><br /><span style="font-family: Courier; color: #800000;">    // client, err := k8s.NewInClusterClient()</span><br /><span style="font-family: Courier; color: #800000;">    if err != nil {</span><br /><span style="font-family: Courier; color: #800000;">        log.Fatal(err)</span><br /><span style="font-family: Courier; color: #800000;">    }</span><br /><br /><span style="font-family: Courier; color: #800000;">    var nodes corev1.NodeList</span><br /><span style="font-family: Courier; color: #800000;">    if err := client.List(context.Background(), "", &nodes); err != nil {</span><br /><span style="font-family: Courier; color: #800000;">        log.Fatal(err)</span><br /><span style="font-family: Courier; color: #800000;">    }</span><br /><span style="font-family: Courier; color: #800000;">    for _, node := range nodes.Items {</span><br /><span style="font-family: Courier; color: #800000;">        fmt.Printf("name=%q schedulable=%t\n", *node.Metadata.Name, !*node.Spec.Unschedulable)</span><br /><span style="font-family: Courier; color: #800000;">    }</span><br /><span style="font-family: Courier; color: #800000;">}</span><br /><br />yaml 库用?ghodss/yamlQ不能用 go-yaml, 不然报错<br />`yaml: unmarshal errors`<br />见:https://github.com/ericchiang/k8s/issues/81<br /><br />复制 .kube/config 到运行目录,q行列出所有节点:<br /><br /><span style="font-family: Courier; color: #0000ff;">[jinqing@host-10-1-2-19 out-cluster]$ cp ~/.kube/config .</span><br /><span style="font-family: Courier; color: #0000ff;">[jinqing@host-10-1-2-19 out-cluster]$ ./out-cluster </span><br /><span style="font-family: Courier; color: #0000ff;">name="host-10-1-2-20" schedulable=true</span><br /><span style="font-family: Courier; color: #0000ff;">name="host-10-1-2-21" schedulable=true</span><br /><span style="font-family: Courier; color: #0000ff;">name="host-10-1-2-22" schedulable=true</span><br /><span style="font-family: Courier; color: #0000ff;">name="host-10-1-2-19" schedulable=true</span></div><div class="dpun"><span style="font-family: Courier; color: #0000ff;"><div class="dpun"><span style="font-family: Courier; color: #0000ff;">name="host-10-1-2-18" schedulable=true</span></div></span></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215796.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-07-22 11:14 <a href="//www.pppqb.icu/jinq0123/archive/2018/07/22/215796.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>kubernetes导出有状态服?/title><link>//www.pppqb.icu/jinq0123/archive/2018/07/14/215783.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 14 Jul 2018 03:43:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/07/14/215783.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215783.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/07/14/215783.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215783.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215783.html</trackback:ping><description><![CDATA[<div class="dpun">kubernetes导出有状态服?br /><br />(金庆的专?2018.7)<br /><br />|游服务器中的房间服务器是有状态服务器Q可以用 kubernetes statefulset 开启多个实例?br /><br />Z让客L能够直连戉K服务器,除了 statefulset 要求?headless 服务Q?br />q须为每个实例创?NodePort cd的服? q且选择Pod和禁止{发?br /><br />下面 bootcamp.yml 先创Z bootcamp headless 服务(clusterIP: None), <br />又创Z bootcamp StatefulSet, 实例个数?2.<br />然后创徏 bootcamp-0,1,2 服务Q分别对?bootcamp-0,1,2 pod.<br /><br />服务个数大于实例个数Q是x试下服务没有对应的实例时的表现?br /><br />|游中的匚w服务器将分配一个房间给客户端,列D bootcamp-0,1,2 pod 所在节点的外网 IP,<br />q同对应服务的端口,发送给客户端,让客L直连?br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ cat bootcamp.yml </span><br /><span style="color: #0000ff; font-family: Courier;">apiVersion: v1</span><br /><span style="color: #0000ff; font-family: Courier;">kind: Service</span><br /><span style="color: #0000ff; font-family: Courier;">metadata:</span><br /><span style="color: #0000ff; font-family: Courier;">  name: bootcamp</span><br /><span style="color: #0000ff; font-family: Courier;">  namespace: jq</span><br /><span style="color: #0000ff; font-family: Courier;">  labels:</span><br /><span style="color: #0000ff; font-family: Courier;">    name: bootcamp</span><br /><span style="color: #0000ff; font-family: Courier;">spec:</span><br /><span style="color: #0000ff; font-family: Courier;">  ports:</span><br /><span style="color: #0000ff; font-family: Courier;">    - port: 8080</span><br /><span style="color: #0000ff; font-family: Courier;">  clusterIP: None  # StatefulSet要求Headless服务</span><br /><span style="color: #0000ff; font-family: Courier;">  selector:</span><br /><span style="color: #0000ff; font-family: Courier;">    app: bootcamp  # 选择 bootcamp 应用</span><br /><br /><span style="color: #0000ff; font-family: Courier;">---</span><br /><span style="color: #0000ff; font-family: Courier;">apiVersion: apps/v1beta1</span><br /><span style="color: #0000ff; font-family: Courier;">kind: StatefulSet</span><br /><span style="color: #0000ff; font-family: Courier;">metadata:</span><br /><span style="color: #0000ff; font-family: Courier;">  name: bootcamp</span><br /><span style="color: #0000ff; font-family: Courier;">  namespace: jq</span><br /><span style="color: #0000ff; font-family: Courier;">spec:</span><br /><span style="color: #0000ff; font-family: Courier;">  serviceName: bootcamp  # 上面?Headless 服务?/span><br /><span style="color: #0000ff; font-family: Courier;">  replicas: 2</span><br /><span style="color: #0000ff; font-family: Courier;">  template:</span><br /><span style="color: #0000ff; font-family: Courier;">    metadata:</span><br /><span style="color: #0000ff; font-family: Courier;">      labels:</span><br /><span style="color: #0000ff; font-family: Courier;">        app: bootcamp  # 应用名,与服务中?selector 对应</span><br /><span style="color: #0000ff; font-family: Courier;">    spec:</span><br /><span style="color: #0000ff; font-family: Courier;">      containers:</span><br /><span style="color: #0000ff; font-family: Courier;">      - name: bootcamp</span><br /><span style="color: #0000ff; font-family: Courier;">        image: docker.io/jocatalin/kubernetes-bootcamp:v1</span><br /><br /><span style="color: #0000ff; font-family: Courier;">---</span><br /><span style="color: #0000ff; font-family: Courier;">kind: Service</span><br /><span style="color: #0000ff; font-family: Courier;">apiVersion: v1</span><br /><span style="color: #0000ff; font-family: Courier;">metadata:</span><br /><span style="color: #0000ff; font-family: Courier;">  name: bootcamp-0</span><br /><span style="color: #0000ff; font-family: Courier;">  namespace: jq</span><br /><span style="color: #0000ff; font-family: Courier;">spec:</span><br /><span style="color: #0000ff; font-family: Courier;">  type: NodePort  # 对外服务</span><br /><span style="color: #0000ff; font-family: Courier;">  externalTrafficPolicy: Local  # 不要转发到其他节?/span><br /><span style="color: #0000ff; font-family: Courier;">  selector:</span><br /><span style="color: #0000ff; font-family: Courier;">    app: bootcamp</span><br /><span style="color: #0000ff; font-family: Courier;">    statefulset.kubernetes.io/pod-name: bootcamp-0  # 选择 pod</span><br /><span style="color: #0000ff; font-family: Courier;">  ports:</span><br /><span style="color: #0000ff; font-family: Courier;">  - protocol: TCP</span><br /><span style="color: #0000ff; font-family: Courier;">    nodePort: 30880  # 对外端口</span><br /><span style="color: #0000ff; font-family: Courier;">    port: 8080</span><br /><span style="color: #0000ff; font-family: Courier;">---</span><br /><span style="color: #0000ff; font-family: Courier;">kind: Service</span><br /><span style="color: #0000ff; font-family: Courier;">apiVersion: v1</span><br /><span style="color: #0000ff; font-family: Courier;">metadata:</span><br /><span style="color: #0000ff; font-family: Courier;">  name: bootcamp-1</span><br /><span style="color: #0000ff; font-family: Courier;">  namespace: jq</span><br /><span style="color: #0000ff; font-family: Courier;">spec:</span><br /><span style="color: #0000ff; font-family: Courier;">  type: NodePort</span><br /><span style="color: #0000ff; font-family: Courier;">  externalTrafficPolicy: Local</span><br /><span style="color: #0000ff; font-family: Courier;">  selector:</span><br /><span style="color: #0000ff; font-family: Courier;">    app: bootcamp</span><br /><span style="color: #0000ff; font-family: Courier;">    statefulset.kubernetes.io/pod-name: bootcamp-1</span><br /><span style="color: #0000ff; font-family: Courier;">  ports:</span><br /><span style="color: #0000ff; font-family: Courier;">  - protocol: TCP</span><br /><span style="color: #0000ff; font-family: Courier;">    nodePort: 30881</span><br /><span style="color: #0000ff; font-family: Courier;">    port: 8080</span><br /><span style="color: #0000ff; font-family: Courier;">---</span><br /><span style="color: #0000ff; font-family: Courier;">kind: Service</span><br /><span style="color: #0000ff; font-family: Courier;">apiVersion: v1</span><br /><span style="color: #0000ff; font-family: Courier;">metadata:</span><br /><span style="color: #0000ff; font-family: Courier;">  name: bootcamp-2</span><br /><span style="color: #0000ff; font-family: Courier;">  namespace: jq</span><br /><span style="color: #0000ff; font-family: Courier;">spec:</span><br /><span style="color: #0000ff; font-family: Courier;">  type: NodePort</span><br /><span style="color: #0000ff; font-family: Courier;">  externalTrafficPolicy: Local</span><br /><span style="color: #0000ff; font-family: Courier;">  selector:</span><br /><span style="color: #0000ff; font-family: Courier;">    app: bootcamp</span><br /><span style="color: #0000ff; font-family: Courier;">    statefulset.kubernetes.io/pod-name: bootcamp-2</span><br /><span style="color: #0000ff; font-family: Courier;">  ports:</span><br /><span style="color: #0000ff; font-family: Courier;">  - protocol: TCP</span><br /><span style="color: #0000ff; font-family: Courier;">    nodePort: 30882</span><br /><span style="color: #0000ff; font-family: Courier;">    port: 8080</span><br /><br />因ؓ statefulset 的每个实例有不同的标{,所以可以ؓ服务选择一个实例?br /><br />利用 externalTrafficPolicy: Local 讄来禁止{发?br />参?service.spec.externalTrafficPolicy 的说明:<br /><br />https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-type-nodeport<br /><br />Setting service.spec.externalTrafficPolicy to the value Local will only proxy requests to local endpoints, never forwarding traffic to other nodes and thereby preserving the original source IP address. If there are no local endpoints, packets sent to the node are dropped, ...<br /><br />因ؓ有可能多个Pod开在同一节点上,所以对外端口设成了不同?30880-30882?br />如果限制每个节点只开一个实例,则对外端口可以设成同一个?br /><br />创徏服务Q?br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ kubectl apply -f bootcamp.yml </span><br /><span style="color: #0000ff; font-family: Courier;">service "bootcamp" created</span><br /><span style="color: #0000ff; font-family: Courier;">statefulset.apps "bootcamp" created</span><br /><span style="color: #0000ff; font-family: Courier;">service "bootcamp-0" created</span><br /><span style="color: #0000ff; font-family: Courier;">service "bootcamp-1" created</span><br /><span style="color: #0000ff; font-family: Courier;">service "bootcamp-2" created</span><br /><br />服务如下Q?br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ kubectl get service -n jq</span><br /><span style="color: #0000ff; font-family: Courier;">NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp     ClusterIP   None             <none>        8080/TCP         3m</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-0   NodePort    10.96.128.137    <none>        8080:30880/TCP   3m</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-1   NodePort    10.109.2.56      <none>        8080:30881/TCP   3m</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-2   NodePort    10.102.181.193   <none>        8080:30882/TCP   3m</span><br /><br />2个实例:<br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ kubectl get pod -n jq -o wide</span><br /><span style="color: #0000ff; font-family: Courier;">NAME         READY     STATUS    RESTARTS   AGE       IP            NODE</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-0   1/1       Running   0          4m        10.244.0.42   host-10-240-79-10</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-1   1/1       Running   0          4m        10.244.1.63   host-10-240-79-11</span><br /><br />讉K服务必须指定节点Q不会自动{发:<br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.10:30880</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-0 | v=1</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.10:30881</span><br /><span style="color: #0000ff; font-family: Courier;">curl: (7) Failed connect to 10.240.79.10:30881; Connection timed out</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30880</span><br /><span style="color: #0000ff; font-family: Courier;">curl: (7) Failed connect to 10.240.79.11:30880; Connection timed out</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1</span><br /><br />没有负蝲均衡Q?0881端口L讉K bootcamp-1Q?br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30881</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-1 | v=1</span><br /><br />也可以从外网讉K.<br /><br />30882 端口无法q接Q?br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.11:30882</span><br /><span style="color: #0000ff; font-family: Courier;">curl: (7) Failed connect to 10.240.79.11:30882; Connection refused</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.10:30882</span><br /><span style="color: #0000ff; font-family: Courier;">curl: (7) Failed connect to 10.240.79.10:30882; Connection refused</span><br /><br />3个端口都有监听:<br /><br /><span style="color: #0000ff; font-family: Courier;">[root@host-10-240-79-11 tmp]# netstat -ntl | grep 3088</span><br /><span style="color: #0000ff; font-family: Courier;">tcp6       0      0 :::30881                :::*                    LISTEN     </span><br /><span style="color: #0000ff; font-family: Courier;">tcp6       0      0 :::30882                :::*                    LISTEN     </span><br /><span style="color: #0000ff; font-family: Courier;">tcp6       0      0 :::30880                :::*                    LISTEN     </span><br /><br />iptables-save 输出如下, 其中 10.244是Pod的网Dc?br /><br />没有实例q行的节点上Q会丢弃hQ?br /><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-MARK-MASQ</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-XLB-LJXDQ4W47M42IZBH</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-MARK-MASQ</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-XLB-U5NEOQT6R5WSBVOH</span><br /><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-LJXDQ4W47M42IZBH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-LJXDQ4W47M42IZBH</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-LJXDQ4W47M42IZBH -m comment --comment "jq/bootcamp-1: has no local endpoints" -j KUBE-MARK-DROP</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-U5NEOQT6R5WSBVOH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-U5NEOQT6R5WSBVOH</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-U5NEOQT6R5WSBVOH -m comment --comment "jq/bootcamp-0: has no local endpoints" -j KUBE-MARK-DROP</span><br /><br />有实例运行的节点上会转发l?Pod 8080Q?br /><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-MARK-MASQ</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-0:" -m tcp --dport 30880 -j KUBE-XLB-U5NEOQT6R5WSBVOH</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -s 127.0.0.0/8 -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-MARK-MASQ</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-NODEPORTS -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp --dport 30881 -j KUBE-XLB-LJXDQ4W47M42IZBH</span><br /><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-LJXDQ4W47M42IZBH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-LJXDQ4W47M42IZBH</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-LJXDQ4W47M42IZBH -m comment --comment "Balancing rule 0 for jq/bootcamp-1:" -j KUBE-SEP-LJQA4WUIKJUQ5ALU</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-U5NEOQT6R5WSBVOH -s 10.244.0.0/16 -m comment --comment "Redirect pods trying to reach external loadbalancer VIP to clusterIP" -j KUBE-SVC-U5NEOQT6R5WSBVOH</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-XLB-U5NEOQT6R5WSBVOH -m comment --comment "jq/bootcamp-0: has no local endpoints" -j KUBE-MARK-DROP</span><br /><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-SEP-LJQA4WUIKJUQ5ALU -s 10.244.1.63/32 -m comment --comment "jq/bootcamp-1:" -j KUBE-MARK-MASQ</span><br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-SEP-LJQA4WUIKJUQ5ALU -p tcp -m comment --comment "jq/bootcamp-1:" -m tcp -j DNAT --to-destination 10.244.1.63:8080</span><br /><br />30882 端口无法q接<br /><span style="color: #0000ff; font-family: Courier;">-A KUBE-EXTERNAL-SERVICES -p tcp -m comment --comment "jq/bootcamp-2: has no endpoints" -m addrtype --dst-type LOCAL -m tcp --dport 30882 -j REJECT --reject-with icmp-port-unreachable</span><br /><br />试下扩容:<br /><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ kubectl get statefulset -n jq</span><br /><span style="color: #0000ff; font-family: Courier;">NAME       DESIRED   CURRENT   AGE</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp   2         2         45m</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ kubectl scale --replicas=3 statefulset/bootcamp -n jq</span><br /><span style="color: #0000ff; font-family: Courier;">statefulset.apps "bootcamp" scaled</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ kubectl get statefulset -n jq</span><br /><span style="color: #0000ff; font-family: Courier;">NAME       DESIRED   CURRENT   AGE</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp   3         3         47m</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ kubectl get pod -n jq -o wide</span><br /><span style="color: #0000ff; font-family: Courier;">NAME         READY     STATUS    RESTARTS   AGE       IP            NODE</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-0   1/1       Running   0          48m       10.244.0.42   host-10-240-79-10</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-1   1/1       Running   0          48m       10.244.1.63   host-10-240-79-11</span><br /><span style="color: #0000ff; font-family: Courier;">bootcamp-2   1/1       Running   0          45s       10.244.2.60   host-10-240-79-12</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-10-240-79-10 statefulset]$ curl 10.240.79.12:30882</span><br /><span style="color: #0000ff; font-family: Courier;">Hello Kubernetes bootcamp! | Running on: bootcamp-2 | v=1</span><br /></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215783.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-07-14 11:43 <a href="//www.pppqb.icu/jinq0123/archive/2018/07/14/215783.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用目录结构表Cgo包依赖关p?/title><link>//www.pppqb.icu/jinq0123/archive/2018/06/25/215743.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 25 Jun 2018 09:16:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/06/25/215743.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215743.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/06/25/215743.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215743.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215743.html</trackback:ping><description><![CDATA[<div class="dpun">用目录结构表Cgo包依赖关p?br /><br />(金庆的专?2018.6)<br /><br />摘自Q?br />https://www.ardanlabs.com/blog/2017/02/package-oriented-design.html<br /><br />If a package wants to import another package at the same level:<br /><br />* Question the current design choices of these packages.<br />* If reasonable, move the package inside the source tree for the package that wants to import it.<br />* Use the source tree to show the dependency relationships.<br /></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-06-25 17:16 <a href="//www.pppqb.icu/jinq0123/archive/2018/06/25/215743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Golang的包?/title><link>//www.pppqb.icu/jinq0123/archive/2018/06/25/215742.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 25 Jun 2018 08:51:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/06/25/215742.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215742.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/06/25/215742.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215742.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215742.html</trackback:ping><description><![CDATA[<div class="dpun">Golang的包?br /><br />(金庆的专?2018.6)<br /><br />摘自Q?br /><br />https://talks.golang.org/2014/organizeio.slide#1<br /><br />The name of a package<br /><br />Keep package names short and meaningful.<br />Don't use underscores, they make package names long.<br /><br />    io/ioutil not io/util<br />    suffixarray not suffix_array<br /><br />Don't overgeneralize. A util package could be anything.<br /><br />The name of a package is part of its type and function names.<br />On its own, type Buffer is ambiguous. But users see:<br /><br />    buf := new(bytes.Buffer)<br /><br />Choose package names carefully.<br /><br />Choose good names for users.<br /></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215742.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-06-25 16:51 <a href="//www.pppqb.icu/jinq0123/archive/2018/06/25/215742.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>etcd+registrator+confd 服务发现 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/06/13/215722.html金庆金庆Wed, 13 Jun 2018 06:27:00 GMT//www.pppqb.icu/jinq0123/archive/2018/06/13/215722.html//www.pppqb.icu/jinq0123/comments/215722.html//www.pppqb.icu/jinq0123/archive/2018/06/13/215722.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215722.html//www.pppqb.icu/jinq0123/services/trackbacks/215722.htmletcd+registrator+confd 服务发现

(金庆的专?2018.6)

因ؓk8s使用 etcd, 所以?etcd 作ؓ服务发现?DB.

registrator 可以?docker 方式q行的服务自动注册到 etcd.

confd d etcd, 生成配置文g?br />
先运行一个etcd用于试Q?br />
docker run -d \
  -p 12379:2379 \
  --name jinqing-etcd \
  quay.io/coreos/etcd \
   /usr/local/bin/etcd \
  --listen-client-urls //0.0.0.0:2379 \
  --advertise-client-urls //0.0.0.0:12379

再运?registrator:

docker run -d --rm \
    --name=jinqing-registrator \
    --net=host \
    --volume=/var/run/docker.sock:/tmp/docker.sock \
    gliderlabs/registrator:latest \
      -ip="192.168.93.183" \
      etcd://127.0.0.1:12379/registrator

好像只能使用本机?etcd. 一般需要用-ip参数指定本机IP。注册到 registrator 目录?br />
?etcdkeeper 可以查看自动注册的服务。registrator 不支?etcd v3.

然后配置 confd

mkdir -p /etc/confd/{conf.d,templates}

/etc/confd/conf.d/myconfig.toml

[template]
src = "services.toml.tmpl"
dest = "/tmp/services.toml"
keys = [
    "/registrator",
]

/etc/confd/templates/services.toml.tmpl

[config]
{{- range lsdir "/registrator"}}
{{-     $serviceName := . }}
{{-     $serviceDir := printf "/registrator/%s/*" $serviceName }}

    [config.{{ $serviceName }}]
    # {{ $serviceDir }}

{{-     range gets $serviceDir }}
    {{ base .Key }} = {{ .Value }}
{{-     end }}

{{- end}}

# End of [config].

?lsdir 列出所有服务目录,然后?gets 取服务目录下的键值对?br />
执行 confd:

~/go/bin/confd -onetime -backend etcd -node //127.0.0.1:12379

[jinqing@localhost confd]$ cat /tmp/services.toml
[config]

    [config.etcd-2379]
    # /registrator/etcd-2379/*
    localhost.tech:jinqing-etcd:2379 = 192.168.93.183:12379

    [config.nginx]
    # /registrator/nginx/*
    localhost.tech:jinqing-nginx:80 = 192.168.93.183:1024

    [config.registry]
    # /registrator/registry/*
    localhost.tech:registry:5000 = 192.168.93.183:5000

# End of [config].


金庆 2018-06-13 14:27 发表评论
]]>
grpc-go与actor模式 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/06/12/215720.html金庆金庆Tue, 12 Jun 2018 03:15:00 GMT//www.pppqb.icu/jinq0123/archive/2018/06/12/215720.html//www.pppqb.icu/jinq0123/comments/215720.html//www.pppqb.icu/jinq0123/archive/2018/06/12/215720.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215720.html//www.pppqb.icu/jinq0123/services/trackbacks/215720.htmlgrpc-go与actor模式

(金庆的专?2018.6)

grpc-go服务器的每个h都在一个独立的协程中执行?br />|游服务器中Q一般请求会调用游戏戉K的方法,而房间是一个独立的协程?br />可以房间实CؓactorQgrpch通过Call()或Post()Ҏ来执行?br />其中Call()会等待返回,而Post()会异步执行无q回倹{?br />
type Room struct {
    // actC 是其他协E向Room协程发送动作的ChannelQ协E中依ơ执行动作?/span>
    // Action 动作, 是无参数无返回值的函数.
    actC chan func()

    ...
}

// Run q行戉K协程.
func (r *Room) Run() {
    ticker := time.NewTicker(20 * time.Millisecond)
    defer ticker.Stop()

    for r.running {
        select {
        case act := <-r.actC:
            act()
        case <-ticker.C:
            r.tick()
        }
    }
}

// Call calls a function f and returns the result.
// f runs in the Room's goroutine.
func (r *Room) Call(f func() interface{}) interface{} {
    // l果从chq回
    ch := make(chan interface{}, 1)
    r.actC <- func() {
        ch <- f()
    }
    // {待直到q回l果
    return <-ch
}

// Post 一个动作投递到内部协程中执?
func (r *Room) Post(f func()) {
    r.actC <- f
}

grpc服务Ҏ如:

func (m *RoomService) Test(ctx context.Context, req *pb.TestReq) (*pb.TestResp, error) {
    conn := conn_mgr.GetConn(ctx)
    if conn == nil {
        return nil, fmt.Errorf("can not find connection")
    }

    room := conn.GetRoom()
    resp := room.Call(func() interface{} {
        return room.Test(req)
    })

    return resp.(*pb.TestResp), nil
}

金庆 2018-06-12 11:15 发表评论
]]>
?kubeadm --config 创徏 k8s 集群 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/05/27/215683.html金庆金庆Sun, 27 May 2018 11:22:00 GMT//www.pppqb.icu/jinq0123/archive/2018/05/27/215683.html//www.pppqb.icu/jinq0123/comments/215683.html//www.pppqb.icu/jinq0123/archive/2018/05/27/215683.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215683.html//www.pppqb.icu/jinq0123/services/trackbacks/215683.html?kubeadm --config 创徏 k8s 集群

(金庆的专?2018.5)

利用阉K云的yum镜像和docker镜像Q可以不用代理直接安装创?k8s 集群?br />
K8s 版本?v1.10.3

参考:

https://blog.csdn.net/u010209217/article/details/78533936
Kubernetes 1.7.5部v以及kubernates-dashboard 1.7安装

https://www.cnblogs.com/liangDream/p/7358847.html
CentOS7.3利用kubeadm安装kubernetes1.7.3完整?官方文填坑?

https://yq.aliyun.com/articles/66474
阉K云快速部|Kubernetes - VPC环境

Docker 已安装?br />
采用阉K云的yum源镜像,直接安装:
yum -y install kubectl kubeadm kubelet

vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf, 为kubeletd一个额外的参数,
q样kubelet׃会在启动pod的时候去墙外的k8s仓库拉取pause-amd64:3.0镜像?br />--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0

export KUBE_REPO_PREFIX 的方式指定kube镜像库已?.8版本后无效,需要改为配|文件中配置 imageRepository?br />
kubeadm.yaml CZQ?br />https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/

apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
api:
  advertiseAddress: "10.20.79.10"
networking:
  podSubnet: "10.244.0.0/16"
kubernetesVersion: "v1.10.3"
imageRepository: "registry.cn-hangzhou.aliyuncs.com/google_containers"

初始化命令ؓQ?br />kubeadm init --config kubeadm.yaml

其他注意点:

需要开?kubelet.service, 不然查会报警告:
systemctl enable kubelet && systemctl start kubelet
需要关?swap:
[ERROR Swap]: running with swap on is not supported. Please disable swap
swapoff -a

可以查看 ls -ltr /etc/kubernetes/manifests/
yaml文g列表Q每个文仉会写着镜像的地址和版?br />
[ERROR FileAvailable--etc-kubernetes-manifests-kube-apiserver.yaml]: /etc/kubernetes/manifests/kube-apiserver.yaml already exists
[ERROR Port-10250]: Port 10250 is in use
kubeadm会自动检查当前环境是否有上次命o执行?#8220;D留”。如果有,必须清理后再行执行init。我们可以通过”kubeadm reset”来清理环?以备重来?br />
journalctl -xeu kubelet
用来查看kubelet执行有什么错误?br />
failed to run Kubelet: failed to create kubelet: misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"
需要修?/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
sed -i "s/cgroup-driver=systemd/cgroup-driver=cgroupfs/g" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
systemctl daemon-reload && systemctl restart kubelet


金庆 2018-05-27 19:22 发表评论
]]>
推荐Golang的assert?/title><link>//www.pppqb.icu/jinq0123/archive/2018/05/14/215637.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 14 May 2018 02:42:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/05/14/215637.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215637.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/05/14/215637.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215637.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215637.html</trackback:ping><description><![CDATA[<div class="dpun">推荐Golang的assert?br /><br />(金庆的专?2018.5)<br /><br />https://github.com/aurelien-rainone/assertgo<br /><br />Conditionally compiled assertions in Go <br /><br />和C++中的assert()一Pq个是带条g~译的,必须使用 debug 才能启用?br /><br />如:<br /><br />$ go run -tags debug main.go<br /><br />使用CZQ?br /><br />assert.True(true, "never printed")<br /><br /></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215637.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-05-14 10:42 <a href="//www.pppqb.icu/jinq0123/archive/2018/05/14/215637.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>consul命o中的几个地址 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/05/09/215627.html金庆金庆Wed, 09 May 2018 10:32:00 GMT//www.pppqb.icu/jinq0123/archive/2018/05/09/215627.html//www.pppqb.icu/jinq0123/comments/215627.html//www.pppqb.icu/jinq0123/archive/2018/05/09/215627.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215627.html//www.pppqb.icu/jinq0123/services/trackbacks/215627.htmlconsul命o中的几个地址

(金庆的专?2018.5)

consul命o行中有以下几个地址参数Q?br />
* -bind
    l定地址Q用于集通信Q缺?0.0.0.0
* -clint
    l定地址Q用?RPC, DNS, HTTP and HTTPSQ缺?127.0.0.1
* -serf-lan-bind
    l定地址Q用于内|集通信Q缺省?-bind 地址
* -serf-wan-bind
    l定地址Q用于跨机房通信Q缺省?-bind 地址
* -advertise
    通告地址Q通告l集中其他节点Q缺省?-bind 地址
* -advertise-wan
    通告地址Q通告l其他机房的服务节点Q缺省?-advertise 地址
* -join -retry-join
    加入集群的目标地址
* -join-wan -retry-join-wan
    跨机戉K联的目标地址
* -recursor
    上游DNS地址

官方文Q?https://www.consul.io/docs/agent/options.html#command-line-options


金庆 2018-05-09 18:32 发表评论
]]>
服务发现的组?/title><link>//www.pppqb.icu/jinq0123/archive/2018/05/04/215617.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 04 May 2018 08:07:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/05/04/215617.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215617.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/05/04/215617.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215617.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215617.html</trackback:ping><description><![CDATA[<div class="dpun"><div class="dpun"> <p>服务发现的组?/p> <p>(金庆的专?2018.5)</p> <p>服务发现有以下组Ӟ</p> <ul class="dpun"><li class="dpun"><p>Service Registry 服务注册中心</p> <p>l护服务的列表,提供查询。一般实Cؓ分布式键值存储数据库?/p></li><li class="dpun"><p>Registrator 注册?/p> <p>监听服务创徏和删除事Ӟq在服务注册中心动态注册或注销服务?/p></li><li class="dpun"><p>Health Checker 健康查器</p> <p>监视服务是否健康Qƈ在服务注册中心动态更新服务?/p></li><li class="dpun"><p>Load balancer 负蝲均衡?/p> <p>服务请求分散到各个服务器?/p></li></ul> </div></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-05-04 16:07 <a href="//www.pppqb.icu/jinq0123/archive/2018/05/04/215617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Prometheus动态配|目?/title><link>//www.pppqb.icu/jinq0123/archive/2018/04/24/215601.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 24 Apr 2018 04:13:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/04/24/215601.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215601.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/04/24/215601.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215601.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215601.html</trackback:ping><description><![CDATA[<div class="dpun">Prometheus动态配|目?br /><br />(金庆的专?2018.4)<br /><br />最单的配置是静态目标:<br /><br /><span style="color: #800000;">scrape_configs:</span><br /><span style="color: #800000;">  - job_name: 'prometheus'</span><br /><br /><span style="color: #800000;">    static_configs:</span><br /><span style="color: #800000;">      - targets: ['localhost:9090', 'localhost:9100']</span><br /><span style="color: #800000;">        labels:</span><br /><span style="color: #800000;">          group: 'prometheus'</span><br /><br />更改此文件后Q可以发?SIGHUP 触发配置重新加蝲?br /><br />Prometheus 提供了服务发现功能,可以?consul, dns, kubernetes, file {等多种来源发现新的目标?br />其中最单的是从文g发现服务?br /><br />例如 /root/prometheus/prometheus.yml 配置如下Q?br /><br /><span style="color: #800000;">global:</span><br /><span style="color: #800000;">  scrape_interval: 15s</span><br /><span style="color: #800000;">  evaluation_interval: 15s</span><br /><span style="color: #800000;">scrape_configs:</span><br /><span style="color: #800000;">  - job_name: 'prometheus'</span><br /><span style="color: #800000;">    static_configs:</span><br /><span style="color: #800000;">      - targets: ['127.0.0.1:9090', '127.0.0.1:9100']</span><br /><span style="color: #800000;">        labels:</span><br /><span style="color: #800000;">          group: 'prometheus'</span><br /><span style="color: #800000;">  - job_name: 'test'</span><br /><span style="color: #800000;">    file_sd_configs:</span><br /><span style="color: #800000;">      - files: ['/etc/prometheus/test_sd_config/*.yml']</span><br /><span style="color: #800000;">        refresh_interval: 5s</span><br /><br />?docker 启动 prometheus:<br /><br /><span style="color: #000080;">docker run -d --net=host \</span><br /><span style="color: #000080;">  -v /root/prometheus:/etc/prometheus \</span><br /><span style="color: #000080;">  --name prometheus-server \</span><br /><span style="color: #000080;">  prom/prometheus</span><br /><br />创徏 /root/prometheus/test_sd_config/test.yml 如下<br /><br /><span style="color: #800000;">- targets: [ "192.168.93.192:8080" ]</span><br /><span style="color: #800000;">  labels:</span><br /><span style="color: #800000;">    group: "my_test_group"</span><br /><br />5s内就会自动读?test.yml q添加新的目标?br />可用览器打开Prometheus 9090 端口, <br />查看 Status 中的 Configuration, Targets, Service Discovery,<br />可以看到新添加的目标?br /></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215601.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-04-24 12:13 <a href="//www.pppqb.icu/jinq0123/archive/2018/04/24/215601.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Dockerq行Prometheus和Grafana - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/04/19/215597.html金庆金庆Thu, 19 Apr 2018 05:52:00 GMT//www.pppqb.icu/jinq0123/archive/2018/04/19/215597.html//www.pppqb.icu/jinq0123/comments/215597.html//www.pppqb.icu/jinq0123/archive/2018/04/19/215597.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215597.html//www.pppqb.icu/jinq0123/services/trackbacks/215597.htmlDockerq行Prometheus和Grafana

(金庆的专?2018.4)

Prometheus官网的运行示例是直接执行?br />可以参照 https://www.katacoda.com/ 的教E用Dockerq行Prometheus和Grafana.
搜烦 Grafana 的教E,q行步骤如下Q?br />
1. ~写 prometheus.yml

global:
  scrape_interval:     15s
  evaluation_interval: 15s
scrape_configs:
  - job_name: 'prometheus'

    static_configs:
      - targets: ['localhost:9090', 'localhost:9100']
        labels:
          group: 'prometheus'

localhost 好像不行Q换?127.0.0.1
          
2. q行 prometheus

docker run -d --net=host \
  -v /root/prometheus.yml:/etc/prometheus/prometheus.yml \
  --name prometheus-server \
  prom/prometheus
 
3. q行 Node Exporter

docker run -d -p 9100:9100 \
-v "/proc:/host/proc" \
-v "/sys:/host/sys" \
-v "/:/rootfs" \
--net="host" \
--name=prometheus \
quay.io/prometheus/node-exporter:v0.13.0 \
  -collector.procfs /host/proc \
  -collector.sysfs /host/sys \
  -collector.filesystem.ignored-mount-points "^/(sys|proc|dev|host|etc)($|/)"

4. q行 Grafana
 
  docker run -d --name=grafana -p 3000:3000 grafana/grafana
 
~省用户Q?admin/admin

5. d数据源,q导入A表盘

Add Data Sources ->
Name: Prometheus
Type: Prometheus
URL: //1.2.3.4:9090
Access: proxy
Save & Test...

Create Import ->
Grafana.com Dashboard: 22





金庆 2018-04-19 13:52 发表评论
]]>
grpc-lua CZ - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/04/13/215587.html金庆金庆Fri, 13 Apr 2018 07:41:00 GMT//www.pppqb.icu/jinq0123/archive/2018/04/13/215587.html//www.pppqb.icu/jinq0123/comments/215587.html//www.pppqb.icu/jinq0123/archive/2018/04/13/215587.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215587.html//www.pppqb.icu/jinq0123/services/trackbacks/215587.htmlgrpc-lua CZ

(金庆的专?2018.4)

grpc-lua (https://github.com/jinq0123/grpc-lua) ?grpc ?lua l定库,
应用?luapbintf , 不需要生成代码,直接d proto 文g?br />
如:
    -- Sync request.
    local request = { name = "world" }
    local response = assert(stub:sync_request("SayHello", request))
    print("Greeter received: " .. response.message)

完整的示例代码见 examples 目录?br />
服务器和客户端都支持同步和异步调用?br />
?examples/conan_install.bat.example 去除 .example 后缀Q然后运行,
安装所有的依赖? d安装 conan 包管理工?(//docs.conan.io/en/latest/installation.html)?br />q需要设|?git 代理Q因?grpc 的子库需要翻q墙?br />
conan_install.bat 实际上是下蝲依赖库代码ƈ~译。结果在用户目录 .conan/data/?br />在其中搜?lua-cpp.exe, lua-cpp.dll, luapbintf.dll, grpc_lua.dll q复制到 examples/helloworld/ 目录下?br />
然后?helloworld 目录下分别运?run_server.bat ?run_client.bat 试?br />
已编译测试可行的完整包可下蝲Q?br />grpc-lua 代码及示例Windows执行E序Qhttps://download.csdn.net/download/jq0123/10346554
grpc-lua CZ CentOS 7.4 执行E序打包Qhttps://download.csdn.net/download/jq0123/10346003

CentOS 7.4 实测Q?br />
[jinqing@localhost helloworld]$ ls
greeter_client.lua   grpc_lua.so       lua-cpp         run_server.bat
greeter_server.lua   helloworld.proto  luapbintf.so
greeter_service.lua  liblua-cpp.so     run_client.bat
[jinqing@localhost helloworld]$ ./lua-cpp greeter_server.lua
Server listening on 0.0.0.0:50051
Got hello from world
Got hello from world

[jinqing@localhost helloworld]$ ./lua-cpp greeter_client.lua
Greeter received: Hello world
Async greeter received: Hello world
[jinqing@localhost helloworld]$

[jinqing@localhost route_guide]$ ./lua-cpp route_guide_server.lua
RecordRoute reader end.
RouteChat reader end.

[jinqing@localhost route_guide]$ ./lua-cpp route_guide_client.lua
-------------- Sync get feature --------------
Found feature: {
...


金庆 2018-04-13 15:41 发表评论
]]>
?DocFetcher 全文搜烦 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/04/08/215577.html金庆金庆Sun, 08 Apr 2018 07:17:00 GMT//www.pppqb.icu/jinq0123/archive/2018/04/08/215577.html//www.pppqb.icu/jinq0123/comments/215577.html//www.pppqb.icu/jinq0123/archive/2018/04/08/215577.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215577.html//www.pppqb.icu/jinq0123/services/trackbacks/215577.html?DocFetcher 全文搜烦

(金庆的专?2018.4)

以前?Notepad++ 的全文搜索,没有索引Q每ơ搜索都ȝ待一会儿?br />
?DocFetcher 是开源的桌面搜烦应用Q徏好烦引后Q搜索会立即出结果?br />
先须为某个目录创建烦引,选择某些后缀名的文g。然后选中该烦引进行搜索?br />

金庆 2018-04-08 15:17 发表评论
]]>
|游服务?Services-based ?Cells-based 架构 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/03/10/215551.html金庆金庆Sat, 10 Mar 2018 10:03:00 GMT//www.pppqb.icu/jinq0123/archive/2018/03/10/215551.html//www.pppqb.icu/jinq0123/comments/215551.html//www.pppqb.icu/jinq0123/archive/2018/03/10/215551.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215551.html//www.pppqb.icu/jinq0123/services/trackbacks/215551.html|游服务?Services-based ?Cells-based 架构

(金庆的专?2018.3)

无缝世界|游服务器架构的设计思\
//blog.csdn.net/SmartTony/article/details/6842065
提出?U网游服务器架构Q?br />
* Services-based architecture Z服务的架?br />* Cells-based architecture Zcell的架?br />
Z服务的架构按功能划分成不同服务,不同服务实现于不同的q程?br />而基于cell的架构用相同的Cellq程l成一个集,每个Cellq程包含全部的功能?br />
Z服务的架构一直是L的架构,自从 microservice ?service mesh 概念相􋹁行Q?br />Z微服务的架构应该会成为未来的方向?br />
在无~大地图|游中,应该用基于cell的架构来实现地图及相兛_能,
其他与位|无关的功能则应该尽量按服务实现?br />考虑到服务来回调用g时较大,对于实时性强的功能,如PK也应该在cell上实现?br />
可以考虑客户端通过专门的网xq接cell, 使用udp/kcp来减时延?br />而其他非实时性服务由Tcp|关转发?br />服务器内部可全部l一采用 gRPC.



金庆 2018-03-10 18:03 发表评论
]]>
|游同步中的旉?/title><link>//www.pppqb.icu/jinq0123/archive/2018/01/18/215477.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 18 Jan 2018 13:28:00 GMT</pubDate><guid>//www.pppqb.icu/jinq0123/archive/2018/01/18/215477.html</guid><wfw:comment>//www.pppqb.icu/jinq0123/comments/215477.html</wfw:comment><comments>//www.pppqb.icu/jinq0123/archive/2018/01/18/215477.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/jinq0123/comments/commentRss/215477.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/jinq0123/services/trackbacks/215477.html</trackback:ping><description><![CDATA[<div class="dpun">|游同步中的旉?br /><br />(金庆的专?2018.1)<br /><br />旉知觉Qtemporal perceptionQ?对客观现象的延箋性和序性的反应。实际上是对事g和运动的知觉?br />-- //dict.youdao.com/w/temporal_perception<br /><br />|游旉以服务器的ؓ准?br />|游客户端落后服务器例如1帧时_所以表现的是过ȝ场景?br />因ؓ玩家自n的行为是已知的,所以本地可以预自w角色的状态,前于其他角艌Ӏ?br />处于前旉的主角与处于q去旉的其他角色共处?br /><br />This raises the problem of interaction between objects displayed in present time space (the player's avatar) and objects displayed in a past time space (remote characters, AI entities). One solution is to make the LCT vary according to the distance from the player's avatar. This idea is called temporal perception, or presentation time or sometimes local perception filters and comes from the analogy with the appearance of the stars in the sky: the farther the distance, the longer the time the light takes to come to us [Singhal-Zyda].<br /><br />-- //www.xlgps.com/article/99968.html 带宽限制下的视觉实体属性传?br /><br />主角可以与过L间的其他角色交互Q距越q,可以允许的滞后时间就长?br />q个概念UC旉感知qo?temporal perception filter)Q?br />或者本地感知过滤器(local perception filter)?br /><br />可以用星星作cLQ我们看到的一光年q的星星其实是一q前的星星?br /><br />Local Perception Filter Demo<br />//mikolalysenko.github.io/local-perception-filter-demo/<br /></div><img src ="//www.pppqb.icu/jinq0123/aggbug/215477.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/jinq0123/" target="_blank">金庆</a> 2018-01-18 21:28 <a href="//www.pppqb.icu/jinq0123/archive/2018/01/18/215477.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>?LiteIDE d选中标记 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2018/01/06/215458.html金庆金庆Sat, 06 Jan 2018 03:05:00 GMT//www.pppqb.icu/jinq0123/archive/2018/01/06/215458.html//www.pppqb.icu/jinq0123/comments/215458.html//www.pppqb.icu/jinq0123/archive/2018/01/06/215458.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215458.html//www.pppqb.icu/jinq0123/services/trackbacks/215458.html?LiteIDE d选中标记

(金庆的专?2018.1)

"[Eclipse Mark Occurrences](//www.eclipse.org/pdt/help/html/mark_occurrences.htm)"
可以在滚动条旁边昄文中所有选中的标讎ͼ
可以选中某个变量昄有多引用。不q?GoClipse 没有 "Mark Occurrences" 功能?br />VS code 有此功能?br />
LiteIDE 对于build错误会显CU标讎ͼ所以感觉可以依此实?Mark Occurrences"?br />
首先扑ֈ了打标记的功能。标记用到颜Ԍ所以搜'QColor', 扑ֈ了:
```c++
QColor markTypeColor(LiteApi::EditorNaviagteType type)
```

相关的接口会用到Q?br />```c++
    void insertNavigateMark(int line, LiteApi::EditorNaviagteType type, const QString &msg, const char* tag);
    void clearAllNavigateMark(LiteApi::EditorNaviagteType types, const char *tag);
```

L选中时触发标记的代码Q选中或搜索时会有圆角框圈出,?find", 扑ֈQ?br />```c++
if (!m_findExpression.isEmpty()) {
    if (!findInBlock(block,m_findExpression,pos,m_findFlags,cur)) {
        break;
    }
    ...
    painter.drawRoundedRect(offsetX+left,r.top()+l.y(),right-left,l.height(),3,3);
} else if (!m_selectionExpression.isEmpty()) {
    if (!findInBlock(block,m_selectionExpression,pos,QTextDocument::FindWholeWords,cur)) {
        break;
    }
    ...
    painter.drawRoundedRect(offsetX+left,r.top()+l.y(),right-left,l.height(),3,3);
}
```

发现L框仅在可视区域。箋l查?m_findExpression ?m_selectionExpression 更改处,
d 'updateNavigateMarks()'

```c++
void LiteEditorWidgetBase::setFindOption(LiteApi::FindOption *opt)
{
    ...
+   updateNavigateMarks(LiteApi::EditorNavigateFind);
    viewport()->update();
}
```

```c++
void LiteEditorWidgetBase::slotSelectionChanged()
{
    ...
        m_selectionExpression.setPattern(pattern);
+       updateNavigateMarks(LiteApi::EditorNavigateSelection);
        viewport()->update();
    ...
}
```

L?个新的类型:
```c++
enum EditorNaviagteType{
    EditorNavigateNormal = 1,
    EditorNavigateWarning = 2,
    EditorNavigateError = 4,
    EditorNavigateReload = 8,
+   EditorNavigateFind = 16,
+   EditorNavigateSelection = 32,
    EditorNavigateBad = EditorNavigateWarning|EditorNavigateError
};
```

搜烦 `EditorNavigateWarning`, 扑ֈ因新增类型须更改优先U表和颜色函数?br />
```c++
const int PRIORITYLIST_LENGTH = 7;
const LiteApi::EditorNaviagteType MARKTYPE_PRIORITYLIST[PRIORITYLIST_LENGTH] = {
        ..., LiteApi::EditorNavigateFind, LiteApi::EditorNavigateSelection, ...
    };
...
inline QColor markTypeColor(LiteApi::EditorNaviagteType type) {
    switch(type) {
    ...
    case LiteApi::EditorNavigateNormal:
        return Qt::darkGreen;
    case LiteApi::EditorNavigateReload:
        return Qt::darkBlue;
    }
}
```

更新标记时先清空Q然后逐行搜烦d标记Q?br />```c++
// Update selections or find marks.
void LiteEditorWidgetBase::updateNavigateMarks(LiteApi::EditorNaviagteType type)
{
    clearAllNavigateMark(type, "");
    ...

    QTextDocument *doc = this->document();
    for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
    {
        if (!needToMarkBlock(it, type))
            continue;
        int lineNumber = it.blockNumber() + 1;
        insertNavigateMark(lineNumber, type, QString("%1: %2").arg(lineNumber).arg(it.text()), "");
    }
}

bool LiteEditorWidgetBase::needToMarkBlock(
    const QTextBlock &block, LiteApi::EditorNaviagteType type) const
{
    ...
    if (LiteApi::EditorNavigateFind == type)
        return findInBlock(block, m_findExpression, pos, m_findFlags, cur);
    if (LiteApi::EditorNavigateSelection == type)
        return findInBlock(block, m_selectionExpression, pos,
                           QTextDocument::FindWholeWords, cur);
    return false;
}
```

已合q主qԌ
```
Revision: 43f4954b0b802eccbbf451136be600bfcec71f27
Author: Jin Qing <jinq0123@163.com>
Date: 18.1.5 19:08:26
Message:
Add "Mark Occurrences" function that marks selections and findings.

----
Modified: liteidex/src/api/liteeditorapi/liteeditorapi.h
Modified: liteidex/src/plugins/liteeditor/liteeditorwidgetbase.cpp
Modified: liteidex/src/plugins/liteeditor/liteeditorwidgetbase.h
```

金庆 2018-01-06 11:05 发表评论
]]>
gRPC-go q接理 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/12/25/215444.html金庆金庆Mon, 25 Dec 2017 11:00:00 GMT//www.pppqb.icu/jinq0123/archive/2017/12/25/215444.html//www.pppqb.icu/jinq0123/comments/215444.html//www.pppqb.icu/jinq0123/archive/2017/12/25/215444.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215444.html//www.pppqb.icu/jinq0123/services/trackbacks/215444.htmlgRPC-go q接理

(金庆的专?2017.12)

?example greeter 改一下,处理 SayHello() hӞ不仅仅返回本ơ请求者的名字Q?br />q返回上ơ请求的名字Q如Q?br />```
λ go run greeter_client/main.go
2017/12/25 17:59:13 Greeting: Hello 'world' (prev '')
2017/12/25 17:59:15 Greeting: Hello 'world2' (prev 'world')
```

先将客户端单ơ请求改为多ơ请求:

```go
    r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
    log.Printf("Greeting: %s", r.Message)
    time.Sleep(2 * time.Second)

    r, err = c.SayHello(context.Background(), &pb.HelloRequest{Name: name + "2"})
    log.Printf("Greeting: %s", r.Message)
    ...
```

服务器需要ؓ每个q接保存各自的数据。连接创建时初始化数据,q接断开时清理数据?br />q里利用了连接统计的接口Q不知道是否是最适当的实现方?

服务器创建时d StatsHandler 选项Q输入一?stats.Handler 的实现?br />```
-    s := grpc.NewServer()
+    s := grpc.NewServer(grpc.StatsHandler(&statshandler{}))
```

statshandler 需实现4个方法,只用?个连接相关的ҎQTagConn() ?HandleConn(),
另外2?TagRPC() ?HandleRPC() 用于RPCl计, 实现为空?br />
```go
type statshandler struct{}

// TagConn 用来l连接打个标{,以此来标识连?实在是找不出q有什么办法来标识q接).
// q个标签是个指针Q可保证每个q接唯一?/span>
// 该指针dC下文中去Q键?connCtxKey{}.
func (h *statshandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
    return context.WithValue(ctx, connCtxKey{}, info)
}

// TagRPC 为空.
func (h *statshandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
    return ctx
}

// HandleConn 会在q接开始和l束时被调用Q分别会输入不同的状?
func (h *statshandler) HandleConn(ctx context.Context, s stats.ConnStats) {
    tag, ok := getConnTagFromContext(ctx)
    if !ok {
        log.Fatal("can not get conn tag")
    }

    connsMutex.Lock()
    defer connsMutex.Unlock()

    switch s.(type) {
    case *stats.ConnBegin:
        conns[tag] = ""
        log.Printf("begin conn, tag = (%p)%#v, now connections = %d\n", tag, tag, len(conns))
    case *stats.ConnEnd:
        delete(conns, tag)
        log.Printf("end conn, tag = (%p)%#v, now connections = %d\n", tag, tag, len(conns))
    default:
        log.Printf("illegal ConnStats type\n")
    }
}

// HandleRPC 为空.
func (h *statshandler) HandleRPC(ctx context.Context, s stats.RPCStats) {
}
```

用一个map来管理所有连接,以连接的标签(是个指针)为键Qgؓ上次h者的名字?br />因ؓ有多U程讉KQ所有加?Mutex 来保护?br />q接l束Ӟ从 conns 中删除连接相关的数据?br />
```go
var connsMutex sync.Mutex
var conns map[*stats.ConnTagInfo]string = make(map[*stats.ConnTagInfo]string)
```

getConnTagFromContext() 从上下文中取q接标签Q?br />
```go
type connCtxKey struct{}

func getConnTagFromContext(ctx context.Context) (*stats.ConnTagInfo, bool) {
    tag, ok := ctx.Value(connCtxKey{}).(*stats.ConnTagInfo)
    return tag, ok
}
```

最后将 SayHello() 改ؓ记录h者名字,q返回上ơ请求者的名字?br />
```go
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    tag, _ := getConnTagFromContext(ctx)
    log.Printf("SayHello(), conn tag = (%p)%#v\n", tag, tag)

    connsMutex.Lock()
    defer connsMutex.Unlock()
    prev := conns[tag]
    conns[tag] = in.Name

    return &pb.HelloReply{Message: fmt.Sprintf("Hello '%s' (prev '%s')", in.Name, prev)}, nil
}
```

试多个客户端连接,可以看到每个客户端有自己的状态,互不影响?br />
```
E:\Git\grpc-go\examples\helloworld (master)
λ go run greeter_server/main.go
2017/12/25 18:39:03 start
2017/12/25 18:39:11 begin conn, tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}, now connections = 1
2017/12/25 18:39:11 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:13 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:13 begin conn, tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}, now connections = 2
2017/12/25 18:39:13 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:15 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:15 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:17 SayHello(), conn tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}
2017/12/25 18:39:17 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:19 end conn, tag = (0xc042182040)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0420818f0), LocalAddr:(*net.TCPAddr)(0xc0420818c0)}, now connections = 1
2017/12/25 18:39:19 SayHello(), conn tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}
2017/12/25 18:39:21 end conn, tag = (0xc0421ae200)&stats.ConnTagInfo{RemoteAddr:(*net.TCPAddr)(0xc0421de060), LocalAddr:(*net.TCPAddr)(0xc0421de030)}, now connections = 0
```


金庆 2017-12-25 19:00 发表评论
]]>
asio 协程?yield - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/12/07/215397.html金庆金庆Thu, 07 Dec 2017 06:51:00 GMT//www.pppqb.icu/jinq0123/archive/2017/12/07/215397.html//www.pppqb.icu/jinq0123/comments/215397.html//www.pppqb.icu/jinq0123/archive/2017/12/07/215397.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215397.html//www.pppqb.icu/jinq0123/services/trackbacks/215397.html

asio 协程?yield


(金庆的专?2017.12)


https://stackoverflow.com/questions/26127458/yielding-in-boost-asio-stackful-coroutine


Asio spawn() 可以产生一个协E,协程中可以调?async_read(..., yield), async_write(..., yield), 但是不知道如何主动释放控制权(yield)?


asio::spawn(strand_, [this, self](asio::yield_context yield)
{
    while (!computationFinished)
    {
        computeSomeMore();
        yield; // WHAT SHOULD THIS LINE BE?
    }
}


{案是:

iosvc.post(yield);


其他q可以是

iosvc.poll_one();

iosvc.poll();


应该?post(yield) 最合适?/p>


... polling the io_service avoids the context switch overhead, but unhandled exceptions from handlers will unwind and destroy the coroutine.




金庆 2017-12-07 14:51 发表评论
]]>
?Lile 创徏 gRPC-go 服务 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/11/28/215377.html金庆金庆Tue, 28 Nov 2017 10:47:00 GMT//www.pppqb.icu/jinq0123/archive/2017/11/28/215377.html//www.pppqb.icu/jinq0123/comments/215377.html//www.pppqb.icu/jinq0123/archive/2017/11/28/215377.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215377.html//www.pppqb.icu/jinq0123/services/trackbacks/215377.html?Lile 创徏 gRPC-go 服务

(金庆的专?2017.11)

Lile 是一个工P用于 Go 语言快速创?gRPC 服务?br />https://github.com/lileio/lile

会自动添?Prometheus, Zipkin ?Google PubSub 支持?br />
go get -u github.com/lileio/lile/...
安装所有依赖包Qƈ生成 bin/lile.exe, bin/protoc-gen-lile-server.exe.
另外q需要安?protoc.exe.

按照CZ创徏 users 服务Q?br />
E:\gopath\src\github.com
λ lile new jinq0123/users
Creating project in E:\gopath\src\github.com\jinq0123\users
Is this OK? [y]es/[n]o
y
.
├── server
│   ├── server.go
│   └── server_test.go
├── subscribers
│   └── subscribers.go
├── users
│   ├── cmd
│   │   ├── root.go
│   │   ├── serve.go
│   │   ├── subscribe.go
│   │   └── up.go
│   └── main.go
├── users.proto
├── Makefile
├── Dockerfile
├── .travis.yml
└── .gitignore

查看 Makefile, 复制其中 protoc 脚本Q将 $$GOPATH 改ؓ %GOPATH%Q运行:

E:\gopath\src\github.com\jinq0123\users
λ protoc -I . users.proto --lile-server_out=. --go_out=plugins=grpc:%GOPATH%/src
2017/11/28 16:59:24 [Creating] server\read.go
2017/11/28 16:59:24 [Creating test] server\read_test.go

protoc-gen-lile-server.exe 生?server\read.go, 对应 user.proto 中的Ҏ Users::Read().
grpc的插件将生成 users.pb.goQ与仅仅?grpc 生成的代码相同?br />
D:/Go/bin/go.exe install -v [E:/gopath/src/github.com/jinq0123/users/users]
github.com/jinq0123/users/users
成功: q程退Z?0.

可直接编译生?user.exe.

无参数运行则昄命o行帮助:

E:\gopath\src\github.com\jinq0123\users
λ users
A gRPC based service

Usage:
  users [command]

Available Commands:
  help        Help about any command
  serve       Run the RPC server
  subscribe   Subscribe to and process queue messages
  up          up runs both RPC and pubub subscribers

Flags:
  -h, --help   help for users

Use "users [command] --help" for more information about a command.

用子命oserve启动服务Q?br />
E:\gopath\src\github.com\jinq0123\users
λ users serve
INFO[0000] Serving gRPC on :8000
INFO[0000] Using Zipkin Global tracer
INFO[0000] Prometheus metrics at :9000/metrics

//localhost:9000/metrics 会显C?br />
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
...

?grpc-lua 来测试下Q?br />
E:\Git\grpc-lua\examples\helloworld (master)
λ lua-cpp.exe
Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio
> package.path = "../../src/lua/?.lua;" .. package.path
> grpc = require("grpc_lua.grpc_lua")
> grpc.import_proto_file("users.proto")
> stub = grpc.service_stub("localhost:8000", "users.Users")
D1128 17:28:13.711000000  4612 dns_resolver.c:301] Using native dns resolver
> request = {id = "abcd"}
> response, err, cod = stub:sync_request("Read", request)
> cod
2
> insp = require("inspect")
> insp(resonse)
nil
> insp(err)
"not yet implemented"

~省实现q回 "not yet implemented" 错误。更改实C如下Q?br />
func (s UsersServer) Read(ctx context.Context, r *users.Request) (*users.Response, error) {
    // return nil, errors.New("not yet implemented")
    return &users.Response{Id: "Hello, " + r.Id}, nil
}

再次hQ?br />
> response, err, cod = stub:sync_request("Read", request)
> err
Endpoint read failed
...
> response, err, cod = stub:sync_request("Read", request)
> err
nil
> insp(response)
{
  id = "Hello, abcd"
}


金庆 2017-11-28 18:47 发表评论
]]>
protobuf中的枚D~省值应该ؓENUN_TYPE_UNSPECIFIED - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/11/22/215364.html金庆金庆Wed, 22 Nov 2017 02:45:00 GMT//www.pppqb.icu/jinq0123/archive/2017/11/22/215364.html//www.pppqb.icu/jinq0123/comments/215364.html//www.pppqb.icu/jinq0123/archive/2017/11/22/215364.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215364.html//www.pppqb.icu/jinq0123/services/trackbacks/215364.htmlprotobuf中的枚D~省值应该ؓENUN_TYPE_UNSPECIFIED

(金庆的专?2017.11)

Googol 公布?API Design 规范中,*.proto 中的枚D~省值徏议ؓ ENUN_TYPE_UNSPECIFIED?br />
https://mp.weixin.qq.com/s?__biz=MzA5ODg4Mzk2OQ==&mid=2247483705&idx=1&sn=cc2ffef9ac431510c1791dbe6e774b85

The first value should be named ENUM_TYPE_UNSPECIFIED as it is returned when an enum value is not explicitly specified.

enum FooBar {
  // The first value represents the default and must be == 0.
  FOO_BAR_UNSPECIFIED = 0;
  FIRST_VALUE = 1;
  SECOND_VALUE = 2;
}

参考:protobuf中的枚D~省值应该ؓUNKNOWN
//blog.csdn.net/jq0123/article/details/52219597


金庆 2017-11-22 10:45 发表评论
]]>
?dep 代替 go get 来获取私有库 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/11/06/215328.html金庆金庆Mon, 06 Nov 2017 06:27:00 GMT//www.pppqb.icu/jinq0123/archive/2017/11/06/215328.html//www.pppqb.icu/jinq0123/comments/215328.html//www.pppqb.icu/jinq0123/archive/2017/11/06/215328.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215328.html//www.pppqb.icu/jinq0123/services/trackbacks/215328.html

?dep 代替 go get 来获取私有库


(金庆的专?2017.11)


go get 功能比较弱,无法获取分支Q标{,特定版本Qfork, ?dep 可以做到?code>dep q可以获取私有库?/p>

?gitee.com U有库作试。创?gogettest 库?/p>

可用Q?/p>

go get -u gitee.com/jinq0123/gogettest

如果改ؓU有库则p|Q?/p>

λ go get -v gitee.com/jinq0123/gogettest
Fetching https://gitee.com/jinq0123/gogettest?go-get=1
Parsing meta tags from https://gitee.com/jinq0123/gogettest?go-get=1 (status code 403)
package gitee.com/jinq0123/gogettest: unrecognized import path "gitee.com/jinq0123/gogettest" (parse https://gitee.com/jinq0123/gogettest?go-get=1: no go-import meta tags ())

?dep 工具取私有库

https://github.com/golang/dep

安装dep

go get -u github.com/golang/dep/cmd/dep1

初始?/h3>

在项目目录下q行Q?/p>

dep init

生成 Gopkg.toml ?Gopkg.lock

d强制(constraint)

?Gopkg.toml 中添加:

 

[[constraint]]
  branch = "master"
  name = "gitee.com/jinq012345/gogettest"
  source = "https://gitee.com/jinq0123/gogettest.git"
source 强制使用 https 来获?gotgettest 库?

 

注意库名Ҏ?jinq012345, q样导入Q?
imort "gitee.com/jinq012345/gogettest"

name和source的设|可支持?fork 库获取?/p>

获取gogettest?/h3>
dep ensure

会弹?https 的登录用户名和密码输入框?/p>

金庆 2017-11-06 14:27 发表评论
]]>函数错误 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/10/30/215318.html金庆金庆Mon, 30 Oct 2017 04:22:00 GMT//www.pppqb.icu/jinq0123/archive/2017/10/30/215318.html//www.pppqb.icu/jinq0123/comments/215318.html//www.pppqb.icu/jinq0123/archive/2017/10/30/215318.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215318.html//www.pppqb.icu/jinq0123/services/trackbacks/215318.html函数错误

(金庆的专?2017.10)

摘自QGo语言圣经
https://shower.im/doc/gopl-zh/ch5/ch5-04.html

* 保证成功Q没有错误?br />* 无法保证成功Q如IO操作?br />    + q回bool, 原因只有一?br />    + q回error
    
5U错误处理策?br />1. 传播错误
2. 重试
3. l束E序Q只应在main中)
4. 日志
5. 忽略


金庆 2017-10-30 12:22 发表评论
]]>
用docker stack开启redis集群 - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/10/26/215308.html金庆金庆Thu, 26 Oct 2017 04:08:00 GMT//www.pppqb.icu/jinq0123/archive/2017/10/26/215308.html//www.pppqb.icu/jinq0123/comments/215308.html//www.pppqb.icu/jinq0123/archive/2017/10/26/215308.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215308.html//www.pppqb.icu/jinq0123/services/trackbacks/215308.html用docker stack开启redis集群

(金庆的专?2017.10)

?个docker swarm节点Q开启redis cluster.
每个机器上开2个redis节点Q共10个redis节点?br />采用官方的redis:alpine镜像?br />
docker-stack.yml 如下Q?br />
version: "3"
services:
  redis001:
    image: redis:alpine
    volumes:
      - /home/redis/001/data:/data
      - /home/redis/001/conf:/conf
    command: redis-server --appendonly yes --cluster-enabled yes --cluster-config-file /conf/nodes.conf --cluster-announce-ip 10.240.79.8 --cluster-announce-port 7001 --cluster-announce-bus-port 17001
    ports:
      - "7001:6379"
      - "17001:16379"
    networks:
      - redisnet
    deploy:
      placement:
        constraints:
          - node.hostname == host-10-240-79-8

  redis002:
    image: redis:alpine
    volumes:
      - /home/redis/002/data:/data
      - /home/redis/002/conf:/conf
    command: redis-server --appendonly yes --cluster-enabled yes --cluster-config-file /conf/nodes.conf --cluster-announce-ip 10.240.79.9 --cluster-announce-port 7002 --cluster-announce-bus-port 17002
    ports:
      - "7002:6379"
      - "17002:16379"
    networks:
      - redisnet
    deploy:
      placement:
        constraints:
          - node.hostname == host-10-240-79-9

  redis003:
  ...
  redis010:
    ...
 
networks:
  redisnet:

数据保存文g?/home/redis/001/data
集群配置文g保存到 /home/redis/001/conf/nodes.conf  
各机器上目录需要预先创建,不然docker开启失败?br />q且需要设|目录权限,不然?Permission denied".
redis-server以用户uid=100(redis)q行Q所?br />    chown -R 100 /home/redis/

启动redis服务?
    docker stack deploy -c docker-stack.yml redis

redis-server启动后,q行 redis-trib.rb 来组?redis cluster:

    docker run --rm -it inem0o/redis-trib create --replicas 1 10.240.79.8:7001 10.240.79.9:7002 ... 10.240.79.12:7010

注意 inem0o/redis-trib 的说明中Q命令示例缺?"-it", 会报错退出:
Can I set the above configuration? (type 'yes' to accept): : undefined method `chomp' for nil:NilClass (NoMethodError)
        from /usr/bin/redis-trib:1295:in `create_cluster_cmd'
        from /usr/bin/redis-trib:1701:in `<main>'

q行 redis-cli 试Q?-c" 参数表示集群Q可q接L机器?001-7010L端口Q?br />[root@host-10-240-79-9 ~]# docker run -it --rm redis:alpine redis-cli -h 10.240.79.8 -p 7006 -c
10.240.79.8:7006> get a
-> Redirected to slot [15495] located at 10.240.79.10:7003
(nil)

用swarm mode开启redis服务比较方便?br />但是Z性能考虑Q应该禁?swarm 的NAT转发和负载均衡?br />研究了下Q暂时还没学会?br />


金庆 2017-10-26 12:08 发表评论
]]>
用docker开启一个时ftpd - սƵ2019|սع//www.pppqb.icu/jinq0123/archive/2017/10/13/215294.html金庆金庆Fri, 13 Oct 2017 12:15:00 GMT//www.pppqb.icu/jinq0123/archive/2017/10/13/215294.html//www.pppqb.icu/jinq0123/comments/215294.html//www.pppqb.icu/jinq0123/archive/2017/10/13/215294.html#Feedback0//www.pppqb.icu/jinq0123/comments/commentRss/215294.html//www.pppqb.icu/jinq0123/services/trackbacks/215294.html用docker开启一个时ftpd

(金庆的专?2017.10)

?docker hub 上搜 ftpd, 扑ֈ星数最多的 pure-ftpd:
https://hub.docker.com/r/stilliard/pure-ftpd/

Ҏ其中的指C开?

1. 启动 docker

docker run -d --name ftpd_server -p 21:21 -p 30000-30009:30000-30009 -e "PUBLICHOST=localhost" stilliard/pure-ftpd:hardened

其中 PUBLICHOST=localhost 应该换成自己的主机名或IP, 不然 passive 无法q接?br />
2. q入 docker, d一?ftp 用户

docker exec -it ftpd_server /bin/bash
pure-pw useradd bob -f /etc/pure-ftpd/passwd/pureftpd.passwd -m -u ftpuser -d /home/ftpusers/bob

pure-pw useradd 会询问密码?br />
如果惌怹保存上传的文Ӟ则需要在docker启动中添加卷映射Q不然docker关闭后文件就不存在了?br />详见其中QKeep user database in a volume




սƵ2019 2017-10-13 20:15 发表评论
]]>