<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cong</title><link>https://blog.cong.moe/</link><description>Recent content on Cong</description><generator>Hugo</generator><language>en</language><copyright>Copy, _right?_ :thinking_face:</copyright><lastBuildDate>Tue, 17 Jun 2025 16:51:00 +0800</lastBuildDate><atom:link href="https://blog.cong.moe/index.xml" rel="self" type="application/rss+xml"/><item><title>Books</title><link>https://blog.cong.moe/books/</link><pubDate>Tue, 16 Jul 2019 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/books/</guid><description/></item><item><title>About</title><link>https://blog.cong.moe/about/</link><pubDate>Mon, 02 Jul 2018 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/about/</guid><description/></item><item><title>聊聊AI和MCP</title><link>https://blog.cong.moe/post/2025-06-17-ai-and-mcp/</link><pubDate>Tue, 17 Jun 2025 16:51:00 +0800</pubDate><guid>https://blog.cong.moe/post/2025-06-17-ai-and-mcp/</guid><description/></item><item><title>一种 golang 开发工具管理方式</title><link>https://blog.cong.moe/post/2022-12-31-golang-dev-tools/</link><pubDate>Sat, 31 Dec 2022 16:51:00 +0800</pubDate><guid>https://blog.cong.moe/post/2022-12-31-golang-dev-tools/</guid><description/></item><item><title>Dapr 源码解析 | Pluggable Components</title><link>https://blog.cong.moe/post/2022-10-06-dapr-pluggable-components/</link><pubDate>Thu, 06 Oct 2022 17:40:39 +0800</pubDate><guid>https://blog.cong.moe/post/2022-10-06-dapr-pluggable-components/</guid><description>&lt;p>对于 Dapr 这种基础组件, 可扩展性是非常重要的一个特性. Dapr 最主要的特性和目标就是为用户提供不同场景下的标准化 API 屏蔽依赖中间件底层, 从而降低用户开发成本增加增强软件可移植性. 所以 Dapr 底层中间件支持越多也就意味着适用的范围越广. 本文来分析 Dapr 即将发布的 1.9 版本的新特性 &amp;ndash; &lt;code>Pluggable Components&lt;/code>, 这是一个用户扩展 component 的完整解决方案.&lt;/p></description></item><item><title>Grpc Proxy</title><link>https://blog.cong.moe/post/2022-09-14-grpc-proxy/</link><pubDate>Wed, 14 Sep 2022 10:37:51 +0800</pubDate><guid>https://blog.cong.moe/post/2022-09-14-grpc-proxy/</guid><description>&lt;p>对于 http proxy 大家非常熟悉, 各式各样的中间件都能简单支持. 但是在反向代理这个场景下, 同样基于 http2 协议的 grpc 却没法像 http 那样随意使用中间件做代理, 很重要的一点原因是: grpc 基于长连接, 普通的反代没法做到调用级别的负载均衡. 今天就来简单探讨下应用层代理的实现.&lt;/p></description></item><item><title>Grpc 泛化调用</title><link>https://blog.cong.moe/post/2022-09-04-grpc-generic-call/</link><pubDate>Sun, 04 Sep 2022 23:10:36 +0800</pubDate><guid>https://blog.cong.moe/post/2022-09-04-grpc-generic-call/</guid><description>&lt;p>一般来说 Grpc 使用时, 只需要在 proto 文件中指定好 message 和 service 类型, pb 就能帮我们生成好对应语言的桩代码, 对于服务端只需要 implement 对应的 handler 接口, 对于客户端直接生成了开箱即用的客户端代码. 这也是 Grpc 多语言移植性强的原因. 今天简单介绍下 Grpc 的调用逻辑, 最终做到仅需要 pb 生成的 message 类型实现服务端和客户端逻辑.&lt;/p></description></item><item><title>Grpc ClientConnInterface 扩展</title><link>https://blog.cong.moe/post/2022-08-04-grpc-client-conn-interface-ext/</link><pubDate>Thu, 04 Aug 2022 14:50:36 +0800</pubDate><guid>https://blog.cong.moe/post/2022-08-04-grpc-client-conn-interface-ext/</guid><description>&lt;p>对于 Grpc go 用户来说最熟悉的扩展方式肯定是拦截器, 正如上文中所说, 但是某些场景下使用仍然需要其他扩展方式. 本文简单介绍下 grpc client 端的 &lt;code>ClientConnInterface&lt;/code> 扩展.&lt;/p></description></item><item><title>Grpc client 拦截器 CallOption 扩展</title><link>https://blog.cong.moe/post/2022-07-21-grpc-interceptor-call-option/</link><pubDate>Thu, 21 Jul 2022 16:26:40 +0800</pubDate><guid>https://blog.cong.moe/post/2022-07-21-grpc-interceptor-call-option/</guid><description>&lt;p>本文简单讲述 Grpc client 拦截器 CallOption 扩展.&lt;/p></description></item><item><title>Dapr 源码解析 | Distribute Lock</title><link>https://blog.cong.moe/post/2022-06-23-dapr-distribute-lock-api/</link><pubDate>Thu, 23 Jun 2022 20:03:25 +0800</pubDate><guid>https://blog.cong.moe/post/2022-06-23-dapr-distribute-lock-api/</guid><description>&lt;p>Dapr 1.18 版本即将发布, 本文介绍 1.18 版本新功能 &lt;code>Distribute Lock Api&lt;/code> 分布式锁功能.&lt;/p></description></item><item><title>Kitex 服务发现与负载均衡</title><link>https://blog.cong.moe/post/2022-06-14-kitex-resolver-balancer/</link><pubDate>Thu, 16 Jun 2022 21:28:01 +0800</pubDate><guid>https://blog.cong.moe/post/2022-06-14-kitex-resolver-balancer/</guid><description>&lt;p>Kitex 是字节开源的高性能, 强可扩展 的 Golang 微服务 RPC 框架. 之前写过 
 
 &lt;a href="https://blog.cong.moe/post/2021-03-06-grpc-go-discovery-lb/">gRPC-go 的服务发现和负载均衡源码分析&lt;/a>, 本文分析下 Kitex 源码, 对比下两者的差异.&lt;/p></description></item><item><title>现代化的 Protobuf 构建工具 buf</title><link>https://blog.cong.moe/post/2022-05-18-buf-tool/</link><pubDate>Wed, 18 May 2022 16:06:15 +0800</pubDate><guid>https://blog.cong.moe/post/2022-05-18-buf-tool/</guid><description>&lt;p>虽然 Protobuf 已经是使用非常广泛的 IDL(interface description language), 但是对它熟悉的人并没有那么多. 因为它在序列化层面上比 JSON 难很多, 并且还有很多复杂的工具链. 本文介绍一下现代化的 Protobuf 构建工具 &lt;code>buf&lt;/code>.&lt;/p></description></item><item><title>gRPC Go 服务发现与负载均衡(更新版)</title><link>https://blog.cong.moe/post/2021-03-06-grpc-go-discovery-lb/</link><pubDate>Wed, 11 May 2022 19:01:06 +0800</pubDate><guid>https://blog.cong.moe/post/2021-03-06-grpc-go-discovery-lb/</guid><description>&lt;p>&lt;a href="https://grpc.io" target="_blank" rel="noreferrer">gRPC&lt;/a> 是 Google 开源的一款高性能, 支持多种语言的 RPC 框架. 已经被广泛用于集群内服务间调用. 为了大规模流量和避免单点故障, 所以服务往往是部署多实例的, 于是负载均衡就是硬需求了.&lt;/p></description></item><item><title>Dapr 源码解析 | Resiliency</title><link>https://blog.cong.moe/post/2022-04-08-dapr-resiliency/</link><pubDate>Fri, 08 Apr 2022 22:46:30 +0800</pubDate><guid>https://blog.cong.moe/post/2022-04-08-dapr-resiliency/</guid><description/></item><item><title>Ristretto 高性能 go 语言缓存</title><link>https://blog.cong.moe/post/2022-03-19-ristretto-high-performance-go-cache/</link><pubDate>Sat, 19 Mar 2022 19:03:50 +0800</pubDate><guid>https://blog.cong.moe/post/2022-03-19-ristretto-high-performance-go-cache/</guid><description/></item><item><title>北大肖臻《区块链技术与应用》公开课学习笔记</title><link>https://blog.cong.moe/post/2022-01-13-blockchain-xiaozhen/</link><pubDate>Thu, 13 Jan 2022 14:07:07 +0800</pubDate><guid>https://blog.cong.moe/post/2022-01-13-blockchain-xiaozhen/</guid><description>&lt;p>本文是学习北京大学肖臻老师《区块链技术与应用》公开课时总结出的一些简单笔记, 也是在公司内部分享的资料, 并且在最后增加了本人学习智能合约和 NFT 的一些资料. 强烈建议想要了解区块链技术的朋友们去看肖老师公开课视频, 肖老师是带着大家一步一步推导出各种数据结构和技术方案的选用, 让你知其然并知其所以然.&lt;/p></description></item><item><title>Dapr | State Store Encryption</title><link>https://blog.cong.moe/post/2022-01-11-dapr-state-store-encryption/</link><pubDate>Tue, 11 Jan 2022 18:05:39 +0800</pubDate><guid>https://blog.cong.moe/post/2022-01-11-dapr-state-store-encryption/</guid><description>&lt;p>之前源码系列文章讲到过, Dapr 可以对集群内部提供 &lt;code>kv store&lt;/code> (键值存储) 的功能. 但是很多时候我们希望有更好的安全性, 因为存储功能总是需要外部软件提供, 所以 dapr 提供了键值存储自动加密的功能.&lt;/p></description></item><item><title>gRPC 扩展错误处理</title><link>https://blog.cong.moe/post/2021-12-29-grpc-richer-error-handling/</link><pubDate>Wed, 29 Dec 2021 16:15:57 +0800</pubDate><guid>https://blog.cong.moe/post/2021-12-29-grpc-richer-error-handling/</guid><description>&lt;p>开发过程中我们会花费大量时间和错误处理打交道, HTTP 协议错误处理基本会通过 status code 和请求响应(自定义消息) 来传递错误, 而 gRPC 这边错误处理就没有 HTTP 这么好控制.&lt;/p></description></item><item><title>gRPC 扩展类型的使用</title><link>https://blog.cong.moe/post/2021-12-28-grpc-advance-types/</link><pubDate>Tue, 28 Dec 2021 14:24:16 +0800</pubDate><guid>https://blog.cong.moe/post/2021-12-28-grpc-advance-types/</guid><description>&lt;p>gRPC 使用 protobuf 格式对消息进行编码, 基本类型都会映射到各种语言的类型. 为了丰富表达能力, 官方基于基本类型封装了一些类型, 例如: &lt;code>Timestamp&lt;/code>, &lt;code>Duration&lt;/code>, &lt;code>Any&lt;/code>, &lt;code>Struct&lt;/code>.&lt;/p></description></item><item><title>一点面试感想</title><link>https://blog.cong.moe/post/2021-12-23-interview/</link><pubDate>Thu, 23 Dec 2021 10:44:34 +0800</pubDate><guid>https://blog.cong.moe/post/2021-12-23-interview/</guid><description/></item><item><title>Dapr 源码解析 | Name Resolution</title><link>https://blog.cong.moe/post/2021-11-25-dapr-name-resolution/</link><pubDate>Thu, 25 Nov 2021 15:40:17 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-25-dapr-name-resolution/</guid><description>&lt;p>Name resolution 解决的是微服务中的服务发现问题, dapr 中服务的标识符为 &lt;code>app-id&lt;/code> , 服务间调用是通过 &lt;code>app-id&lt;/code> 来确定目标服务的. 所以就需要 &lt;code>app-id&lt;/code> 到真实服务地址的映射.&lt;/p>
