-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
111 lines (110 loc) · 16.5 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>hexo+github搭建个人博客</title>
<url>/2020/11/26/hexo-github%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2/</url>
<content><![CDATA[<p>最近工作中学的新东西挺多的,重开博客记录一下。博客采用hexo+github page的方式搭建。<br>主要参考这篇<a href="https://zhuanlan.zhihu.com/p/26625249">文章</a>,进行操作。<br>用的是这个<a href="https://github.com/wzpan/hexo-theme-freemind">主题</a>的readable配色方案。<br>支持搜索,留言功能,但是顶部的分类和标签按钮不可用。对布局和颜色也不是特别满意,后面有需要再折腾这些吧。</p>
<p>整个过程还算是比较顺利,下面简单记录一下:</p>
<a id="more"></a>
<ol>
<li>配置hexo的_config.yaml和theme的_config.yaml,由于我还深度改了一下theme的一些文案,<del>就单独fork了这个theme的仓库,然后用的是我fork的这个仓库</del>。直接将该仓库添加到当前项目。</li>
<li>hexo g 的原理似乎是把source代码转换之后,放到public目录中。hexo d则是把public的代码复制到.deploy_git目录中,然后在推到xx.github.io仓库,而且似乎是push -f ??</li>
<li>参考<a href="https://www.zhihu.com/question/21193762/answer/79109280">这里的做法</a>将source代码push到该仓库的hexo分支,以期望对source进行管理。</li>
<li>测试,在另一台电脑上clone仓库,checkout到hexo分支,执行npm install之后,就可以用hexo进行管理了。</li>
</ol>
<hr>
<p>2020-11-26 20:00 继续折腾</p>
<ol>
<li>看到另外一篇文章提到nexT主题,发现更好看,果断换。</li>
<li>参考<a href="http://theme-next.iissnan.com/getting-started.html">这篇</a>和<a href="https://theme-next.js.org/docs/getting-started/configuration.html">这篇</a>,发现nexT主题直接通过npm下载安装到node_modules目录,同时配置文件放在外面的做法更加优雅。</li>
<li>但是,freemind那个主题比这个看起更加“技术”一点。[苦笑]</li>
</ol>
]]></content>
<tags>
<tag>hexo</tag>
</tags>
</entry>
<entry>
<title>grpcurl指南</title>
<url>/2020/11/26/grpcurl%E6%8C%87%E5%8D%97/</url>
<content><![CDATA[<p>基于protoreflect包实现的,gRPC服务访问,探查工具</p>
<p>有3种指定gRPC服务schema的方式:</p>
<a id="more"></a>
<ul>
<li><p>服务开启server reflection之后,直接指定服务地址</p>
</li>
<li><p>本地提供服务对应的proto源文件</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">-proto value //指定proto源文件,可以指定多个</span><br><span class="line">-import-path value //指定import依赖的查找路径,可以指定多个</span><br></pre></td></tr></table></figure></li>
<li><p>本地提供服务对应的protoset文件</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">-protoset value //指定protoset,可以指定多个</span><br></pre></td></tr></table></figure>
<p>protoset是描述服务信息的<code>google.protobuf.FileDescriptorSet</code>对象实例。它以二进制格式存储在protoset文件中。生成的方式如下:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">protoc --proto_path=. \</span><br><span class="line"> --descriptor_set_out=myservice.protoset \</span><br><span class="line"> --include_imports \</span><br><span class="line"> my/custom/server/service.proto</span><br></pre></td></tr></table></figure>
<p>在protoc编译过程中已经指定了import path,并且依赖的proto也都编译到了同一个protoset,因此通过这种方式指定schema无需另外指定import path。并且,不需要每次使用都进行proto解析,性能更好。在脚本多次调用时,使用这种方式更加合适。</p>
</li>
</ul>
<ol>
<li><p>服务访问<br>支持包括streaming method在内的所有类型的gRPC接口访问,支持TLS和plain-text方式访问。对于TLS方式,支持指定各种参数。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">grpcurl [-d ''] address method</span><br></pre></td></tr></table></figure>
<p>其中address支持</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">ip:port //ip+端口</span><br><span class="line">host:port //主机名+端口</span><br><span class="line">ip:servicename //ip+知名端口</span><br><span class="line">host:servicename //主机名+知名端口</span><br><span class="line">-unix=true /a/path/to/the/domain/socket //unix套接字</span><br></pre></td></tr></table></figure>
<p>连接方式支持plaintext和TLS方式,TLS支持各种参数指定</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">-plaintext //plaintext模式</span><br><span class="line">//下面都是TLS方式的参数</span><br><span class="line">-insecure //跳过server certificate和domain verification</span><br><span class="line">-authority string //指定 :authority头,和-servername参数一样,在TLS certificate时,替换server name参数。因此不能和-servername同时提供。推荐使用本参数</span><br><span class="line">-servername string //指定TLS certificate时的server name参数</span><br><span class="line">-cacert string //指定根证书</span><br><span class="line">-cert string //指定client certificate(public key)</span><br><span class="line">-key string //指定client private key</span><br></pre></td></tr></table></figure>
<p>其中method必须是fully-qualified,即必须是service+method,格式可以是</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">service/method</span><br><span class="line">service.method</span><br></pre></td></tr></table></figure>
<p>此外通过-d指定请求结构数据,-d选项必须在address 和 method前面。如果是空的请求,可以不需要-d选项。 <code>-d @</code> 指定从标准输入中读取请求数据,这个选项配合<code>jq</code>命令进行管道操作有奇效。</p>
</li>
<li><p>服务探查</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">grpcurl [address/proto/protoset] list [symbol]</span><br><span class="line">grpcurl [address/proto/protoset] describe [symbol]</span><br></pre></td></tr></table></figure>
<p>这里的symbol都必须是fully-qualified名字。list可以带service;describe可以带service,enum,message。<br>list 不带symbol时,输出所有的service;带service时,输出该service的所有method;<br>describe 不带symbol时,也是输出所有的service;带symbol时,输出该symbol的详细信息。</p>
</li>
<li><p>其他选项</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">-H value //指定额外的header, 格式 'name:value'。可以多个。</span><br><span class="line">-reflect-header value //指定服务探查时额外的header</span><br><span class="line">-rpc-header value //指定rpc访问时额外的header</span><br><span class="line">-expand-headers //上述3个选项中的${NAME}格式的header用环境变量进行展开,目的是避免在命令行中暴露密码等敏感信息</span><br><span class="line"></span><br><span class="line">-connect-timeout float //指定连接超时时间, 默认10s</span><br><span class="line">-keepalive-time float //连接空闲时,心跳请求发送间隔时间</span><br><span class="line">-max-time float //单次请求最大处理时间,可以避免grpcurl因为复杂请求或者网络状况差或者错误的stream使用方式而挂住</span><br><span class="line">-max-msg-sz int //单个rsp的最大长度,默认4,194,304(即4M))</span><br><span class="line"></span><br><span class="line">-format string //指定请求数据格式,可选json和text,默认是json</span><br><span class="line">-format-error //发生错误时,用-format指定的格式打印错误</span><br><span class="line"></span><br><span class="line">-allow-unknown-fields //用json格式解析req时,忽略未知的字段</span><br><span class="line">-emit-defaults //用json解析rsp时,忽略默认值</span><br><span class="line">-msg-template //describe子命令探查message时,打印一个message的模板,方便复制使用</span><br><span class="line">-protoset-out string //list或者describe时,把protoset写到指定的文件中</span><br><span class="line">-use-reflection //当指定-proto或者--protoset时,默认是不通过服务reflection进行探查的,通过这个选项可以同时打开本地模式和服务reflection模式</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
</ol>
]]></content>
<tags>
<tag>grpc,protobuf</tag>
</tags>
</entry>
<entry>
<title></title>
<url>/2020/11/26/protobuf%20golang%E7%9A%84%E7%89%88%E6%9C%AC%E9%97%AE%E9%A2%98/</url>
<content><![CDATA[<h2 id="protobuf-golang的版本历史问题"><a href="#protobuf-golang的版本历史问题" class="headerlink" title="protobuf golang的版本历史问题"></a>protobuf golang的版本历史问题</h2><p>v1版<br>模块:github.com/golang/protobuf<br>仓库地址:<a href="https://github.com/golang/protobuf">https://github.com/golang/protobuf</a><br>protoc-gen-go包:github.com/golang/protobuf/protoc-gen-go<br>首次release时间:2010.4.20<br>依赖:从1.4.0开始,依赖v2实现</p>
<p>v2版<br>模块:google.golang.org/protobuf<br>仓库地址:<a href="https://github.com/protocolbuffers/protobuf-go">https://github.com/protocolbuffers/protobuf-go</a><br>protoc-gen-go包:google.golang.org/protobuf/cmd/protoc-gen-go<br>首次release时间:2020.3.2<br>依赖:从go.mod看对v1有依赖,但是只在文件internal/weakdeps/weakdeps.go找到如下依赖代码:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">import _ "github.com/golang/protobuf/proto"</span><br></pre></td></tr></table></figure>
<p>没搞懂这种循环依赖为什么没问题?</p>
<p>根据<a href="https://blog.golang.org/protobuf-apiv2">官方说明</a>,v2具有更好的性能,更清晰的接口以及对反射的一手支持。<br>v1从1.4.0开始,底层其实是对v2的封装,提供v1的接口。<br>v2使用不同的包名,这样兼顾了性能上的收益和使用上的正确性,可以让开发者进行平稳过渡。<br>但是,两个版本由于原理不同,他们各自工具生成的.pb.go只能搭配自己的版本的代码使用。</p>
<p>对于为何不遵循语义化版本的惯例,官方并没有直接说出来。只是说明,v1版的版本号一定不会升到1.20.0,所以可以区分v1和v2。但是又声明会对v1版提供无限期的支持。<br>这里感觉就有点矛盾了?无限期支持,怎么保证不升到1.20.0?</p>
<p>参考文档<br>v1:<br><a href="https://blog.golang.org/protobuf">https://blog.golang.org/protobuf</a><br><a href="https://github.com/golang/protobuf/blob/master/go.mod">https://github.com/golang/protobuf/blob/master/go.mod</a></p>
<p>v2:<br><a href="https://blog.golang.org/protobuf-apiv2">https://blog.golang.org/protobuf-apiv2</a><br><a href="https://github.com/protocolbuffers/protobuf-go/blob/master/go.mod">https://github.com/protocolbuffers/protobuf-go/blob/master/go.mod</a></p>
]]></content>
</entry>
<entry>
<title>理解gitsubmodule</title>
<url>/2020/12/09/%E7%90%86%E8%A7%A3gitsubmodule/</url>
<content><![CDATA[<p>git submodule最好的理解,就是指针。主仓库中,某个特定的目录,在版本管理模型中,不被标识为目录,而是一个指向其他仓库某个具体提交(commit-ish)的指针。<br>因此,对于子仓库目录而言,git不关心里面的具体内容,而只关心他的“指向”,即commit-ish。目录在,则子仓库在;目录被删除,则认为不再引用该子仓库。而目录在,不管里面的内容有还是没有(有,且被修改是另外一回事),都认为对子仓库的引用不变。这里之所以说这里多,是因为这对子仓库添加,拉取,删除的理解非常重要。</p>
<a id="more"></a>
<p>子仓库信息在主仓库的三个地方进行了记录:<br> * .gitmodule文件,这个会被添加进仓库<br> * 子仓库对应的目录,也会被添加到仓库,只是不是以目录的形式,而是一个commit-ish<br> * .git/config文件,很明显,这不会被加入到代码库中<br>三个地方的信息互有联系,又各司其职。下面依次用git submodule的各个子命令来理解这里面的联系和区别,以及他们的职责。</p>
<ol>
<li><code>git submodule </code> 读取HEAD的tree-ish中,子仓库的目录已经对应的commit-ish</li>
<li><code>git submodule add xx.git xx</code> 同时更新上面列到的三个地方</li>
</ol>
<p>在添加子仓库之后,代码库会出现两个新的变更。一个是.gitmodule文件,一个是子仓库目录。提交这两个变更就算是完成了子仓库的添加。</p>
<ol start="3">
<li><code>git clone </code> 拉取仓库代码,明显,.gitmodule和子仓库目录(空)会拉取到本地</li>
<li><code>git submodule init xx</code> 从git的输出来看,这一步是注册子仓库。这里对注册的理解,是把.gitmodule的内容“搬”到.git/config目录中,“搬”加了引号,因为不是简单的拷贝,当子仓库地址是相对文件路径时,需要计算出一个新的路径,可以直接进行子仓库的clone的新地址。</li>
<li><code>git submodule update xx</code> 依据HEAD中记录的子仓库的commit-ish,以及.git/config的子仓库地址,在子仓库的目录中checkout出对应的内容。如果子仓库中已经有代码,似乎什么都不做。如果要放弃那些变更,可以添加-f选项。但是对于未加入代码跟踪的内容,-f也无法移除。似乎只能进入对应目录,执行<code>git clean -fd</code>进行删除。</li>
</ol>
<p>到这里,对于<code>git clone</code> 之后,还需要<code>git submodule init</code>和<code>git submodule update</code>就很好理解了。子仓库代码的管理需要.git/config,因此必须先进行init。拉取子仓库的代码,则是用update命令进行。如果嫌操作麻烦,<code>git clone --recursive</code>选项也提供好了,一条命令执行clone以及全部子仓库的init和update。<br>很明显,init和update并不会产生新的变更,他们只是初始化了当前工作区对子仓库的操作环境,后面就可以通过git submodule的子命令对子仓库进行管理(虽然也没啥可管理的)。</p>
<p>最后,如何删除子仓库就可以推导出来了:<br> * 删除.gitmodule文件中的条目<br> * 删除子仓库对应的目录<br>提交上述两个操作。这样新clone仓库的人,子仓库就彻底从他们视线里消失了。<br>但是还有一些事情需要注意:<br> * .git/config还留着个尾巴,还需要手动删除(尽管这个尾巴似乎不会造成什么问题)<br> * 对于已经clone人来说,pull操作会让他们的子仓库目录变成untracked状态。<br>从上面的理解来看,这里缺少的其实是对.git/config和子目录文件的维护。命令准备好了,就是这个:</p>
<ol start="6">
<li><code>git submodule deinit xx</code> 相当于是init和update的逆向操作,即删除子仓库目录下的所有内容,删除.git/config文件中,子仓库的配置。执行这条操作之后,去除了当前工作区对子仓库的操作环境,无法再通过git submodule 子命令对子仓库进行操作。</li>
</ol>
<p>操作之后发现,先删除子仓库目录,再执行deinit会报找不到的错误。因此,应该先执行deinit,然后再进行删除。<br>对于其他人来说,先deinit再pull固然可以,但是操作上不现实。目前看,只能手动删除子仓库目录和维护.git/config了。</p>
<p>理解完这些之后,剩下的git submodule子命令就好办了。啃<a href="https://git-scm.com/docs/git-submodule">官方文档</a>也更带劲了。</p>
]]></content>
<tags>
<tag>git,gitsubmodule</tag>
</tags>
</entry>
</search>