&lt;p>dapr 服务发现其实就是单纯的 gRPC 服务发现, 因为服务间调用是通过 dapr sidecar 转发的, 而 sidecar 之间是通过 gRPC 交流的, 所以最终就变成了 gRPC 服务发现了.&lt;/p></description></item><item><title>Dapr 源码解析 | Operator</title><link>https://blog.cong.moe/post/2021-11-24-dapr-operator/</link><pubDate>Wed, 24 Nov 2021 16:52:50 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-24-dapr-operator/</guid><description>&lt;p>dapr operator 是 dapr 的几个独立软件之一.&lt;/p>
&lt;p>operator 是对 k8s 功能的扩展, 可以用来扩展 CRD 做更精细化的事情, 例如: 自动化运维部署高可用数据库, 因为它是用代码解决问题而不是配置.&lt;/p></description></item><item><title>Dapr 源码解析 | Sidecar Injector</title><link>https://blog.cong.moe/post/2021-11-23-dapr-sidecar-injector/</link><pubDate>Tue, 23 Nov 2021 18:58:34 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-23-dapr-sidecar-injector/</guid><description>&lt;p>dapr sidecar injector 是 dapr 几个独立软件之一, 功能是在 k8s 环境为用户服务注入 dapr runtime sidecar 容器.&lt;/p></description></item><item><title>Dapr 源码解析 | 可观测性</title><link>https://blog.cong.moe/post/2021-11-23-dapr-observability/</link><pubDate>Tue, 23 Nov 2021 14:34:46 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-23-dapr-observability/</guid><description>&lt;p>Observability(可观测性)一般指 &lt;code>Logging&lt;/code>, &lt;code>Metrics&lt;/code> 和 &lt;code>Tracing&lt;/code> .&lt;/p></description></item><item><title>Dapr 源码解析 | mTLS</title><link>https://blog.cong.moe/post/2021-11-19-dapr-mtls/</link><pubDate>Fri, 19 Nov 2021 16:34:47 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-19-dapr-mtls/</guid><description>&lt;p>&lt;a href="https://en.wikipedia.org/wiki/Mutual_authentication" target="_blank" rel="noreferrer">mutual authentication TLS&lt;/a> 是 dapr 提供的开箱即用的安全功能, 为 dapr sidecar 之间的流量进行加密.&lt;/p>
&lt;p>&lt;strong>注意&lt;/strong>: 本文不会讲述 mTLS 技术原理和相关证书生成细节, 如需了解请自行查找资料(主要是我自己也不懂).&lt;/p></description></item><item><title>Dapr 源码解析 | 服务间调用</title><link>https://blog.cong.moe/post/2021-11-10-dapr-service-invocation/</link><pubDate>Wed, 10 Nov 2021 18:10:38 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-10-dapr-service-invocation/</guid><description>&lt;p>Service Invocation 是 dapr 对外提供的最基础功能, 也就是服务间调用. 另外别的一些功能也会间接使用它.&lt;/p></description></item><item><title>Dapr 源码解析 | 发布订阅</title><link>https://blog.cong.moe/post/2021-11-05-dapr-pubsub/</link><pubDate>Fri, 05 Nov 2021 18:58:13 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-05-dapr-pubsub/</guid><description>&lt;p>发布订阅在 dapr 既是一个 component 又是一个 building block.&lt;/p>
&lt;p>dapr 的 pubsub 构建块可以对外提供一个&lt;code>最少一次送达保证&lt;/code>的发布订阅 API, 可以支持多种软件作为 message broker. 使用这个功能我们的服务就需要引入繁杂的 message broker sdk 和管理消息队列连接.&lt;/p></description></item><item><title>Dapr 源码解析 | 组件模块</title><link>https://blog.cong.moe/post/2021-11-02-dapr-component/</link><pubDate>Tue, 02 Nov 2021 15:50:51 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-02-dapr-component/</guid><description>&lt;p>&lt;code>Components&lt;/code> 是 dapr 抽象出来的提供某种特定功能的可插拔组件, 为 dapr 或者 building blocks 所使用.&lt;/p>
&lt;p>例如: 服务发现功能就是 dapr 的一个 component, 它的提供者可以使 mDNS, Kubernetes 和 consul, dapr 允许用户根据需求选择使用提供者的某种.&lt;/p></description></item><item><title>Dapr 源码解析 | 配置模块</title><link>https://blog.cong.moe/post/2021-11-01-dapr-configuration/</link><pubDate>Mon, 01 Nov 2021 14:10:29 +0800</pubDate><guid>https://blog.cong.moe/post/2021-11-01-dapr-configuration/</guid><description>&lt;p>本文源码选用 dapr 1.4.3 &lt;a href="https://github.com/zcong1993/dapr-1/tree/learn-1.4.3" target="_blank" rel="noreferrer">https://github.com/zcong1993/dapr-1/tree/learn-1.4.3&lt;/a>&lt;/p></description></item><item><title>Dapr 源码解析 | 项目总览</title><link>https://blog.cong.moe/post/2021-10-28-dapr-project-overview/</link><pubDate>Thu, 28 Oct 2021 17:58:42 +0800</pubDate><guid>https://blog.cong.moe/post/2021-10-28-dapr-project-overview/</guid><description>&lt;p>本文源码选用 dapr 1.4.3 &lt;a href="https://github.com/zcong1993/dapr-1/tree/learn-1.4.3" target="_blank" rel="noreferrer">https://github.com/zcong1993/dapr-1/tree/learn-1.4.3&lt;/a>&lt;/p></description></item><item><title>Dapr 源码解析 | 基本介绍</title><link>https://blog.cong.moe/post/2021-10-26-dapr-overview/</link><pubDate>Tue, 26 Oct 2021 19:22:58 +0800</pubDate><guid>https://blog.cong.moe/post/2021-10-26-dapr-overview/</guid><description/></item><item><title>服务端超时控制</title><link>https://blog.cong.moe/post/2021-10-18-server-timeout-handler/</link><pubDate>Mon, 18 Oct 2021 19:01:32 +0800</pubDate><guid>https://blog.cong.moe/post/2021-10-18-server-timeout-handler/</guid><description>&lt;p>服务端的资源是有限的, 处理已经超时的请求是没任何意义的. 超时控制是保障服务稳定的一道重要防线, 本质是快速失败节省资源.&lt;/p></description></item><item><title>Node Grpc Health Check</title><link>https://blog.cong.moe/post/2021-09-24-node-grpc-health-check/</link><pubDate>Fri, 24 Sep 2021 11:43:56 +0800</pubDate><guid>https://blog.cong.moe/post/2021-09-24-node-grpc-health-check/</guid><description>&lt;p>健康检查往往用来判断服务是否能够对外正常提供服务, 例如: k8s 中就会用就绪检查和健康检查来判断是否需要重启/剔除 pod.&lt;/p>
&lt;p>之前文章也介绍过 gRPC 是客户端负载均衡(简单来说因为长连接基于连接的负载均衡没太大意义), 所以客户端更需要主动感知服务端健康状态的能力. 因此 gRPC 提出了 &lt;a href="https://github.com/grpc/grpc/blob/master/doc/health-checking.md" target="_blank" rel="noreferrer">GRPC Health Checking Protocol&lt;/a>.&lt;/p></description></item><item><title>使用 VictoriaMetrics 替换 Prometheus</title><link>https://blog.cong.moe/post/2021-08-23-use-victoria-metrics-replace-prometheus/</link><pubDate>Mon, 23 Aug 2021 15:33:00 +0800</pubDate><guid>https://blog.cong.moe/post/2021-08-23-use-victoria-metrics-replace-prometheus/</guid><description>&lt;p>&lt;a href="https://prometheus.io" target="_blank" rel="noreferrer">Prometheus&lt;/a> 早已成为服务监控标准, 而监控也是集群可观测性中的重要一环, 也是比较容易落地的一环. Prometheus + Grafana 已经是最为流行的监控方案.&lt;/p></description></item><item><title>OpenTelemetry-JS Tracing 实现详解</title><link>https://blog.cong.moe/post/2021-07-23-opentelemetry-js/</link><pubDate>Fri, 23 Jul 2021 18:05:25 +0800</pubDate><guid>https://blog.cong.moe/post/2021-07-23-opentelemetry-js/</guid><description>&lt;h2 id="1-opentelemetry-是什么" class="relative group">1. OpenTelemetry 是什么? &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#1-opentelemetry-%e6%98%af%e4%bb%80%e4%b9%88" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;p>&lt;a href="https://opentelemetry.io" target="_blank" rel="noreferrer">OpenTelemetry&lt;/a> 是由 &lt;a href="https://opentracing.io" target="_blank" rel="noreferrer">OpenTracing&lt;/a> 和 &lt;a href="https://opencensus.io" target="_blank" rel="noreferrer">OpenCensus&lt;/a> 合并而成, 前身之一 OpenTracing 则是 CNCF 的一个 tracing 方向的孵化项目. OpenTelemetry 对自己的定义是一个大而全的可观测性框架.&lt;/p></description></item><item><title>写了个简单的多设备文本分享工具</title><link>https://blog.cong.moe/post/2021-07-09-text-sharing/</link><pubDate>Fri, 09 Jul 2021 15:18:30 +0800</pubDate><guid>https://blog.cong.moe/post/2021-07-09-text-sharing/</guid><description>&lt;p>多设备共享, 发送文本这个难题困扰我很久了, 一直找不到简单, 单纯, 安全, 好用的工具. 所以我就自己写了个简单的小工具.&lt;/p></description></item><item><title>使用 dbmate 管理数据库 migration</title><link>https://blog.cong.moe/post/2021-06-15-use-dbmate-manage-db-migration/</link><pubDate>Tue, 15 Jun 2021 19:07:31 +0800</pubDate><guid>https://blog.cong.moe/post/2021-06-15-use-dbmate-manage-db-migration/</guid><description/></item><item><title>使用 esbuild 加速 ts 构建</title><link>https://blog.cong.moe/post/2021-06-06-esbuild-tsc/</link><pubDate>Sun, 06 Jun 2021 23:40:17 +0800</pubDate><guid>https://blog.cong.moe/post/2021-06-06-esbuild-tsc/</guid><description/></item><item><title>滑动窗口计数器</title><link>https://blog.cong.moe/post/2021-06-03-rolling-window/</link><pubDate>Thu, 03 Jun 2021 11:47:21 +0800</pubDate><guid>https://blog.cong.moe/post/2021-06-03-rolling-window/</guid><description/></item><item><title>分布式全局唯一 ID 生成</title><link>https://blog.cong.moe/post/2021-04-13-gulid/</link><pubDate>Tue, 13 Apr 2021 19:03:05 +0800</pubDate><guid>https://blog.cong.moe/post/2021-04-13-gulid/</guid><description/></item><item><title>inlets + caddy 实现安全内网穿透隧道</title><link>https://blog.cong.moe/post/2021-03-26-inlets-caddy-secure-tunnel/</link><pubDate>Fri, 26 Mar 2021 18:37:48 +0800</pubDate><guid>https://blog.cong.moe/post/2021-03-26-inlets-caddy-secure-tunnel/</guid><description>&lt;p>对接外部产品回调(callback)类需求时, 如果将我们开发中的服务暴露到公网, 对接调试会省很大力气. 因此 &lt;a href="https://github.com/inlets/inlets" target="_blank" rel="noreferrer">inlets&lt;/a> 就是我们需要的轻量级内网穿透工具.&lt;/p></description></item><item><title>在 Typescript 中使用 gRPC</title><link>https://blog.cong.moe/post/2021-03-16-grpc-on-typescript/</link><pubDate>Tue, 16 Mar 2021 15:32:21 +0800</pubDate><guid>https://blog.cong.moe/post/2021-03-16-grpc-on-typescript/</guid><description>&lt;p>gRPC 是一个高性能, 支持多种语言的 RPC 框架, 官方已经支持了 NodeJS 语言. 而 Typescript 作为 JavaScript 的超集, 可以提高 js 代码的可维护性, 并且代码提示很不错, 已在 js 市场占据了很大份额. 本文简单介绍下 gRPC 在 Typescript 中如何使用.&lt;/p></description></item><item><title>在 k8s 中使用 gRPC Go 服务发现</title><link>https://blog.cong.moe/post/2021-03-15-grpc-go-discovery-in-k8s/</link><pubDate>Mon, 15 Mar 2021 16:51:07 +0800</pubDate><guid>https://blog.cong.moe/post/2021-03-15-grpc-go-discovery-in-k8s/</guid><description>&lt;p>k8s 已经成为云时代云平台的一等公民, 本文介绍下如何在 k8s 中使用 grpc 服务发现. 如果没看上篇文章, 请先查看上篇文章 
 
 &lt;a href="https://blog.cong.moe/post/2021-03-06-grpc-go-discovery-lb/">gRPC Go 服务发现与负载均衡&lt;/a>.&lt;/p></description></item><item><title>NodeJS 新特性 AbortController</title><link>https://blog.cong.moe/post/2021-03-02-node-abort-controller/</link><pubDate>Tue, 02 Mar 2021 23:25:10 +0800</pubDate><guid>https://blog.cong.moe/post/2021-03-02-node-abort-controller/</guid><description>&lt;p>NodeJS &lt;code>15.0.0&lt;/code> 版本增加了一个很有意思的新特性 &lt;a href="https://nodejs.org/dist/latest-v15.x/docs/api/globals.html#globals_class_abortcontroller" target="_blank" rel="noreferrer">AbortController&lt;/a>, 主要是用来撤销某些正在运行的 &lt;code>Promise&lt;/code>.&lt;/p></description></item><item><title>leetcode-tool 一个让你更方便刷题的工具</title><link>https://blog.cong.moe/post/2020-11-30-leetcode_tool/</link><pubDate>Mon, 30 Nov 2020 21:51:01 +0800</pubDate><guid>https://blog.cong.moe/post/2020-11-30-leetcode_tool/</guid><description>&lt;p>现在程序员招聘越来越注重算法之类的考核了, 所以刷算法题也就成了程序员日常生活的一部分了. 今天介绍一个工具: &lt;a href="https://github.com/zcong1993/leetcode-tool" target="_blank" rel="noreferrer">leetcode-tool&lt;/a>, 帮助大家更轻松的刷题, 沉淀知识.&lt;/p></description></item><item><title>构建高质量的 Docker 镜像</title><link>https://blog.cong.moe/post/2020-08-20-docker-images/</link><pubDate>Thu, 20 Aug 2020 15:13:12 +0800</pubDate><guid>https://blog.cong.moe/post/2020-08-20-docker-images/</guid><description>&lt;p>docker 的出现改写了服务部署规则, 也是 k8s 的基础. 而镜像是 docker 运行 container 的基础. 如何构建高质量的镜像呢?&lt;/p></description></item><item><title>使用 loki 作为 k8s 应用日志收集器(下篇)</title><link>https://blog.cong.moe/post/2020-08-08-use_loki_as_k8s_log_collector_2/</link><pubDate>Sat, 08 Aug 2020 00:40:58 +0800</pubDate><guid>https://blog.cong.moe/post/2020-08-08-use_loki_as_k8s_log_collector_2/</guid><description>&lt;p>
 
 &lt;a href="https://blog.cong.moe/post/2020-07-27-use_loki_as_k8s_log_collector/">上篇文章&lt;/a> 介绍了日志收集的背景和 loki 的优点, 真正部署的时候基本是一键的感觉没什么技术含量(虽然开箱即用部署简单是优势), 本章将介绍如何使用它来收集容器内日志文件.&lt;/p></description></item><item><title>使用 loki 作为 k8s 应用日志收集器(上篇)</title><link>https://blog.cong.moe/post/2020-07-27-use_loki_as_k8s_log_collector/</link><pubDate>Mon, 03 Aug 2020 00:39:39 +0800</pubDate><guid>https://blog.cong.moe/post/2020-07-27-use_loki_as_k8s_log_collector/</guid><description>&lt;p>应用日志是我们的好朋友, 不仅在排查错误时必不可少而且还有助于我们了解应用运行状态. 虽然现在到了 K8S 的时代, 但是它并没有提供一个开箱即用的日志解决方案, 那么我们该怎么做呢?&lt;/p></description></item><item><title>Sync Github Fork</title><link>https://blog.cong.moe/post/2020-07-28-sync_github_fork/</link><pubDate>Tue, 28 Jul 2020 15:48:55 +0800</pubDate><guid>https://blog.cong.moe/post/2020-07-28-sync_github_fork/</guid><description>&lt;p>&lt;a href="https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-forks" target="_blank" rel="noreferrer">Github Fork&lt;/a> 是一个很常见的操作, 常用来做自己的定制化开发, 或者做修改之后提交(pr)回上游仓库.&lt;/p>
&lt;p>然而, 有时候我们经常需要自己的 fork 版本和上游更新保持一致. 例如最近很火的这个项目 &lt;a href="https://github.com/anuraghazra/github-readme-stats" target="_blank" rel="noreferrer">anuraghazra/github-readme-stats&lt;/a>, 我们需要部署自己的服务, 这时就希望我们的 fork 版本同步更新上游的新功能和 bug fix. 那么怎么做呢?&lt;/p></description></item><item><title>浅谈 k8s pod 亲和性配置</title><link>https://blog.cong.moe/post/2020-07-13-assign-pod-node/</link><pubDate>Mon, 13 Jul 2020 00:52:46 +0800</pubDate><guid>https://blog.cong.moe/post/2020-07-13-assign-pod-node/</guid><description>&lt;p>kubernetes 的出现极大地简化了我们编排分配应用的负担，但是默认条件下，k8s 只能够帮我们做资源上的调度协调。那么如何让 k8s 更 “懂” 我们，能够在满足我们某些特殊需求的前提下进行资源上的自动调度呢？&lt;/p></description></item><item><title>使用 prometheus 监控应用</title><link>https://blog.cong.moe/post/2020-07-03-use_prometheus/</link><pubDate>Fri, 03 Jul 2020 14:02:19 +0800</pubDate><guid>https://blog.cong.moe/post/2020-07-03-use_prometheus/</guid><description>&lt;p>生产环境的应用往往都需要 7x24 小时高强度服务用户, 上线之后如果想睡好觉, 就需要知晓应用运行的某些状态指标, 以此判断应用是否健康, 这也就是监控的意义之一.&lt;/p>
&lt;p>当然还可以有更高的追求, 例如: 接口 QPS, 接口的错误率, 接口的 90 分位响应时间等等, 这些可以帮助我们更好的了解应用的运行状态, 更好得确立优化方向.&lt;/p>
&lt;p>于是接下来介绍一下开源监控组件 &lt;a href="https://prometheus.io" target="_blank" rel="noreferrer">prometheus&lt;/a>&lt;/p></description></item><item><title>一个可以根据 mongoose schema 生成 model 类型的工具</title><link>https://blog.cong.moe/post/2020-06-17-auto_generate_mongoose_model_types/</link><pubDate>Wed, 17 Jun 2020 15:12:21 +0800</pubDate><guid>https://blog.cong.moe/post/2020-06-17-auto_generate_mongoose_model_types/</guid><description>&lt;p>MongoDB 在 NodeJS 社区有着非常广泛的使用. 虽然灵活是 MongoDB 的一大优势, 但是真正业务中不希望它 &amp;lsquo;过于灵活&amp;rsquo;, 因此一般都会搭配 mongoose 来使用, 所以基本也会定义 &lt;code>Schema&lt;/code>.&lt;/p>
&lt;p>由于 mongoose 出现很早, 它是以 Object 的形式来定义 Schema. 但是随着 Typescript 的流行, ts 和 mongoose 结合使用时, 定义 Model 类型时不能直接使用 Schema 类型, 所以我们一般都要根据对应的 Schema 类型再写一个类型: &lt;code>type UserModel = mongoose.Model&amp;lt;UserType&amp;gt;&lt;/code>.&lt;/p>
&lt;p>综上, 我决定写一个自动化工具来解放双手, 减少人工失误.&lt;/p></description></item><item><title>NodeJS 如何实现 "ThreadLocal"</title><link>https://blog.cong.moe/post/2020-02-01-nodejs-threadlocal/</link><pubDate>Sat, 01 Feb 2020 15:52:04 +0800</pubDate><guid>https://blog.cong.moe/post/2020-02-01-nodejs-threadlocal/</guid><description>&lt;p>提起 &lt;code>ThreadLocal&lt;/code> 这个词，线程局部存储，Java 的朋友们可能很熟悉。从名字看就可以看出来应该是多线程语言的 “特权”，大家都知道 NodeJS 是单线程的，那么它与 NodeJS 又有什么关系呢？&lt;/p></description></item><item><title>测试环境 K8S 如何部署数据库</title><link>https://blog.cong.moe/post/2020-01-30-k8s-deploy-stateful-app/</link><pubDate>Thu, 30 Jan 2020 23:53:10 +0800</pubDate><guid>https://blog.cong.moe/post/2020-01-30-k8s-deploy-stateful-app/</guid><description>&lt;p>之前文章中也提到，k8s 已经越来越普及，已经变得接近傻瓜式了，无论是生产环境或是开发环境配合别的系统做 CI/CD，相信大家或多或少也都用到了一些。那么，如果让你在测试环境搭建一个数据库，你们怎么做呢？&lt;/p></description></item><item><title>Ts typings 包版本冲突问题</title><link>https://blog.cong.moe/post/2020-01-06-ts-typings-packages-conflict/</link><pubDate>Mon, 06 Jan 2020 19:44:35 +0800</pubDate><guid>https://blog.cong.moe/post/2020-01-06-ts-typings-packages-conflict/</guid><description>&lt;p>对于 Node 开发者来说, 早已习惯成千上万的项目依赖, 但是过多的依赖会导致依赖变成网状而且会带来 &lt;code>版本冲突&lt;/code>, 虽然 npm 会帮助我们处理这些问题, 但是如果是 typings 包冲突的话, 编译基本就会报错了, 我们来看看为什么吧.&lt;/p></description></item><item><title>阿里云 K8S 的角色权限问题</title><link>https://blog.cong.moe/post/ali-k8s-role/</link><pubDate>Mon, 28 Oct 2019 17:48:09 +0800</pubDate><guid>https://blog.cong.moe/post/ali-k8s-role/</guid><description>&lt;p>随着 k8s 的成熟, 越来越多的云平台都集成了 k8s, 基本都成了半傻瓜式操作. 我们公司用的是阿里云平台, 但是在进行授权管理时遇到了一些与预想不一致的情况.&lt;/p></description></item><item><title>使用 Github Actions 做一个免费的 Task Runner</title><link>https://blog.cong.moe/post/github-actions/</link><pubDate>Sun, 15 Sep 2019 21:43:52 +0800</pubDate><guid>https://blog.cong.moe/post/github-actions/</guid><description>&lt;p>有时候我们需要周期性的执行一些脚本，有时候需要在有必要的时候通过触发执行一些脚本。我们有点追求，需要知道任务执行的时间，执行的状态，执行的日志。这么一整套其实是个挺复杂的需求，那么有没有现成的，优雅的解决方案呢？答案是有！那就是 &lt;code>Github Actions&lt;/code>！&lt;/p></description></item><item><title>访问控制利器 Casbin</title><link>https://blog.cong.moe/post/casbin/</link><pubDate>Thu, 29 Aug 2019 22:30:17 +0800</pubDate><guid>https://blog.cong.moe/post/casbin/</guid><description>&lt;p>往往我们会有需要访问控制的需要，比如后台系统需要根据部门来控制权限。&lt;code>k8s&lt;/code> 使用 &lt;code>RBAC&lt;/code> 作为访问控制策略，使用过的应该知道。那么怎么样才能写出这么优雅的访问控制器呢？有什么成熟的框架呢？答案是：有！那就是今天的主角 &lt;a href="https://casbin.org/en/" target="_blank" rel="noreferrer">Casbin&lt;/a>!&lt;/p></description></item><item><title>Http Middleware</title><link>https://blog.cong.moe/post/http-middleware/</link><pubDate>Sun, 28 Jul 2019 01:27:39 +0800</pubDate><guid>https://blog.cong.moe/post/http-middleware/</guid><description>&lt;p>接触过 web 服务编程的人对中间件无人不知无人不晓，那么这么常见的东西本质是什么样子的呢？下面我们简单了解一下。&lt;/p></description></item><item><title>Node Singleflight</title><link>https://blog.cong.moe/post/node-singleflight/</link><pubDate>Fri, 26 Jul 2019 00:59:12 +0800</pubDate><guid>https://blog.cong.moe/post/node-singleflight/</guid><description>&lt;p>什么是 &lt;code>singleflight&lt;/code> ？&lt;/p>
&lt;p>这里引用 &lt;code>go&lt;/code> 语言的描述：&lt;code>singleflight&lt;/code> 为重复函数调用提供抑制机制，通俗的讲就是短时间内同时重复调用同一函数时，确保函数只被调用一次，别的调用 “等待” 调用完成并返回相同结果。&lt;/p></description></item><item><title>做一个短链接服务</title><link>https://blog.cong.moe/post/short-url/</link><pubDate>Sun, 24 Mar 2019 00:25:01 +0800</pubDate><guid>https://blog.cong.moe/post/short-url/</guid><description>&lt;p>分享链接是一个很常见的需求，对于软件开发者，我们往往需要追踪一下用户行为，所以往往 url 会带有一些参数。链接长显得很臃肿，看起来不舒服，而且我们携带的信息也是明文的，容易被用户猜到改动，所以当遇到这些问题时，你可能需要一个短链接服务。&lt;/p></description></item><item><title>API 错误应该返回什么</title><link>https://blog.cong.moe/post/api-error/</link><pubDate>Thu, 07 Feb 2019 23:22:30 +0800</pubDate><guid>https://blog.cong.moe/post/api-error/</guid><description>&lt;p>现在前后端沟通的方式大多应该是基于 &lt;code>http&lt;/code> 的序列化使用 &lt;code>json&lt;/code> 的请求, 规范往往会使用 &lt;code>Restful&lt;/code>. 然而程序大多数时间都是在处理异常, 但是错误信息组织方式却千奇百怪, 这里简单说一下我自己的理解.&lt;/p></description></item><item><title>Envoy</title><link>https://blog.cong.moe/post/envoy/</link><pubDate>Thu, 06 Sep 2018 15:09:48 +0800</pubDate><guid>https://blog.cong.moe/post/envoy/</guid><description>&lt;p>负载均衡应用非常广泛, 实现方式也有多种, 有硬件层面上的, 也有软件层面的. 软件层面上的基本大家都很熟悉 &lt;code>nginx&lt;/code>. 与 docker 配合得很好得有 &lt;code>traefik&lt;/code>, k8s 好多组件选择了 &lt;code>envoy&lt;/code>, 今天尝试了一下.&lt;/p></description></item><item><title>DB Url</title><link>https://blog.cong.moe/post/db-url/</link><pubDate>Tue, 28 Aug 2018 18:38:32 +0800</pubDate><guid>https://blog.cong.moe/post/db-url/</guid><description>&lt;p>服务基本都会使用各式各样的数据库, 一般会使用配置文件配置数据库的地址, 用户名, 密码, 使用数据库名等信息. 有的人喜欢配置一条 url, 而有的人喜欢把它拆开, 两者有什么区别呢?&lt;/p></description></item><item><title>Influx + Grafana 监控应用</title><link>https://blog.cong.moe/post/influx-grafana/</link><pubDate>Mon, 02 Jul 2018 18:05:22 +0800</pubDate><guid>https://blog.cong.moe/post/influx-grafana/</guid><description>&lt;p>监控是服务必不可少的一项功能. 当然早已不满足于单纯 health 的监控. 最近尝试了 &lt;code>Influx DB + Grafana&lt;/code> 做监控和显示服务.&lt;/p></description></item><item><title>Let’s Encrypt 通配符证书</title><link>https://blog.cong.moe/post/2018-03-15-wildcard-certificates/</link><pubDate>Thu, 15 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2018-03-15-wildcard-certificates/</guid><description>&lt;p>&lt;a href="https://letsencrypt.org/" target="_blank" rel="noreferrer">Let’s Encrypt&lt;/a> 非常良心地为我们提供免费的 CA 证书, 最近终于支持通配符子域名证书了, 也就是说 &lt;code>*.example.com&lt;/code> 可以共用一个证书了.&lt;/p></description></item><item><title>docker link 干了什么</title><link>https://blog.cong.moe/post/2018-01-26-docker-link/</link><pubDate>Fri, 26 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2018-01-26-docker-link/</guid><description>&lt;blockquote>
&lt;p>总感觉 docker link 很神奇, 之后发现竟然是用很简单的方法实现的.&lt;/p>&lt;/blockquote>
&lt;p>最早接触 &lt;code>docker link&lt;/code> 是在 &lt;code>docker-compose&lt;/code> 配置中看到的&lt;/p></description></item><item><title>circleci 系列2 - compose</title><link>https://blog.cong.moe/post/2018-01-25-circle2/</link><pubDate>Thu, 25 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2018-01-25-circle2/</guid><description>&lt;blockquote>
&lt;p>&lt;a href="https://blog.cong.moe/circleci-start/">上一章&lt;/a> 描述了一个最简单的例子, 然而后端项目往往依赖数据库(虽然基本上测试都建议用 &lt;code>sqlite&lt;/code>), 本文简单描述一下多镜像测试, 以 &lt;code>mysql&lt;/code> 为例.&lt;/p>&lt;/blockquote></description></item><item><title>circleci 系列1 - 起步</title><link>https://blog.cong.moe/post/2018-01-21-circleci-start/</link><pubDate>Sun, 21 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2018-01-21-circleci-start/</guid><description>&lt;blockquote>
&lt;p>ci 工具的使用会极大得减少开发者的测试发布负担, 减少错误定位消耗的时间.&lt;/p>&lt;/blockquote>
&lt;h3 id="circleci" class="relative group">&lt;a href="https://circleci.com" target="_blank" rel="noreferrer">circleci&lt;/a> &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#circleci" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h3>&lt;p>我的 github 代码基本都是使用 &lt;code>circleci&lt;/code>, 之前是 1.0 版本, 但是从它 2.0 测试版本发布我就一直使用 2.0. 建议大家使用 2.0, 因为 2.0 优化了很多东西, 支持 docker 镜像, 配置更加清晰简介, 速度快了好几倍, 是至今我见到的免费 ci 最好用的一个.&lt;/p></description></item><item><title>不要将思考方式带入别的语言</title><link>https://blog.cong.moe/post/2017-12-03-change-mind/</link><pubDate>Sun, 03 Dec 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-12-03-change-mind/</guid><description>&lt;blockquote>
&lt;p>不同的编程语言不仅仅是语法层次上的差别,所以说会用只是一个开始.&lt;/p>&lt;/blockquote>
&lt;p>惯用语言往往影响你的思考方式,比如习惯 JAVA 的人喜欢封装工厂类, 我当前最熟悉的语言是 js, 所以在学习 go 语言的时候对我的思路造成了不少干扰.&lt;/p>
&lt;p>因为 js 和 go 语言的差别远远不止一个是静态语言一个是动态语言. js 是异步单线程, go 则是多线程(goroutine). 所以用 js 的方式编写 go 程序就不会发挥出 go 的威力.&lt;/p></description></item><item><title>文档是什么？</title><link>https://blog.cong.moe/post/2017-09-03-what-is-document/</link><pubDate>Sun, 03 Sep 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-09-03-what-is-document/</guid><description>&lt;blockquote>
&lt;p>在软件行业，文档无处不在，可是是否想过文档书写该注意什么呢？&lt;/p>&lt;/blockquote>
&lt;h2 id="给谁看" class="relative group">给谁看？ &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e7%bb%99%e8%b0%81%e7%9c%8b" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;p>这个应该是首先应该去想的，文档是给谁看的？客户还是同事？对方是什么职业？&lt;/p>
&lt;p>比如，对方是客户可能不懂代码，你写的文档应该注重介绍，类比和展示，而不是怎么实现；&lt;/p>
&lt;p>对方如果是库的使用者，那么应该从用法深入到专业方面的实现；&lt;/p>
&lt;p>如果是合作者，那么你应当注重介绍如何开发和依赖还有设计思路方面的。&lt;/p>
&lt;p>这才是我们始终关注的主线，时刻要记住！&lt;/p></description></item><item><title>登录系统密码升级</title><link>https://blog.cong.moe/post/2017-08-15-upgrade-password/</link><pubDate>Tue, 15 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-08-15-upgrade-password/</guid><description>&lt;blockquote>
&lt;p>由于工作的原因，没想到又开始使用 PHP 了。。。稍微说一下密码加密吧。&lt;/p>&lt;/blockquote>
&lt;p>只要有登录系统，就会有密码加密。之前的加密惯用 md5，随着计算机性能的提高 md5 早已不是安全的加密算法了，比如某些网站就 md5 到源字符串查询的功能，简单的单词都可以查出来。当然，也有自造盐值 md5 加密，但是复杂度决定了它还是不够安全，为何不用 bcrypt 呢？虽然慢，但是网站的注册量并发量不会很大的，所以完全没压力。&lt;/p>
&lt;p>当然，也有一个原因是维护一些远古时期的代码。其实，非常简单就可以替用户升级的。&lt;/p></description></item><item><title>koa + graphql + dataloader</title><link>https://blog.cong.moe/post/2017-07-20-koa-graphql-dataloader/</link><pubDate>Thu, 20 Jul 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-07-20-koa-graphql-dataloader/</guid><description>&lt;blockquote>
&lt;p>如果不熟悉 dataloader 和 graphql，请看之前的两篇文章。&lt;/p>&lt;/blockquote>
&lt;p>dataloader 配合 graphql 使用会使得 schema 定义变得非常简洁清晰。&lt;/p></description></item><item><title>使用dataloader</title><link>https://blog.cong.moe/post/2017-07-13-use-dataloader/</link><pubDate>Thu, 13 Jul 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-07-13-use-dataloader/</guid><description>&lt;p>&lt;code>dataloader&lt;/code>简单的说就是实现了接口&lt;code>([input1, input2...]) =&amp;gt; ([output1, output2...])&lt;/code>，输入几个值就会输出几条数据，对于我们使用者知道这个就差不多了。当然，他的功能实现远不止这些，&lt;a href="https://github.com/facebook/dataloader" target="_blank" rel="noreferrer">详情请查看项目&lt;/a>。&lt;/p></description></item><item><title>koa graphql 处理图片上传</title><link>https://blog.cong.moe/post/2017-07-05-koa-graphql-support-image-upload/</link><pubDate>Wed, 05 Jul 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-07-05-koa-graphql-support-image-upload/</guid><description>&lt;p>graphql 一般都是以&lt;code>application/json&lt;/code>和&lt;code>application/graphql&lt;/code>的形式请求的，如果要上传文件，会用到&lt;code>form-data&lt;/code>形式，所以，我们需要写一个中间件来处理。&lt;/p></description></item><item><title>koa graphql server 支持 application/graphql</title><link>https://blog.cong.moe/post/2017-06-25-koa-graphql-server-support-applicationgraphql/</link><pubDate>Sun, 25 Jun 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-06-25-koa-graphql-server-support-applicationgraphql/</guid><description>&lt;blockquote>
&lt;p>本文需要您对 graphql 有基本的了解&lt;/p>&lt;/blockquote>
&lt;p>graphql 服务端有两个很方便的库，&lt;a href="https://github.com/graphql/express-graphql" target="_blank" rel="noreferrer">express-graphql&lt;/a> 和 &lt;a href="https://github.com/apollographql/apollo-server" target="_blank" rel="noreferrer">apollo-server&lt;/a>。&lt;/p>
&lt;p>&lt;code>express-graphql&lt;/code>默认支持&lt;code>application/graphql&lt;/code>， 而&lt;code>apollo-server&lt;/code>中的库都不支持，我们可以自行实现。&lt;/p></description></item><item><title>入坑静态语言</title><link>https://blog.cong.moe/post/2017-06-18-start-static-language/</link><pubDate>Sun, 18 Jun 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-06-18-start-static-language/</guid><description>&lt;blockquote>
&lt;p>静态语言和动态语言差别远远没有有无 type 那么简单&lt;/p>&lt;/blockquote>
&lt;p>接触编程一年多一点，最早的时候只会&lt;code>PHP&lt;/code>，接着学了&lt;code>JavaScript&lt;/code>写了些&lt;code>nodejs&lt;/code>，看了看前端的框架，了解了了解前端的构建工具（深坑）。最终成功将最熟悉的语言编程了 JavaScript，虽然现在的工作还是 PHP，但是下一个工作将是 nodejs。&lt;/p>
&lt;p>基于 nodejs 也写了一些 cli 工具，因为我用后端语言就是 cli 和 web，前端出了 css 我其实还可以的。。。&lt;/p></description></item><item><title>bind in javascript</title><link>https://blog.cong.moe/post/2017-05-26-bind-in-javascript/</link><pubDate>Fri, 26 May 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-05-26-bind-in-javascript/</guid><description>&lt;p>&lt;code>bind&lt;/code> 在 &lt;code>JavaScript&lt;/code> 中有个重要的用法就是偏函数。我之前不太熟悉这个方法，所以一些东西看了半天才明白。&lt;/p></description></item><item><title>生活中的概率</title><link>https://blog.cong.moe/post/2017-05-17-probability-in-life/</link><pubDate>Wed, 17 May 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-05-17-probability-in-life/</guid><description>&lt;blockquote>
&lt;p>脱离前提条件，我们觉得再正确的东西往往都是错的。&lt;/p>&lt;/blockquote>
&lt;p>说起概率，我们在熟悉不过了，从初中学习到大学。最熟悉的应该是抛硬币的例子吧，那么现在先思考一下，为什么抛一次硬币，正面向上的概率是 1/2？&lt;/p></description></item><item><title>使用firebase快速开发你的应用</title><link>https://blog.cong.moe/post/2017-04-14-firebase/</link><pubDate>Fri, 14 Apr 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-04-14-firebase/</guid><description>&lt;blockquote>
&lt;p>这两天了解了一下 Google 的 firebase 服务，于是就尝试了一下，结合 vue 做了个简单的小东西，本文简单介绍一下。详情请参看官方文档以及本例源码。&lt;/p>&lt;/blockquote>
&lt;p>GitHub: &lt;a href="https://github.com/zcong1993/fire-todo" target="_blank" rel="noreferrer">zcong1993/fire-todo&lt;/a>&lt;/p>
&lt;p>在线尝试: &lt;a href="http://vue-todos.surge.sh/" target="_blank" rel="noreferrer">http://vue-todos.surge.sh/&lt;/a>&lt;/p></description></item><item><title>php __invoke</title><link>https://blog.cong.moe/post/2017-02-17-php-invoke/</link><pubDate>Fri, 17 Feb 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-02-17-php-invoke/</guid><description>&lt;blockquote>
&lt;p>php 类魔术方法&lt;code>__invoke&lt;/code>, 当 class 定义此方法时，使用函数方式调用类的实例化时，此方法就会被调用。&lt;/p>&lt;/blockquote></description></item><item><title>Git入门教程8-github基本配置</title><link>https://blog.cong.moe/post/2017-01-18-github-config/</link><pubDate>Wed, 18 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-18-github-config/</guid><description>&lt;h2 id="基本配置" class="relative group">基本配置 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e5%9f%ba%e6%9c%ac%e9%85%8d%e7%bd%ae" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;hr>
&lt;p>&lt;code>github&lt;/code>账号注册流程非常简单，仅需要电子邮件验证就可以了。我们默认各位已经注册好账号了。&lt;/p>
&lt;p>使用&lt;code>github&lt;/code>我们不仅可以将自己的代码同步带云端进行版本控制，还可以在这个庞大的开源社区分享代码，也可以学习别人分享的开源代码，还可以和别人协作共同进行项目开发。&lt;/p>
&lt;p>&lt;code>github&lt;/code>放置公开的开源代码是免费的，你如果想要创建私密的项目，需要付费。&lt;/p>
&lt;p>理论上，你拥有账号就可以使用了，但是让你更方便快捷的使用它，还是建议你做以下两点优化。&lt;/p></description></item><item><title>yarn config</title><link>https://blog.cong.moe/post/2017-01-17-yarn-config/</link><pubDate>Tue, 17 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-17-yarn-config/</guid><description>&lt;blockquote>
&lt;p>GFW 内开发的生存之道，不但要攻克代码难题还要和我们的保护伞作斗争，真是累。&lt;/p>&lt;/blockquote>
&lt;h2 id="cnpm" class="relative group">cnpm &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#cnpm" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;p>这里肯定得感激淘宝为我们带来的国内&lt;a href="https://npm.taobao.org/" target="_blank" rel="noreferrer">npm 镜像站&lt;/a>，好多人为了方便直接使用&lt;code>cnpm&lt;/code>，但是&lt;code>cnpm&lt;/code>和&lt;code>npm&lt;/code> 处理依赖的方式不一样，所以使用&lt;code>cnpm&lt;/code>的项目中的&lt;code>node_modules&lt;/code>文件夹下回有一个额外的&lt;code>.bin&lt;/code>目录，所以会有很多额外的开销，也会使得有些&lt;code>IDE&lt;/code>打开项目时非常卡。所以，我已经放弃使用&lt;code>cnpm&lt;/code>了， 当然&lt;code>yarn&lt;/code>的出现也是非常大的原因。&lt;/p></description></item><item><title>Git入门教程5-版本回退</title><link>https://blog.cong.moe/post/2017-01-10-git-reset/</link><pubDate>Tue, 10 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-10-git-reset/</guid><description>&lt;h2 id="版本回退" class="relative group">版本回退 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e7%89%88%e6%9c%ac%e5%9b%9e%e9%80%80" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;hr>
&lt;p>就像上一节提到的，我们经常会犯错误，有事写了半天代码才发现做了好多无用功，需要退回到没有修改的状态，而且我们还提交了版本。git 作为版本管理工具肯定允许我们乘坐&lt;code>时光机&lt;/code>回到任何我们提交的版本。git 让代码世界有了后悔药这个东西。&lt;/p></description></item><item><title>Git入门教程6-分支起步</title><link>https://blog.cong.moe/post/2017-01-10-git-branch/</link><pubDate>Tue, 10 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-10-git-branch/</guid><description>&lt;h2 id="分支起步" class="relative group">分支起步 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e5%88%86%e6%94%af%e8%b5%b7%e6%ad%a5" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;p>分支的概念和树枝差不多，从某一主干分成多个分支。git 的分支也是这样的，但是 git 的分支更强大的一点就是可以合并，这样我们就可以并行开发。这在多人合作中尤为突出。每个人都有一个从主干分出来的分支，完成各自负责的开发最后合并到主干，这样效率就非常高了，或者创建 debug 分支和 feature 分支在解决 bug 的同时不影响新功能的开发。&lt;/p>
&lt;p>分支有时也可以保存不同版本，一般主分支&lt;code>master&lt;/code>都是保存的比较稳定的版本，开发会放在&lt;code>dev&lt;/code>分支，历史版本有时也会保留在分支中比如&lt;code>1.0&lt;/code>分支。&lt;/p></description></item><item><title>Git入门教程7-解决冲突</title><link>https://blog.cong.moe/post/2017-01-10-git-conflect/</link><pubDate>Tue, 10 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-10-git-conflect/</guid><description>&lt;h2 id="解决冲突" class="relative group">解决冲突 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e8%a7%a3%e5%86%b3%e5%86%b2%e7%aa%81" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;hr>
&lt;p>上一节提到了分支的创建和合并，现实中我们的代码往往是互相联系的。比如我们在 bug 修复分支和 dev 分支开发功能时，同时修改了某个文件，之后修复 bug 分支结束的时候需要合并到主分支，之后 dev 分支合并到 master 分支的时候，这时这个文件的版本和 dev 分支分出去的状态不一样，很可能同一部分的代码会相互冲突。&lt;/p>
&lt;p>这时，我们就需要解决冲突，因为 git 并不知道我们真正需要保留的是哪个版本，有时可能需要结合两个版本修正出第三个版本，所以这只能由我们自己判断了。多人合作时往往会需要冲突的两个人商讨得出最终保留版本。请记住，无论如何都不要擅自修改或丢弃他人的代码。&lt;/p></description></item><item><title>Git入门教程4-撤销更改</title><link>https://blog.cong.moe/post/2017-01-05-gitcancel/</link><pubDate>Thu, 05 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-05-gitcancel/</guid><description>&lt;h2 id="撤销更改" class="relative group">撤销更改 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e6%92%a4%e9%94%80%e6%9b%b4%e6%94%b9" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;hr>
&lt;p>上一节我们学习了 git 提交版本只需要简单的 3 步，那么有时候我们需要撤销一些更改。&lt;/p>
&lt;p>撤销更改的策略往往会取决于你是在什么状态需要撤销，撤销到什么状态。&lt;/p></description></item><item><title>Git入门教程1-安装</title><link>https://blog.cong.moe/post/2017-01-04-git-install/</link><pubDate>Wed, 04 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-04-git-install/</guid><description>&lt;h2 id="安装" class="relative group">安装 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e5%ae%89%e8%a3%85" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;hr>
&lt;p>几乎所有软件在不同平台安装方法都不一样，Linux 有自己的包管理工具，OSX 大多人也依赖 homebrew 进行软管理，Windows 下直接下载软件安装包安装会比较方便。&lt;/p>
&lt;p>git 主要使用时主要依赖于命令行工具（虽然也有图形界面软件），不过还是建议使用命令行，等你适用了之后，你会真的觉得命令行方便简洁高效了。&lt;/p></description></item><item><title>Git入门教程2-配置</title><link>https://blog.cong.moe/post/2017-01-04-gitconfig/</link><pubDate>Wed, 04 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-04-gitconfig/</guid><description>&lt;h2 id="配置" class="relative group">配置 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e9%85%8d%e7%bd%ae" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;hr>
&lt;p>上一节安装的结尾我们配置了两项信息：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ git config --global user.name &lt;span class="s2">&amp;#34;your username&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git config --global user.email &lt;span class="s2">&amp;#34;your email&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>也就是我们的用户名和邮箱，这也是我们信息的标识符，也就是 git 最基本的配置项。&lt;/p></description></item><item><title>Git入门教程3-快速上手</title><link>https://blog.cong.moe/post/2017-01-04-gitquickstart/</link><pubDate>Wed, 04 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.cong.moe/post/2017-01-04-gitquickstart/</guid><description>&lt;h2 id="快速上手" class="relative group">快速上手 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e5%bf%ab%e9%80%9f%e4%b8%8a%e6%89%8b" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h2>&lt;hr>
&lt;p>经过前两步安装和配置之后我们就可以开始使用 git 的基本操作了。&lt;/p>
&lt;h3 id="创建版本仓库" class="relative group">创建版本仓库 &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100">&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#%e5%88%9b%e5%bb%ba%e7%89%88%e6%9c%ac%e4%bb%93%e5%ba%93" aria-label="Anchor">#&lt;/a>&lt;/span>&lt;/h3>&lt;p>git 的项目都是以项目文件夹作为一个版本管理仓库，现在我们就开始创建一个版本仓库，使用的命令是&lt;code>git init&lt;/code>。&lt;/p></description></item></channel></rss>