[{"content":"介绍 书接上文 OneDev 自建 Git 服务和 CI/CD，这次通过 ArgoCD 实现项目部署，项目编译、镜像构建依然通过 OneDev 流水线实现。当然用别的 Git 服务也是可以的。\nArgo CD 被实现为一个 kubernetes 控制器，它持续监控正在运行的应用程序并将当前的活动状态与所需的目标状态（如 Git repo 中指定的）进行比较。Argo CD 报告和可视化差异，同时提供自动或手动将实时状态同步回所需目标状态的工具。\n上次 git 仓库只有一个，这次 git 仓库分为两个\nwx-msg-push 为项目代码 gitops 应用部署定义\n整体流程为：\nwx-msg-push 正常开发提交 当创建 tag 推送时，触发 OneDev 流水线构建 检出 wx-msg-push 代码，在容器中编译可执行文件，生成多平台可执行文件压缩包制品 通过 kaniko 构建 wx-msg-push 项目镜像，推送至镜像仓库 检出 gitops 代码，修改 wx-msg-push 项目 yaml 文件的镜像版本后 push 在 argocd 中发现 gitops 配置变更 同步应用最新状态 安装部署 高可用配置请参考 High Availability\n$ kubectl create namespace argocd $ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml 安装之后默认会启用 TLS 验证和 http 强制跳转至 https。 我这里不需要，直接修改 argocd-server 配置 kubectl -n argocd edit deployments.apps argocd-server，增加运行 insecure 运行参数，取消该限制。\ncontainers: - command: - argocd-server - --insecure 然后来查看服务地址\n$ kubectl -n argocd get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE argocd-applicationset-controller ClusterIP 10.98.109.34 \u0026lt;none\u0026gt; 7000/TCP,8080/TCP 18m argocd-dex-server ClusterIP 10.108.192.57 \u0026lt;none\u0026gt; 5556/TCP,5557/TCP,5558/TCP 18m argocd-metrics ClusterIP 10.103.219.23 \u0026lt;none\u0026gt; 8082/TCP 18m argocd-notifications-controller-metrics ClusterIP 10.105.150.33 \u0026lt;none\u0026gt; 9001/TCP 18m argocd-redis ClusterIP 10.96.158.98 \u0026lt;none\u0026gt; 6379/TCP 18m argocd-repo-server ClusterIP 10.111.153.43 \u0026lt;none\u0026gt; 8081/TCP,8084/TCP 18m argocd-server ClusterIP 10.98.129.33 \u0026lt;none\u0026gt; 80/TCP,443/TCP 18m argocd-server-metrics ClusterIP 10.110.107.116 \u0026lt;none\u0026gt; 8083/TCP 18m 获取密码 kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=\u0026quot;{.data.password}\u0026quot; | base64 -d; echo\n下载 argocd cli 可以通过命令行直接控制\ncli 登录\n$ argocd login 10.98.129.33 --username admin Password: \u0026#39;admin:login\u0026#39; logged in successfully Context \u0026#39;10.98.129.33\u0026#39; updated cli 修改密码\n$ argocd account update-password *** Enter password of currently logged in user (admin): *** Enter new password for user admin: *** Confirm new password for user admin: Password updated Context \u0026#39;10.98.129.33\u0026#39; updated 给 argocd-server Service 加个 Ingress 再配个负载均衡加个二级域名解析，就直接略过了，可以参考之前的文章。也可以通过暴露 Node port 方式访问。\n登录之后 Applications 还是空的，目前也没有中文界面。\n创建 Projects 先创建一个 Projects，SOURCE REPOSITORIES 可以限制仓库来源，DESTINATIONS 部署到的目标集群限制，CLUSTER RESOURCE、NAMESPACE RESOURCE 资源权限限制，先都直接给 * 想细分可以直接细化。 创建 repo 可以选择 ssh, https 方式，在配置中加上 gitops 仓库地址，Project 选择刚才添加的 nico。 创建 App 在 Applications 中新增 App，可以通过 EDIT AS YAML 直接编辑。 SYNC POLICY 同步策略，可以选择自动或手动\nPRUNE RESOURCES 是否清理未定义资源，参考 No Prune Resources SELF HEAL 自动修复，当集群中应用与定义不符时自动修复 SYNC OPTIONS\nSKIP SCHEMA VALIDATION 跳过验证也就是 kubectl apply --validate=false AUTO-CREATE NAMESPACE 没啥可说的 PRUNE LAST 对资源进行修剪时建议勾选，参考 Allow resource pruning to be an implicit final wave of a sync operation APPLY OUT OF SYNC ONLY 只同步不同步的资源。目前，当使用自动同步 ArgoCD 进行同步时，会应用应用程序中的每个对象。 对于包含数千个对象的应用程序，这需要相当长的时间，并对 api 服务器施加过大的压力。 RESPECT IGNORE DIFFERENCES 是否在同步的时候也忽略 spec.ignoreDifferences 差异配置。默认情况下 spec.ignoreDifferences 配置仅用于计算实时状态和期望状态之间的差异。 PRUNE PROPAGATION POLICY 集联删除策略，分为三种。文档上看默认是 background 详情参考 cascading-deletion。\nforeground 前台，先标记删除资源本身，然后删除所有关联子资源，再删除资源本身。 background 后台，直接删除资源本身，再处理关联子资源。 orphan 孤儿模式，直接删除资源本身，子资源垃圾回收器处理。 REPLACE 使用 kubectl replace/create 代替 kubectl apply RETRY 重试配置\nPath 可指定要配置文件目录 最下面为部署时的工具配置，可以选择 Directory、Helm、Kustomize、Plugin。\n同步时机 argocd 默认每三分钟会检查一次仓库是否有新的修改，如果想要实时更新可以通过 webhook 通知 argocd。但是目前 argocd webhook 仅支持 GitHub, Bitbucket, GitLab, Gogs。对于未支持的 git 服务配置 webhook 会返回 Unknown webhook event 见此，clone 下来可以自己适配下 onedev webhook 也不算太麻烦。当然也可以在页面手动更新。 默认轮询间隔配置可以通过 argocd-cm Configmap 的 timeout.reconciliation 修改，如果想禁用设成 0s 即可，这里我改成 30s 看下效果。yaml 参考 argocd-cm.yaml\n$ kubectl edit configmap argocd-cm -n argocd 现在我修改下 wx-msg-push 代码，push 一个新 tag，就会触发整个流程。最终通过 argocd 部署新版本应用，在 k8s 中对该应用进行修改导致与配置定义不一致的行为都会自动修复。 可以看到部署的历史详情，还可以进行回滚，回滚会禁用自动同步，可以再手动开启。 总结 本文实践了 Argo CD 全程基本通过 web ui 操作，也可以通过 cli 操作。其中 webhook 只支持几个大牌 git，如果使用未支持的 git 服务，建议自行适配，如果不想侵入修改也可以编写远程脚本执行 argocd cli 来触发，达到同样的效果。timeout.reconciliation 建议直接禁用就好了。 Argo CD 不止于此，还有更多使用姿势及配置请通过官方文档了解。\nArgo CD - Declarative GitOps CD for Kubernetes ","permalink":"https://ibelieving.com/posts/2022-07-30-argocd/","summary":"\u003ch2 id=\"介绍\"\u003e介绍\u003c/h2\u003e\n\u003cp\u003e书接上文 \u003ca href=\"/posts/2022-07-12-onedev/\"\u003eOneDev 自建 Git 服务和 CI/CD\u003c/a\u003e，这次通过 ArgoCD 实现项目部署，项目编译、镜像构建依然通过 OneDev 流水线实现。当然用别的 Git 服务也是可以的。\u003c/p\u003e\n\u003cp\u003eArgo CD 被实现为一个 kubernetes 控制器，它持续监控正在运行的应用程序并将当前的活动状态与所需的目标状态（如 Git repo 中指定的）进行比较。Argo CD 报告和可视化差异，同时提供自动或手动将实时状态同步回所需目标状态的工具。\u003c/p\u003e\n\u003cp\u003e上次 git 仓库只有一个，这次 git 仓库分为两个\u003c/p\u003e\n\u003cp\u003ewx-msg-push 为项目代码\ngitops 应用部署定义\u003c/p\u003e\n\u003cp\u003e整体流程为：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ewx-msg-push 正常开发提交\u003c/li\u003e\n\u003cli\u003e当创建 tag 推送时，触发 OneDev 流水线构建\u003c/li\u003e\n\u003cli\u003e检出 wx-msg-push 代码，在容器中编译可执行文件，生成多平台可执行文件压缩包制品\u003c/li\u003e\n\u003cli\u003e通过 kaniko 构建 wx-msg-push 项目镜像，推送至镜像仓库\u003c/li\u003e\n\u003cli\u003e检出 gitops 代码，修改 wx-msg-push 项目 yaml 文件的镜像版本后 push\u003c/li\u003e\n\u003cli\u003e在 argocd 中发现 gitops 配置变更\u003c/li\u003e\n\u003cli\u003e同步应用最新状态\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"安装部署\"\u003e安装部署\u003c/h2\u003e\n\u003cp\u003e高可用配置请参考 \u003ca href=\"https://argo-cd.readthedocs.io/en/stable/operator-manual/high_availability/\"\u003eHigh Availability\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectl create namespace argocd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装之后默认会启用 \u003ccode\u003eTLS\u003c/code\u003e 验证和 \u003ccode\u003ehttp\u003c/code\u003e 强制跳转至 \u003ccode\u003ehttps\u003c/code\u003e。\n我这里不需要，直接修改 \u003ccode\u003eargocd-server\u003c/code\u003e 配置 \u003ccode\u003ekubectl -n argocd edit deployments.apps argocd-server\u003c/code\u003e，增加运行 \u003ccode\u003einsecure\u003c/code\u003e 运行参数，取消该限制。\u003c/p\u003e","title":"Argo CD 实践 GitOps"},{"content":"介绍 今天介绍一个可以自建的开源 Git 服务 OneDev, 功能强大，资源占用少，国人 Java 开发。\n开箱即用的符号跳转、符号搜索 全功能的 CI/CD，支持 GUI 强大易用的 Commit/Issue/Build/Pull Request 查询语言 代码标注和讨论 更多功能特性看官网说明 目前不足是全英文，文档简洁，还不知道什么时候支持中文，也不算什么大事。另外小 Bug 多，不过作者修复神速。\n部署安装 运行环境 k8s v1.21.5，容器运行时 containerd。\n安装方式直接参考官方文档 helm 装就完事，除了在 k8s 运行也可以直接 docker run 和裸机跑。 helm 安装完成会创建一个 onedev 的 service type 是 LoadBalancer，由于我使用 apisix ingress 所以直接改成 ClusterIP 然后外面再套负载均衡走流量。细节不展开了可以参考实践 Apache APISIX Ingress。\n符号跳转、搜索 支持 Java, JavaScript, C, C++, CSharp, Go, PHP, Python, CSS, SCSS, LESS and R 语言，IDE 级别的功能。 据作者说使用 ANTLR 分析主流语言的语法，并提取符号定义进行增量存储，速度快，占用空间小。\nCI/CD 直接来体验下 CI/CD，测试项目依然是我的 wx-msg-push。\n先创建一个 yaml 配置文件，在 k8s 中 apply，这个是 onedev 在 k8s 中部署应用使用。\nkind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: gitops-onedev rules: - apiGroups: [\u0026#34;\u0026#34;] resources: [\u0026#34;services\u0026#34;] verbs: [\u0026#34;get\u0026#34;, \u0026#34;create\u0026#34;] - apiGroups: [\u0026#34;apps\u0026#34;] resources: [\u0026#34;deployments\u0026#34;] verbs: [\u0026#34;get\u0026#34;, \u0026#34;patch\u0026#34;, \u0026#34;create\u0026#34;] 然后在 Administration -\u0026gt; Job Executors 中创建一个 Build 执行方式。类型可以选远程docker、远程shell、k8s。我这里还是选k8s，也可以指定运行节点，Cluster Role 写上刚才创建的 gitops-onedev，镜像仓库用哪写哪就可以，我这里是阿里云。 在项目配置中加上镜像仓库的账号信息。这里 ali-repo-auth 通过 echo -n \u0026quot;username:passwd\u0026quot; | base64 生成。 然后在项目中点击 .onedev-buildspec.yml 进入 build 配置页面。 通过这个页面可以一步步配置 CI/CD。 可以设置触发参数、触发逻辑比如push branch或者push tag，可以设置从属关系、重试、超时、缓存等。 我这里 CI 阶段由 push tag 触发，具体分为四个 Step\ncheckout 代码检出 make 编译可执行文件 build \u0026amp; push 构建镜像推送 publish artifact 发布制品，各平台的可执行文件包 通过 View Source 可以看到实际生成的配置文件。 分享下我现在的配置文件，Job Executor 就是刚才创建的 Build 执行方式。\nversion: 16 jobs: - name: ci jobExecutor: k8s steps: - !CheckoutStep name: checkout cloneCredential: !DefaultCredential {} withLfs: false withSubmodules: true condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: make runInContainer: true image: zyh94946/golang:v1.18.3 interpreter: !ShellInterpreter shell: sh commands: - make release useTTY: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: build \u0026amp; push runInContainer: true image: zyh94946/kaniko:v1.8.1-debug interpreter: !ShellInterpreter shell: /busybox/sh commands: - echo \u0026#34;{\\\u0026#34;auths\\\u0026#34;:{\\\u0026#34;@secret:ali-repo-url@\\\u0026#34;:{\\\u0026#34;auth\\\u0026#34;:\\\u0026#34;@secret:ali-repo-auth@\\\u0026#34;}}}\u0026#34; \u0026gt; /kaniko/.docker/config.json - /kaniko/executor --context \u0026#34;/onedev-build/workspace\u0026#34; --dockerfile \u0026#34;/onedev-build/workspace/Dockerfile\u0026#34; --destination \u0026#34;@secret:ali-repo-url@/zyh94946/nico:wx-msg-push-@tag@\u0026#34; useTTY: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !PublishArtifactStep name: publish artifact artifacts: \u0026#39;*.zip\u0026#39; condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL triggers: - !TagCreateTrigger tags: v* retryCondition: never maxRetries: 3 retryDelay: 30 cpuRequirement: 250 memoryRequirement: 256 timeout: 3600 - name: cd jobExecutor: k8s steps: - !CheckoutStep name: checkout cloneCredential: !DefaultCredential {} withLfs: false withSubmodules: true condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: deploy runInContainer: true image: zyh94946/kubectl:v1.21.5 interpreter: !DefaultInterpreter commands: - \u0026#39;echo \u0026#34;tag: @tag@\u0026#34;\u0026#39; - \u0026#39;if [ \u0026#34;@tag@\u0026#34; != \u0026#34;\u0026#34; ]; then \u0026#39; - \u0026#34;\\tsed -i \\\u0026#34;s/#tag#/@tag@/g\\\u0026#34; k8s.deployment.yaml\u0026#34; - \u0026#34;\\tkubectl apply -f k8s.deployment.yaml\u0026#34; - fi; useTTY: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL jobDependencies: - jobName: ci requireSuccessful: true artifacts: \u0026#39;**\u0026#39; retryCondition: never maxRetries: 3 retryDelay: 30 cpuRequirement: 250 memoryRequirement: 256 timeout: 3600 由于 k8s 集群容器运行时采用 containerd 所以无法通过 docker 正常构建和推送。这里我通过 google 开源的容器工具 kaniko 构建和推送镜像。 该工具镜像地址为 gcr.io/kaniko-project/executor:debug，建议用 debug 版可以进入 shell，由于原镜像地址太慢自行下载后传到了 dockerhub 上 zyh94946/kaniko:v1.8.1-debug。使用方式也很简单，一条命令就完成构建和推送了，具体看上面的配置。\nCD 部分只有两个 Step，代码检出和应用部署，部署中的镜像就是 CI 中创建的。CD 附属于 CI，当 CI 执行成功后手动触发 CD，当然也可以在 CI 完成后自动开始 CD 任务。 关于版本回退，可以从 k8s 中执行 Roll Back，或者在 onedev 中单独执行一个指定 tag 的 CD 重新部署。\n总结 以上就是在 onedev 中的 CI/CD 应用，通过编译可执行文件，构建镜像推送，最后用 kubectl 在 k8s 中部署。 其中通过 kubectl 部署应用，赋予了 onedev 对 k8s 的操作权限。另外还有一种方式采用 Argo CD 拉取配置来更新，onedev 只做 CI 的事，这样即使采用在 k8s 集群外的 git 服务也能有较好的安全性。\n","permalink":"https://ibelieving.com/posts/2022-07-12-onedev/","summary":"\u003ch2 id=\"介绍\"\u003e介绍\u003c/h2\u003e\n\u003cp\u003e今天介绍一个可以自建的开源 Git 服务 \u003ca href=\"https://github.com/theonedev/onedev\"\u003eOneDev\u003c/a\u003e, 功能强大，资源占用少，国人 Java 开发。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e开箱即用的符号跳转、符号搜索\u003c/li\u003e\n\u003cli\u003e全功能的 CI/CD，支持 GUI\u003c/li\u003e\n\u003cli\u003e强大易用的 Commit/Issue/Build/Pull Request 查询语言\u003c/li\u003e\n\u003cli\u003e代码标注和讨论\u003c/li\u003e\n\u003cli\u003e更多功能特性看官网说明\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e目前不足是全英文，文档简洁，还不知道什么时候支持中文，也不算什么大事。另外小 Bug 多，不过作者修复神速。\u003c/p\u003e\n\u003ch2 id=\"部署安装\"\u003e部署安装\u003c/h2\u003e\n\u003cp\u003e运行环境 \u003ccode\u003ek8s v1.21.5\u003c/code\u003e，容器运行时 \u003ccode\u003econtainerd\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e安装方式直接参考\u003ca href=\"https://docs.onedev.io/installation-guide/deploy-to-k8s\"\u003e官方文档\u003c/a\u003e \u003ccode\u003ehelm\u003c/code\u003e 装就完事，除了在 \u003ccode\u003ek8s\u003c/code\u003e 运行也可以直接 \u003ccode\u003edocker run\u003c/code\u003e 和裸机跑。\n\u003ccode\u003ehelm\u003c/code\u003e 安装完成会创建一个 \u003ccode\u003eonedev\u003c/code\u003e 的 \u003ccode\u003eservice\u003c/code\u003e \u003ccode\u003etype\u003c/code\u003e 是 \u003ccode\u003eLoadBalancer\u003c/code\u003e，由于我使用 \u003ccode\u003eapisix ingress\u003c/code\u003e 所以直接改成 \u003ccode\u003eClusterIP\u003c/code\u003e 然后外面再套负载均衡走流量。细节不展开了可以参考\u003ca href=\"/posts/2022-07-05-apache_apisix_ingress/\"\u003e实践 Apache APISIX Ingress\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"符号跳转搜索\"\u003e符号跳转、搜索\u003c/h2\u003e\n\u003cp\u003e支持 Java, JavaScript, C, C++, CSharp, Go, PHP, Python, CSS, SCSS, LESS and R 语言，IDE 级别的功能。\n据作者说使用 ANTLR 分析主流语言的语法，并提取符号定义进行增量存储，速度快，占用空间小。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"符号搜索\" loading=\"lazy\" src=\"/images/onedev1.jpg\"\u003e\n\u003cimg alt=\"符号跳转\" loading=\"lazy\" src=\"/images/onedev2.jpg\"\u003e\u003c/p\u003e","title":"OneDev 自建 Git 服务和 CI/CD"},{"content":"介绍 Apache APISIX 是一个动态、实时、高性能的 API 网关。基于 Nginx 和 Etcd 实现。\n作为 API 网关，APISIX 提供了灵活插件机制、动态上游、动态路由、灰度发布、熔断限流、身份认证、可观测性、Serverless、Wasm等功能。可以处理L4、L7层的流量支持HTTP、HTTPS、TCP、UDP、MQTT、gRPC等协议。\n安装部署 在 kubesphere 中创建一个 Workspace，添加 APISIX Helm Chart 仓库 https://charts.apiseven.com/。\n然后新建一个 ingress-apisix 的 projects，也就是 namespace。在该 project 下创建一个 apisix App，选择刚才添加的仓库。创建 apisix 会同时创建 APISIX Gateway + Dashboard + Ingress Controller。\n版本选择 0.10.0 [2.14.1]\n我最终的配置：\nglobal: imagePullSecrets: [] apisix: enabled: true enableIPv6: true setIDFromPodUID: false customLuaSharedDicts: [] luaModuleHook: enabled: false luaPath: \u0026#39;\u0026#39; hookPoint: \u0026#39;\u0026#39; configMapRef: name: \u0026#39;\u0026#39; mounts: - key: \u0026#39;\u0026#39; path: \u0026#39;\u0026#39; enableCustomizedConfig: false customizedConfig: {} image: repository: apache/apisix pullPolicy: IfNotPresent tag: 2.14.1-alpine kind: Deployment replicaCount: 1 podAnnotations: {} podSecurityContext: {} securityContext: {} podDisruptionBudget: enabled: false minAvailable: 90% maxUnavailable: 1 resources: {} nodeSelector: {} tolerations: [] affinity: {} podAntiAffinity: enabled: false timezone: Asia/Shanghai extraEnvVars: [] nameOverride: \u0026#39;\u0026#39; fullnameOverride: \u0026#39;\u0026#39; gateway: type: NodePort externalTrafficPolicy: Cluster externalIPs: [] http: enabled: true servicePort: 80 containerPort: 9080 tls: enabled: false servicePort: 443 containerPort: 9443 existingCASecret: \u0026#39;\u0026#39; certCAFilename: \u0026#39;\u0026#39; http2: enabled: true stream: enabled: false only: false tcp: [] udp: [] ingress: enabled: false annotations: {} hosts: - host: apisix.local paths: [] tls: [] admin: enabled: true type: ClusterIP externalIPs: [] port: 9180 servicePort: 9180 cors: true credentials: admin: edd1c9f034335f136f87ad84b625c8f1 viewer: 4054f7cf07e344346cd3f287985e76a2 allow: ipList: - 0.0.0.0/0 plugins: - api-breaker - authz-keycloak - basic-auth - batch-requests - consumer-restriction - cors - echo - fault-injection - grpc-transcode - hmac-auth - http-logger - ip-restriction - ua-restriction - jwt-auth - kafka-logger - key-auth - limit-conn - limit-count - limit-req - node-status - openid-connect - authz-casbin - prometheus - proxy-cache - proxy-mirror - proxy-rewrite - redirect - referer-restriction - request-id - request-validation - response-rewrite - serverless-post-function - serverless-pre-function - sls-logger - syslog - tcp-logger - udp-logger - uri-blocker - wolf-rbac - zipkin - traffic-split - gzip - real-ip - ext-plugin-pre-req - ext-plugin-post-req - server-info stream_plugins: - mqtt-proxy - ip-restriction - limit-conn pluginAttrs: {} extPlugin: enabled: false cmd: - /path/to/apisix-plugin-runner/runner - run customPlugins: enabled: true luaPath: /opts/custom_plugins/?.lua plugins: - name: prometheus attrs: export_addr: ip: 0.0.0.0 port: 9091 configMap: name: prometheus mounts: [] updateStrategy: {} extraVolumes: [] extraVolumeMounts: [] discovery: enabled: false registry: null logs: enableAccessLog: true accessLog: /dev/stdout accessLogFormat: \u0026gt;- $remote_addr - $remote_user [$time_local] $http_host \\\u0026#34;$request\\\u0026#34; $status $body_bytes_sent $request_time \\\u0026#34;$http_referer\\\u0026#34; \\\u0026#34;$http_user_agent\\\u0026#34; $upstream_addr $upstream_status $upstream_response_time \\\u0026#34;$upstream_scheme://$upstream_host$upstream_uri\\\u0026#34; accessLogFormatEscape: default errorLog: /dev/stderr errorLogLevel: warn dns: resolvers: - 127.0.0.1 - 172.20.0.10 - 114.114.114.114 - 223.5.5.5 - 1.1.1.1 - 8.8.8.8 validity: 30 timeout: 5 initContainer: image: busybox tag: 1.28 autoscaling: enabled: false minReplicas: 1 maxReplicas: 100 targetCPUUtilizationPercentage: 80 targetMemoryUtilizationPercentage: 80 configurationSnippet: main: \u0026#39;\u0026#39; httpStart: \u0026#39;\u0026#39; httpEnd: \u0026#39;\u0026#39; httpSrv: \u0026#39;\u0026#39; httpAdmin: \u0026#39;\u0026#39; stream: \u0026#39;\u0026#39; serviceMonitor: enabled: false namespace: \u0026#39;\u0026#39; name: \u0026#39;\u0026#39; interval: 15s path: /apisix/prometheus/metrics metricPrefix: apisix_ containerPort: 9091 labels: {} annotations: {} etcd: enabled: true host: - \u0026#39;http://etcd.host:2379\u0026#39; prefix: /apisix timeout: 30 auth: rbac: create: false user: \u0026#39;\u0026#39; password: \u0026#39;\u0026#39; tls: enabled: false existingSecret: \u0026#39;\u0026#39; certFilename: \u0026#39;\u0026#39; certKeyFilename: \u0026#39;\u0026#39; verify: true sni: \u0026#39;\u0026#39; service: port: 2379 replicaCount: 3 dashboard: enabled: true service: type: NodePort ingress-controller: enabled: true config: apisix: serviceNamespace: ingress-apisix serviceMonitor: enabled: true namespace: ingress-apisix interval: 15s 慢慢等待相关镜像下载运行完成。找到 apisix-dashboard Service 的 Node port 在浏览器中打开进入 dashboard，默认用户名、密码都是 admin。\n创建一个 Ingress 举例为我的 wx-msg-push 企业微信消息推送服务创建 Ingress。先创建一个 ClusterIP 类型的 Service，然后创建一个 Ingress。 kubernetes.io/ingress.class 设为 apisix 创建完成，在 apisix-dashboard 上 Route、Upstream 下可以看到对应的条目。apisix-dashboard 也是支持切换中文的。 Upstream 节点直接就到 Pod IP，Pod 有变化 Upstream 会动态更新。\n通过 ingress-apisix Project 下 apisix-gateway Service 的 NodePort 和路由规则里面的域名访问 wx-msg-push 服务。 我这里的域名是 msg-push.ibelieving.io 解析到 k8s 节点，然后通过 msg-push.ibelieving.io:31202 访问 wx-msg-push 服务。\n这是一个简陋的 Ingress 使用例子。正经 k8s 环境下集群节点理论是不提供公网访问的，前端应该配置云负载均衡器作为公网入口，或者自行搭建高可用负载均衡，然后流量再进入 Ingress。而且直接访问 Ingress 只能使用高位端口。\n灰度发布 先创建两个 wx-msg-push Deployment、Service，一个 v1、v2。v2 作为新版，定义一个 ApisixRoute yaml，将三分之一流量路由到 v2，将三分之二流量路由到 v1。\napiVersion: apisix.apache.org/v2beta3 kind: ApisixRoute metadata: namespace: nico name: wx-msg-push spec: http: - name: route-rule match: hosts: - msg-push.ibelieving.io paths: - /* backends: - serviceName: wx-msg-push-v1 servicePort: 80 weight: 2 - serviceName: wx-msg-push-v2 servicePort: 80 weight: 1 $ kubectl apply -f wx-msg-push-route.yaml 通过 curl 进行测试，查看容器日志可以看到请求以三分之一概率进入到了 v2。正式业务使用时对新版本进行灰度测试，分少部分流量，验证通过后慢慢加大权重比例，直至全量切换。 这个路由配置可以从 apisix-dashboard 上看到。这是根据不同权重进行分流，也可以附加自定义规则进行分流。 可以看到 apisix 对 yaml 中配置进行了处理，使用 traffic-split 插件实现了流量分流，upstream_id 对应着 Upstream 中的上游配置，根据 Service 生成。 这个路由规则也可以通过 apisix-dashboard 的交互界面创建，还可以通过 apisix admin api 创建非常方便。 这篇文章只是 apisix 的一小部分，另外还有很多功能、插件可以使用。通过插件、Consumer 可以实现用户登录、权限认证、对不同的用户进行单独的限制。\n参考 建议阅读\nApache APISIX : Software Architecture ","permalink":"https://ibelieving.com/posts/2022-07-05-apache_apisix_ingress/","summary":"\u003ch2 id=\"介绍\"\u003e介绍\u003c/h2\u003e\n\u003cp\u003eApache APISIX 是一个动态、实时、高性能的 API 网关。基于 Nginx 和 Etcd 实现。\u003c/p\u003e\n\u003cp\u003e作为 API 网关，APISIX 提供了灵活插件机制、动态上游、动态路由、灰度发布、熔断限流、身份认证、可观测性、Serverless、Wasm等功能。可以处理L4、L7层的流量支持HTTP、HTTPS、TCP、UDP、MQTT、gRPC等协议。\u003c/p\u003e\n\u003ch2 id=\"安装部署\"\u003e安装部署\u003c/h2\u003e\n\u003cp\u003e在 kubesphere 中创建一个 Workspace，添加 APISIX Helm Chart 仓库 \u003ca href=\"https://charts.apiseven.com/\"\u003ehttps://charts.apiseven.com/\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Add App Repository\" loading=\"lazy\" src=\"/images/apisix1.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e然后新建一个 ingress-apisix 的 projects，也就是 namespace。在该 project 下创建一个 apisix App，选择刚才添加的仓库。创建 apisix 会同时创建 APISIX Gateway + Dashboard + Ingress Controller。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Create App\" loading=\"lazy\" src=\"/images/apisix2.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e版本选择 0.10.0 [2.14.1]\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Create App\" loading=\"lazy\" src=\"/images/apisix3.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e我最终的配置：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eglobal\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eimagePullSecrets\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eapisix\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenableIPv6\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003esetIDFromPodUID\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecustomLuaSharedDicts\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eluaModuleHook\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eluaPath\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehookPoint\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003econfigMapRef\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003emounts\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e        \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003ekey\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e          \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epath\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenableCustomizedConfig\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecustomizedConfig\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eimage\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003erepository\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eapache/apisix\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epullPolicy\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eIfNotPresent\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etag\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e2.14.1\u003c/span\u003e-alpine\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ekind\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eDeployment\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ereplicaCount\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epodAnnotations\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epodSecurityContext\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003esecurityContext\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epodDisruptionBudget\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eminAvailable\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e90\u003c/span\u003e%\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003emaxUnavailable\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eresources\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003enodeSelector\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etolerations\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eaffinity\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epodAntiAffinity\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etimezone\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eAsia/Shanghai\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eextraEnvVars\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003enameOverride\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003efullnameOverride\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003egateway\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etype\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eNodePort\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eexternalTrafficPolicy\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eCluster\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eexternalIPs\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehttp\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eservicePort\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e80\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003econtainerPort\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e9080\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etls\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eservicePort\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e443\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003econtainerPort\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e9443\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eexistingCASecret\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecertCAFilename\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehttp2\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003estream\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eonly\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etcp\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eudp\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eingress\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eannotations\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehosts\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003ehost\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eapisix.local\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e        \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epaths\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etls\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eadmin\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etype\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eClusterIP\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eexternalIPs\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eport\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e9180\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eservicePort\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e9180\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecors\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecredentials\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eadmin\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eedd1c9f034335f136f87ad84b625c8f1\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eviewer\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e4054f7cf07e344346cd3f287985e76a2\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eallow\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eipList\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003e0.0.0.0\u003c/span\u003e/0\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eplugins\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- api-breaker\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- authz-keycloak\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- basic-auth\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- batch-requests\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- consumer-restriction\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- cors\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- echo\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- fault-injection\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- grpc-transcode\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- hmac-auth\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- http-logger\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- ip-restriction\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- ua-restriction\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- jwt-auth\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- kafka-logger\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- key-auth\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- limit-conn\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- limit-count\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- limit-req\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- node-status\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- openid-connect\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- authz-casbin\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- prometheus\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- proxy-cache\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- proxy-mirror\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- proxy-rewrite\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- redirect\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- referer-restriction\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- request-id\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- request-validation\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- response-rewrite\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- serverless-post-function\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- serverless-pre-function\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- sls-logger\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- syslog\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- tcp-logger\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- udp-logger\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- uri-blocker\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- wolf-rbac\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- zipkin\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- traffic-split\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- gzip\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- real-ip\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- ext-plugin-pre-req\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- ext-plugin-post-req\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- server-info\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003estream_plugins\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- mqtt-proxy\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- ip-restriction\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e- limit-conn\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003epluginAttrs\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eextPlugin\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecmd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- /path/to/apisix-plugin-runner/runner\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- run\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003ecustomPlugins\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eluaPath\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e/opts/custom_plugins/?.lua\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eplugins\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eprometheus\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eattrs\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e        \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eexport_addr\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e          \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eip\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e0.0.0.0\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e          \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eport\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e9091\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003econfigMap\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e        \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eprometheus\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e        \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003emounts\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eupdateStrategy\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eextraVolumes\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eextraVolumeMounts\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003ediscovery\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eregistry\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003enull\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003elogs\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenableAccessLog\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eaccessLog\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e/dev/stdout\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eaccessLogFormat\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e\u0026gt;-\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e    $remote_addr - $remote_user [$time_local] $http_host \\\u0026#34;$request\\\u0026#34; $status\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e    $body_bytes_sent $request_time \\\u0026#34;$http_referer\\\u0026#34; \\\u0026#34;$http_user_agent\\\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e    $upstream_addr $upstream_status $upstream_response_time\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e    \\\u0026#34;$upstream_scheme://$upstream_host$upstream_uri\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eaccessLogFormatEscape\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003edefault\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eerrorLog\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e/dev/stderr\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eerrorLogLevel\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003ewarn\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003edns\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eresolvers\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003e127.0.0.1\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003e172.20.0.10\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003e114.114.114.114\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003e223.5.5.5\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003e1.1.1.1\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0550ae\"\u003e8.8.8.8\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003evalidity\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e30\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etimeout\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003einitContainer\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eimage\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003ebusybox\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etag\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e1.28\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eautoscaling\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eminReplicas\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003emaxReplicas\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etargetCPUUtilizationPercentage\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e80\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etargetMemoryUtilizationPercentage\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e80\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003econfigurationSnippet\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003emain\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehttpStart\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehttpEnd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehttpSrv\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehttpAdmin\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003estream\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eserviceMonitor\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003enamespace\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003einterval\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e15s\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epath\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e/apisix/prometheus/metrics\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003emetricPrefix\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eapisix_\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003econtainerPort\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e9091\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003elabels\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eannotations\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e{}\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eetcd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ehost\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e- \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;http://etcd.host:2379\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eprefix\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e/apisix\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etimeout\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e30\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eauth\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003erbac\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecreate\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003euser\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003epassword\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etls\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eexistingSecret\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecertFilename\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ecertKeyFilename\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003everify\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003esni\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eservice\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eport\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e2379\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003ereplicaCount\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e3\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003edashboard\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eservice\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003etype\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eNodePort\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003eingress-controller\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003econfig\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eapisix\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e      \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eserviceNamespace\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eingress-apisix\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e  \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eserviceMonitor\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003eenabled\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003enamespace\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003eingress-apisix\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e    \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003einterval\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e15s\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e慢慢等待相关镜像下载运行完成。找到 \u003ccode\u003eapisix-dashboard\u003c/code\u003e Service 的 \u003ccode\u003eNode port\u003c/code\u003e 在浏览器中打开进入 dashboard，默认用户名、密码都是 \u003ccode\u003eadmin\u003c/code\u003e。\u003c/p\u003e","title":"实践 Apache APISIX Ingress"},{"content":"介绍 KubeSphere 是一个 k8s 集群管理平台，可以管理多云多集群，进行统一的应用分发和运维管理，避免云厂商绑定。提供了运维友好的操作界面，支持多租户，DevOps，服务网格，多种监控纬度。\n目前稳定版是 KubeSphere v3.2.1，我之前装的 k8s 集群是 v1.22.7，KubeSphere 目前对 v1.22 是实验性支持，为了避免踩坑先把 k8s 集群重装了 v1.21.5。\n安装使用 KubeSphere 的安装步骤就省略了，直接按官网的走就可以。记得要给 k8s 配默认 StorageClass，生产环境建议直接上云存储或者 rook+ceph，我为了节省资源直接就用 NFS 了。\nNFS 安装配置参考： How to Install and Configure an NFS Server on Ubuntu 20.04 How To Set Up an NFS Mount on Ubuntu 20.04\nKubeSphere 安装： 在 Kubernetes 上安装 KubeSphere\n安装完成后随便找个节点访问 30880 端口进入 dashboard。\n登录之后进入 defult 集群，在配置多集群前只有这一个。默认展示当前集群资源用量。\n界面可以切换中文显示。Projects 等同于 k8s 中的 namespace 概念，Projects 之上还有一层 workspace，用于多租户资源、计费隔离，当然也有用户权限管理。\nNodes 可以看到集群节点状态 看下 Node 详情 集群监控 Workloads 尝试在 Workloads 中创建一个 Deployment。 选择镜像，设置资源限制 端口暴露，环境变量，健康检查，容器安全设置等等 滚动更新，调度规则等等，就不过多展示了，可以选择这种引导式配置，也可以直接用 yaml 部署非常方便。\nDeployment 详情 扩缩容、版本回滚都很方便。\n","permalink":"https://ibelieving.com/posts/2022-06-25-kubesphere/","summary":"\u003ch2 id=\"介绍\"\u003e介绍\u003c/h2\u003e\n\u003cp\u003eKubeSphere 是一个 k8s 集群管理平台，可以管理多云多集群，进行统一的应用分发和运维管理，避免云厂商绑定。提供了运维友好的操作界面，支持多租户，DevOps，服务网格，多种监控纬度。\u003c/p\u003e\n\u003cp\u003e目前稳定版是 KubeSphere v3.2.1，我之前装的 k8s 集群是 v1.22.7，KubeSphere 目前对 v1.22 是实验性支持，为了避免踩坑先把 k8s 集群重装了 v1.21.5。\u003c/p\u003e\n\u003ch2 id=\"安装使用\"\u003e安装使用\u003c/h2\u003e\n\u003cp\u003eKubeSphere 的安装步骤就省略了，直接按官网的走就可以。记得要给 k8s 配默认 StorageClass，生产环境建议直接上云存储或者 rook+ceph，我为了节省资源直接就用 NFS 了。\u003c/p\u003e\n\u003cp\u003eNFS 安装配置参考：\n\u003ca href=\"https://linuxize.com/post/how-to-install-and-configure-an-nfs-server-on-ubuntu-20-04/\"\u003eHow to Install and Configure an NFS Server on Ubuntu 20.04\u003c/a\u003e\n\u003ca href=\"https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nfs-mount-on-ubuntu-20-04/\"\u003eHow To Set Up an NFS Mount on Ubuntu 20.04\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eKubeSphere 安装：\n\u003ca href=\"https://www.kubesphere.io/docs/v3.3/installing-on-kubernetes/introduction/overview/\"\u003e在 Kubernetes 上安装 KubeSphere\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e安装完成后随便找个节点访问 30880 端口进入 dashboard。\u003c/p\u003e\n\u003cp\u003e登录之后进入 defult 集群，在配置多集群前只有这一个。默认展示当前集群资源用量。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"default Nodes\" loading=\"lazy\" src=\"/images/kk1.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e界面可以切换中文显示。Projects 等同于 k8s 中的 namespace 概念，Projects 之上还有一层 workspace，用于多租户资源、计费隔离，当然也有用户权限管理。\u003c/p\u003e\n\u003cp\u003eNodes 可以看到集群节点状态\n\u003cimg alt=\"Nodes\" loading=\"lazy\" src=\"/images/kk2.jpg\"\u003e\u003c/p\u003e","title":"KubeSphere k8s 集群管理"},{"content":"介绍 虽然是一篇 k8s 的部署文，但也充满了曲折。归其原因也是基础一般。 本文并未涉及 k8s 多主高可用，可参考其它文章通过 ipvs 来实现。\n首先通过上次的文章组网 通过 Netmaker 配置 WireGuard 跨 VPC 组网，组网完成部署 k8s、k3s 都可以，我这三台小弱鸡更适合 k3s。\nhostname 外网ip 内网ip wg ip os ten-1 62.234.xxx.xxx 172.21.0.1 10.1.0.1 Ubuntu 20.04 ten-2 82.156.xxx.xxx 10.0.8.1 10.1.0.2 Ubuntu 20.04 ten-3 81.70.xxx.xxx 10.0.24.1 10.1.0.3 Ubuntu 20.04 先说下为何换到了 Ubuntu，之前在 CentOS 7.6 下已经组网完成且部署完 k8s ，使用中发现容器经常报这个错 failed to write 1 to memory.kmem.limit_in_bytes xxxx memory.kmem.limit_in_bytes: operation not supported，内存指令相关错误。\n尝试将容器内存资源限制删除，该错误可消失恢复正常。 这也不是长久之计，网上参考别人经验，我当时内核为 5.16，可以降级内核解决，但是我要用 WireGuard 低版本内核就使不了。\n索性换了系统算了，且 Ubuntu 20.04 的 5.4 内核已经包含了 WireGuard，而且也没见人说 Debian 系有 memory.kmem.limit_in_bytes 的问题。\nmemory.kmem.limit_in_bytes 报错参考\nhttps://kubesphere.com.cn/forum/d/6677-310516ks https://en.pingcap.com/blog/try-to-fix-two-linux-kernel-bugs-while-testing-tidb-operator-in-k8s/ 安装部署 k8s 版本 为 v1.22.7 容器运行时采用 containerd 网络组件采用 calico 所有节点 修改各个节点 hostname\n$ hostnamectl set-hostname xxx 安装脚本，可以保存为 .sh 脚本直接跑。\n# 配置各节点 host cat \u0026lt;\u0026lt;EOF | sudo tee -a /etc/hosts 10.1.0.1 ten-1 10.1.0.2 ten-2 10.1.0.3 ten-3 EOF swapoff -a rm -f /swap.img # --- containerd 安装 --- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo \\ \u0026#34;deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu/ \\ $(lsb_release -cs) stable\u0026#34; | sudo tee /etc/apt/sources.list.d/docker.list \u0026gt; /dev/null sudo apt update \u0026amp;\u0026amp; sudo apt install containerd.io cat \u0026lt;\u0026lt;EOF | sudo tee /etc/modules-load.d/containerd.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter cat \u0026lt;\u0026lt;EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 EOF sudo sysctl --system sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml # sandbox 默认会下 k8s.gcr.io 的，国内网络会有问题，替换下，参考下面问题排查 sed -i \u0026#39;s#sandbox_image = \u0026#34;.*\u0026#34;#sandbox_image = \u0026#34;registry.aliyuncs.com/google_containers/pause:3.5\u0026#34;#g\u0026#39; /etc/containerd/config.toml systemctl restart containerd # --- kubeadm 安装 --- cat \u0026lt;\u0026lt;EOF | sudo tee /etc/modules-load.d/k8s.conf br_netfilter EOF cat \u0026lt;\u0026lt;EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sudo sysctl --system sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg echo \u0026#34;deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main\u0026#34; | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet=1.22.7-00 kubeadm=1.22.7-00 kubectl=1.22.7-00 sudo apt-mark hold kubelet kubeadm kubectl master 节点 kubeadm.yaml 配置如下，注意修改 controlPlaneEndpoint、advertiseAddress\napiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration networking: podSubnet: 100.64.0.0/10 kubernetesVersion: v1.22.7 controlPlaneEndpoint: \u0026#34;ten-1:6443\u0026#34; imageRepository: registry.aliyuncs.com/google_containers --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: \u0026#34;ipvs\u0026#34; --- apiVersion: kubeadm.k8s.io/v1beta2 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 10.1.0.1 nodeRegistration: criSocket: /run/containerd/containerd.sock calico.yaml 配置直接下载\n$ wget https://projectcalico.docs.tigera.io/manifests/calico.yaml # --- 集群初始化 --- kubeadm init --config ./kubeadm.yaml mkdir ~/.kube sudo cp /etc/kubernetes/admin.conf ~/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config kubectl taint nodes --all node-role.kubernetes.io/master- kubectl apply -f ./calico.yaml work 节点 join 命令替换成 kubeadm init 执行成功时输出的。\n# --- 加入集群 --- scp root@ten-1:/etc/kubernetes/admin.conf /etc/kubernetes/admin.conf mkdir ~/.kube sudo cp /etc/kubernetes/admin.conf ~/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config kubeadm join ten-1:6443 --token 7hepbs.ub5d984rmxc5v3pc \\ --discovery-token-ca-cert-hash sha256:981348138871c4eed993db7664a7663ec9b0e9e6fe2d038a266591174570284c 问题处理 集群初始化时，会卡在 This can take up to 4m0s\n查看 kubelet 日志 journalctl -xeu kubelet 大量报错\n\u0026#34;Error getting node\u0026#34; err=\u0026#34;node \\\u0026#34;ten-1\\\u0026#34; not found\u0026#34; \u0026#34;Error getting node\u0026#34; err=\u0026#34;node \\\u0026#34;ten-1\\\u0026#34; not found\u0026#34; 但本机上 hostname 能 ping 通。再看容器日志 journalctl -xeu containerd 有个镜像没下下来超时，奇怪不是改了仓库地址。\n看下需要的镜像\n$ kubeadm config images list --kubernetes-version=v1.22.7 k8s.gcr.io/kube-apiserver:v1.22.7 k8s.gcr.io/kube-controller-manager:v1.22.7 k8s.gcr.io/kube-scheduler:v1.22.7 k8s.gcr.io/kube-proxy:v1.22.7 k8s.gcr.io/pause:3.4.1 k8s.gcr.io/etcd:3.4.13-0 k8s.gcr.io/coredns/coredns:v1.8.0 并没有 pause:3.5。看看别的配置文件，发现 /etc/containerd/config.toml 中 sandbox_image 用到了。\nsandbox_image = \u0026#34;k8s.gcr.io/pause:3.5\u0026#34; 直接改成 registry.aliyuncs.com/google_containers/pause:3.5 也可以手动从阿里云下载，打 tag。\n下载 nerdctl 让 containerd 用起来像 docker 一样。\nnerdctl pull registry.aliyuncs.com/google_containers/pause:3.5 --namespace \u0026#34;k8s.io\u0026#34; nerdctl tag registry.aliyuncs.com/google_containers/pause:3.5 k8s.gcr.io/pause:3.5 --namespace \u0026#34;k8s.io\u0026#34; 其它命令 kubectl get all --all-namespaces # 手动下载镜像 kubeadm config images pull --kubernetes-version=v1.22.7 --image-repository registry.aliyuncs.com/google_containers # 查看配置模版 kubeadm config print init-defaults # 重置集群 kubeadm reset # 查看可安装 kube 版本 apt-cache madison kubelet # 卸载 kube apt-mark unhold kubeadm kubelet kubectl apt-get remove -y kubelet=1.22.7-00 kubeadm=1.22.7-00 kubectl=1.22.7-00 # 卸载 docker containerd apt-get purge docker-ce docker-ce-cli containerd.io # 查看已有镜像 nerdctl images --namespace \u0026#34;k8s.io\u0026#34; 参考 container-runtimes install-kubeadm create-cluster-kubeadm calico self managed onprem ","permalink":"https://ibelieving.com/posts/2022-04-03-ubuntu_k8s/","summary":"\u003ch2 id=\"介绍\"\u003e介绍\u003c/h2\u003e\n\u003cp\u003e虽然是一篇 k8s 的部署文，但也充满了曲折。归其原因也是基础一般。 本文并未涉及 k8s 多主高可用，可参考其它文章通过 ipvs 来实现。\u003c/p\u003e\n\u003cp\u003e首先通过上次的文章组网 \u003ca href=\"/posts/2022-03-13-netmaker/\"\u003e通过 Netmaker 配置 WireGuard 跨 VPC 组网\u003c/a\u003e，组网完成部署 k8s、k3s 都可以，我这三台小弱鸡更适合 k3s。\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003ehostname\u003c/th\u003e\n          \u003cth\u003e外网ip\u003c/th\u003e\n          \u003cth\u003e内网ip\u003c/th\u003e\n          \u003cth\u003ewg ip\u003c/th\u003e\n          \u003cth\u003eos\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eten-1\u003c/td\u003e\n          \u003ctd\u003e62.234.xxx.xxx\u003c/td\u003e\n          \u003ctd\u003e172.21.0.1\u003c/td\u003e\n          \u003ctd\u003e10.1.0.1\u003c/td\u003e\n          \u003ctd\u003eUbuntu 20.04\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eten-2\u003c/td\u003e\n          \u003ctd\u003e82.156.xxx.xxx\u003c/td\u003e\n          \u003ctd\u003e10.0.8.1\u003c/td\u003e\n          \u003ctd\u003e10.1.0.2\u003c/td\u003e\n          \u003ctd\u003eUbuntu 20.04\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eten-3\u003c/td\u003e\n          \u003ctd\u003e81.70.xxx.xxx\u003c/td\u003e\n          \u003ctd\u003e10.0.24.1\u003c/td\u003e\n          \u003ctd\u003e10.1.0.3\u003c/td\u003e\n          \u003ctd\u003eUbuntu 20.04\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e先说下为何换到了 \u003ccode\u003eUbuntu\u003c/code\u003e，之前在 \u003ccode\u003eCentOS 7.6\u003c/code\u003e 下已经组网完成且部署完 k8s ，使用中发现容器经常报这个错 \u003ccode\u003efailed to write 1 to memory.kmem.limit_in_bytes xxxx memory.kmem.limit_in_bytes: operation not supported\u003c/code\u003e，内存指令相关错误。\u003c/p\u003e\n\u003cp\u003e尝试将容器内存资源限制删除，该错误可消失恢复正常。 这也不是长久之计，网上参考别人经验，我当时内核为 \u003ccode\u003e5.16\u003c/code\u003e，可以降级内核解决，但是我要用 \u003ccode\u003eWireGuard\u003c/code\u003e 低版本内核就使不了。\u003c/p\u003e\n\u003cp\u003e索性换了系统算了，且 \u003ccode\u003eUbuntu 20.04\u003c/code\u003e 的 \u003ccode\u003e5.4\u003c/code\u003e 内核已经包含了 \u003ccode\u003eWireGuard\u003c/code\u003e，而且也没见人说 Debian 系有 \u003ccode\u003ememory.kmem.limit_in_bytes\u003c/code\u003e 的问题。\u003c/p\u003e","title":"Ubuntu 20.04 下部署 k8s v1.22.7 集群"},{"content":"介绍 最近云服务商做活动，手里云主机又多了一个，国内的有三台了，可以组个 k8s 集群了。本文介绍如何跨 VPC 组网，机器情况如下。\nhostname 外网ip 内网ip os ten-1 62.234.xxx.xxx 172.21.0.1 CentOS 7.6 ten-2 82.156.xxx.xxx 10.0.8.1 CentOS 7.9 ten-3 81.70.xxx.xxx 10.0.24.1 CentOS 7.6 MacBook - - Darwin 10.15.6 WireGuard 是由 C 语言写的开源 VPN 方案。概括来讲更快、更简单、更安全，Linux 内核 5.6 版本开始自带。且支持全平台。 Netmaker 是一个可视化操作工具，方便我们对 WrireGuard 的配置管理，相比于直接写配置，当节点多起来会便捷不少。 简单说下运行流程，Netmaker 分服务端和客户端，客户端是 netclient。我们在 Netmaker 上创建虚拟网络，然后在想要加入网络的节点上通过 netclient 加入。Netmaker 会对加入网络的节点自动同步 WireGuard 的配置信息，创建相应的路由规则，之后节点与节点之间的通信直接进行。 本文只是介绍了一部分 Netmaker 功能，更多内容请看 Netmaker 官方文档。\n为了方便 CentOS 内核都已升级至 5.16，自带了 WireGuard。升级内核教程很多就不多说了。\nNetmaker 部署 在 ten-1 上先创建所需目录\n$ mkdir -p /etc/netclient/config $ mkdir -p /data/netmaker 直接容器化部署，compose yml 如下：\nversion: \u0026#34;3.4\u0026#34; services: netmaker: container_name: netmaker image: gravitl/netmaker:v0.9.4 volumes: - /etc/netclient/config:/etc/netclient/config - dnsconfig:/root/config/dnsconfig - /usr/bin/wg:/usr/bin/wg - /data/netmaker:/root/data cap_add: - NET_ADMIN restart: always network_mode: host environment: SERVER_HOST: \u0026#34;SERVER_PUBLIC_IP\u0026#34; COREDNS_ADDR: \u0026#34;SERVER_PUBLIC_IP\u0026#34; GRPC_SSL: \u0026#34;off\u0026#34; DNS_MODE: \u0026#34;on\u0026#34; # dns 不需要直接 off 把下面 coredns 部分也注释 CLIENT_MODE: \u0026#34;on\u0026#34; # 开启 CLIENT_MODE 则默认将 netmaker server 也当做网络节点 API_PORT: \u0026#34;8081\u0026#34; # 记得在服务器安全策略或防火墙上对该端口放行 GRPC_PORT: \u0026#34;50051\u0026#34; # 记得在服务器安全策略或防火墙上对该端口放行 SERVER_GRPC_WIREGUARD: \u0026#34;off\u0026#34; CORS_ALLOWED_ORIGIN: \u0026#34;*\u0026#34; DATABASE: \u0026#34;sqlite\u0026#34; netmaker-ui: container_name: netmaker-ui depends_on: - netmaker image: gravitl/netmaker-ui:v0.9.4 links: - \u0026#34;netmaker:api\u0026#34; ports: - \u0026#34;127.0.0.1:8082:80\u0026#34; # 如果你没有域名直接用公网ip就改成 \u0026#34;80:80\u0026#34; environment: BACKEND_URL: \u0026#34;https://api.NETMAKER_BASE_DOMAIN\u0026#34; # 无证书用http，如果你没有域名直接用公网ip就改成 \u0026#34;http://SERVER_PUBLIC_IP:8081\u0026#34; restart: always coredns: depends_on: - netmaker image: coredns/coredns command: -conf /root/dnsconfig/Corefile container_name: coredns restart: always network_mode: host volumes: - dnsconfig:/root/dnsconfig volumes: dnsconfig: {} 更多参数配置请参考\n官方 compose 示例 官方说明 如果你是直接用公网ip方式访问 netmaker ui 那直接把注释说明的地方修改下跑起来就可以进入下一节了。\n如果你使用域名访问，可以参考下我的方案。 首先解析域名 api.NETMAKER_BASE_DOMAIN，dashboard.NETMAKER_BASE_DOMAIN 至 ten-1。 然后我使用 Traefik 将域名 dashboard.NETMAKER_BASE_DOMAIN 反代 netmaker ui 也就是 127.0.0.1:8082。你可以参考官网选择 Caddy 或 Nginx。 Traefik 配置就不贴了，之前文章写过很多次。\nNetmaker 创建网络 打开 Netmaker UI，首次打开会创建一个用户，然后登录。\nNetworks 虚拟网络管理 Nodes 节点管理，Ingress 和 Egress 网关配置等。 Access Keys 密钥管理 External Clients 安卓或苹果端加入网络使用 DNS Users 配置用户管理网络，支持多租户 然后进入 Networks 创建一个虚拟网络，比如 10.1.0.0/16。\n网络默认监听端口是 51821 记得对该端口放行（运行Netmaker的节点） 这样虚拟网络就创建成功了。\n加入节点 加入节点有两种方式，先说第一种：\n在网络里点 Access keys 创建 Key，获得 Token。\nuses 代表这个 Key 可以用于几个节点\n然后去要加入网络的节点上执行 Install Commands 加入网络。执行的逻辑就是下载 netclient 然后通过 Token 加入网络，Token 里面包含了 Netmaker 的服务端配置信息。 所以你也可以从 这里 手动下载 netclient 执行：netclient join -t TOKEN 。\n第二种是进入网络把 Without Keys 打开\n然后在节点上执行\nnetclient join --dnson no --network ten --apiserver NETMAKE_DOMAIN_OR_IP:8081 --grpcserver NETMAKE_DOMAIN_OR_IP:50051\n在 Nodes 下对刚加入的节点执行同意加入\nmacOS 的加入 也是先下载 netclient，下载时候注意平台如果是 M1 芯片下载 darwin-arm64，之后安装 wireguard-tools:\n$ brew install wireguard-tools 然后执行 netclient join 就行了。\n查看节点 在节点上执行 wg 可以看到加入的虚拟网络和链接的节点。\n$ wg interface: nm-ten public key: aH4j5K2TiYhhwI9Bz0tmxxxx private key: (hidden) listening port: 51821 peer: mbv8tihsqvvtgcejLGB+xxxxx endpoint: 81.70.xxx.xxx:51821 allowed ips: 10.1.0.3/32 latest handshake: 35 seconds ago transfer: 14.37 MiB received, 54.71 MiB sent persistent keepalive: every 20 seconds peer: WDEfuS8deFQyd6syZJNtaxxxx endpoint: 82.156.xxx.xxx:51821 allowed ips: 10.1.0.2/32 latest handshake: 35 seconds ago transfer: 36.74 MiB received, 542.48 MiB sent persistent keepalive: every 20 seconds 网络不通请检查 endpoint 端口的连通性 已经成功分配了ip，ping 一下试试。\n$ ping 10.1.0.2 PING 10.1.0.2 (10.1.0.2) 56(84) bytes of data. 64 bytes from 10.1.0.2: icmp_seq=1 ttl=64 time=8.69 ms 64 bytes from 10.1.0.2: icmp_seq=2 ttl=64 time=9.74 ms 64 bytes from 10.1.0.2: icmp_seq=3 ttl=64 time=51.0 ms ^C --- 10.1.0.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 8.698/23.165/51.057/19.727 ms $ ping 10.1.0.3 PING 10.1.0.3 (10.1.0.3) 56(84) bytes of data. 64 bytes from 10.1.0.3: icmp_seq=1 ttl=64 time=0.893 ms 64 bytes from 10.1.0.3: icmp_seq=2 ttl=64 time=0.948 ms 64 bytes from 10.1.0.3: icmp_seq=3 ttl=64 time=1.01 ms ^C --- 10.1.0.3 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2032ms rtt min/avg/max/mdev = 0.893/0.951/1.014/0.060 ms 网络已经打通了！\nIngress GateWay 和 External Clients 外部客户端，就是可以访问虚拟网络资源，但是虚拟网络内节点不能反过来访问该外部客户端。通过 Ingress GateWay 入口网关实现。 具体就是选择一个节点开启 Ingress GateWay 使其变成一个中继节点，然后在其上添加外部客户端 External Clients 生成配置文件及二维码。中继节点负责为外部客户端的流量请求进行转发。 Linux、macOS、Windows 可以通过 wg-quick up /path/to/config 命令接入网络。 Android 和 iOS 下载 WireGuard App 通过扫描配置二维码就可以接入网络了。\n生成的配置是固定的，网络节点配置修改后需要重新生成配置 Egress GateWay 比如我现在的组网状态下，ten-2 节点私有局域网段是 10.0.8.0/22，ten 网络内其它节点想要访问该私有局域网段的其它服务器，通过 Egress GateWay 出口网关可以实现。\n在 ten-2 节点上创建出口网关后通过 wg 查看配置同步完成网络就打通了。另外通过逗号分隔可以支持多个网段。\n$ wg interface: nm-ten public key: aH4j5K2TiYhhwI9Bz0tmxxxx private key: (hidden) listening port: 51821 peer: mbv8tihsqvvtgcejLGB+xxxxx endpoint: 81.70.xxx.xxx:51821 allowed ips: 10.1.0.3/32 latest handshake: 55 seconds ago transfer: 644.40 MiB received, 24.83 MiB sent persistent keepalive: every 20 seconds peer: WDEfuS8deFQyd6syZJNtaxxxx endpoint: 82.156.xxx.xxx:51821 allowed ips: 10.1.0.2/32, 10.0.8.0/22 latest handshake: 44 seconds ago transfer: 569.67 MiB received, 38.38 MiB sent persistent keepalive: every 20 seconds 其它 组网成功后部署了 k8s 集群, 可以进一步折腾了。\n另外推荐一个 k8s 可视化管理工具 Lens，号称是 k8s 的 IDE，操作 k8s 相当方便。\n","permalink":"https://ibelieving.com/posts/2022-03-13-netmaker/","summary":"\u003ch1 id=\"介绍\"\u003e介绍\u003c/h1\u003e\n\u003cp\u003e最近云服务商做活动，手里云主机又多了一个，国内的有三台了，可以组个 k8s 集群了。本文介绍如何跨 VPC 组网，机器情况如下。\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003ehostname\u003c/th\u003e\n          \u003cth\u003e外网ip\u003c/th\u003e\n          \u003cth\u003e内网ip\u003c/th\u003e\n          \u003cth\u003eos\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eten-1\u003c/td\u003e\n          \u003ctd\u003e62.234.xxx.xxx\u003c/td\u003e\n          \u003ctd\u003e172.21.0.1\u003c/td\u003e\n          \u003ctd\u003eCentOS 7.6\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eten-2\u003c/td\u003e\n          \u003ctd\u003e82.156.xxx.xxx\u003c/td\u003e\n          \u003ctd\u003e10.0.8.1\u003c/td\u003e\n          \u003ctd\u003eCentOS 7.9\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eten-3\u003c/td\u003e\n          \u003ctd\u003e81.70.xxx.xxx\u003c/td\u003e\n          \u003ctd\u003e10.0.24.1\u003c/td\u003e\n          \u003ctd\u003eCentOS 7.6\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMacBook\u003c/td\u003e\n          \u003ctd\u003e-\u003c/td\u003e\n          \u003ctd\u003e-\u003c/td\u003e\n          \u003ctd\u003eDarwin 10.15.6\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eWireGuard\u003c/code\u003e 是由 \u003ccode\u003eC\u003c/code\u003e 语言写的开源 \u003ccode\u003eVPN\u003c/code\u003e 方案。概括来讲更快、更简单、更安全，\u003ccode\u003eLinux\u003c/code\u003e 内核 \u003ccode\u003e5.6\u003c/code\u003e 版本开始自带。且支持全平台。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eNetmaker\u003c/code\u003e 是一个可视化操作工具，方便我们对 \u003ccode\u003eWrireGuard\u003c/code\u003e 的配置管理，相比于直接写配置，当节点多起来会便捷不少。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e简单说下运行流程，\u003ccode\u003eNetmaker\u003c/code\u003e 分服务端和客户端，客户端是 \u003ccode\u003enetclient\u003c/code\u003e。我们在 \u003ccode\u003eNetmaker\u003c/code\u003e 上创建虚拟网络，然后在想要加入网络的节点上通过 \u003ccode\u003enetclient\u003c/code\u003e 加入。\u003ccode\u003eNetmaker\u003c/code\u003e 会对加入网络的节点自动同步 \u003ccode\u003eWireGuard\u003c/code\u003e 的配置信息，创建相应的路由规则，之后节点与节点之间的通信直接进行。\n本文只是介绍了一部分 \u003ccode\u003eNetmaker\u003c/code\u003e 功能，更多内容请看 \u003ca href=\"https://docs.netmaker.org/index.html\"\u003eNetmaker 官方文档\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e为了方便 \u003ccode\u003eCentOS\u003c/code\u003e 内核都已升级至 \u003ccode\u003e5.16\u003c/code\u003e，自带了 \u003ccode\u003eWireGuard\u003c/code\u003e。升级内核教程很多就不多说了。\u003c/p\u003e\n\u003ch1 id=\"netmaker-部署\"\u003eNetmaker 部署\u003c/h1\u003e\n\u003cp\u003e在 \u003ccode\u003eten-1\u003c/code\u003e 上先创建所需目录\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ mkdir -p /etc/netclient/config\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ mkdir -p /data/netmaker\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e直接容器化部署，\u003ccode\u003ecompose yml\u003c/code\u003e 如下：\u003c/p\u003e","title":"通过 Netmaker 配置 WireGuard 跨 VPC 组网"},{"content":"近期阅读了《考试脑科学：脑科学中的高效记忆法》做个笔记。该书前面讲解了人脑记忆的原理，海马体、杏仁核、θ波等。后面讲解了记忆的种类，人处于什么状态记忆力更好等等。\n《高中生学习法》出版已有十余年。这期间，脑科学研究不断进步，十几年前无法解释的事情现在已 经开始逐渐明晰。同时，书中有些内容甚至已经被明确证实是错误的。也就是说，《高中生学习法》 这本书，仅十余年就已落后于时代了。\n需要说明的是《考试脑科学》是《高中生学习法》(出版于2002年)的修订版。《考试脑科学》原书于2011年出版，中文翻译版于2019年出版。现在2022年已经又过去十年了，不知道脑科学进步没。\n◆ 2-4 蛮干终究是徒劳\n潜在记忆的保存时间只有 1 个月左右，如果不在 1个月以内复习学到的知识，潜在记忆就无法发挥作用了。\n意思是一个月之后再去复习和学习新知识没有什么区别\n在复习时也要像初次学习那样用功，不仅要用眼看，还要动笔写、出声读，尽可能地调动自己的感官。这样一来，通过视觉、听觉、触觉等传达的信息都会对刺激海马体起到积极作用。\n刺激方面越多对知识的记忆越深刻\n结合海马体的性质，我建议大家按照如下计划展开复习。第 1 次复习：学习后的第 2 天第 2 次复习：第 1 次复习 1 周后第 3 次复习：第 2 次复习 2 周后第 4 次复习：第 3 次复习 1 个月后\n◆ 3-2 童心是提高成绩的“营养素”\n畅销书作家韦恩·戴尔 5 曾这样说：“一个人在早上醒来后，首先想到的是‘很好，新的一天开始了’，还是‘哎，怎么又要起床了’，完全取决于他的心态。”确实如此。学习也和心情有关，我们要像孩子一样，无论在何时都应该保持一颗易受感动的心。包含好奇心和憧憬心的“童心”，正是促使θ波出现的重要因素。\n大家上学时应该都有过的经历，感兴趣的科目学起来很快，没兴趣的怎么学也不会。这里可以说是做了解释，当你对知识好奇、感兴趣时会出现 θ脑电波，θ波的出现有对记忆力增强的效果，可以事半功倍。\n◆ 3-5 狮子记忆法\n通过狮子记忆法，我们可以推测出饥饿、走动和降低室温这 3 种能提高记忆力的技巧。\n如果要解释得稍微专业一些，那就是当肚子饿的时候我们的胃会分泌一种名为食欲刺激激素 (ghrelin)的饥饿激素。这种饥饿激素能随血液循环进入海马体，促使海马体神经元产生LTP。相反，在吃饱后不仅饥饿激素的水平会降低，而且血液还会相对集中于胃部和肠道，这往往会导致脑 的活动水平降低。\n来回走动及坐车或脑能感知到正在移动时会自动产生θ波。\n◆ 4-3 睡眠和记忆\n在睡觉前把题目过一遍也是一种很重要的学习技巧。\n◆ 4-6 能有效利用全天时间的学习方案\n饭前处于饥饿状态，正适合学习。睡觉前也是学习的黄金期。早饭或晚饭后处于饱腹状态时，不学习也不要紧。\n睡觉前非常适合学习那些需要记忆的知识，比如数据库原理、调度器原理；上午可以说是人在一天之中最清醒的时间，用来学习对逻辑思维能力要求比较高的比如刷题；最后，因为在早上刚起床的这段时间内不适合背诵，所以只要做一些简单的计算或者复习就可以了。\n做了些修改替换，哈哈。\n◆ 5-2 面对失败，毫不气馁的积极态度最重要\n每次经历失败后，我们都应该思考下一次要怎么做才能成功。如果还是失败了，就再次思考其他解决方案……像这样不断循环下去。失败的次数越多，就越能形成准确牢固的记忆。即使偶尔取得了几次不错的成绩，对于大家来说其实也并没有什么实质性的收获。所以，即使考试成绩不理想也没必要闷闷不乐，大家可以转换思维，把它当作一件好事而非坏事。失败后最重要的是带着疑问找出失败原因，并想出解决方案\n因此，对于学习来说，“善于反省”和“保持乐观”也很重要。\n我们需要透过自身这扇窗户观望世界，所以必须不断磨砺自己。\n◆ 脑心理学专栏 13 / 葡萄糖\n补充葡萄糖能让脑活跃起来。\n◆ 5-7 带着长期计划去学习\n当我们想要学习某一领域的知识时，最重要的是理解和把握知识的整体概貌。在刚开始的时候，可以先忽略细节，首先把握全局，之后再一点点地记忆细节。总之，脑的记忆是模糊的，刚开始并不能区分出相似的事物。\n◆ 5-8 先扩大擅长科目的优势\n首先，不管具体是哪一科，总之要有一门擅长的科目。在有了一门不输给任何人的擅长科目之后再去挑战其他科目的学习，这种学习方法从脑科学的角度来看是非常有效的。\n◆ 6-2 联想很重要\n此外，“想象”这种行为还可以强烈地刺激海马体，也就是说它具有精致化和活跃海马体这两个优点。越充分地发挥自己的想象力，记忆就越能长时间地保留下来。\n要想顺利地发挥想象，最好的方法就是自己创作用于记忆的谐音，因为创作过程本身就是一种“经验记忆”，所以自然就能想象出谐音文字所描绘的情境来。当然，即使不使用谐音记忆法，联想也很重要。只是在这种情况下，与单纯地把知识或信息关联起来相比，我们更需要充分发挥自己的想象力，让知识的内容更加丰富。如果条件允许，大家最好能结合自己的实际经验记忆，这样效果会更好。自己的经验与记忆关联得越多，记忆就越接近经验记忆。\n知识记忆就是从书上学到的或别人讲的。 经验记忆好比是自己实际经历过后产生的。\n◆ 6-3 向别人讲述学到的知识\n你想记住哪些信息，就把哪些信息讲给自己的朋友或者家人听——这就是形成经验记忆的最简单的方法。\n博学的人几乎毫无例外，都是在平时就有强烈的讲述欲望的人。\n虽然“经验记忆法”看起来像是万能的，但遗憾的是它也有缺点，那就是经验记忆会逐渐转化成知识记忆。即使是好不容易才形成的经验记忆，如果我们置之不理，那么我们在记忆中带入的体验感就会慢慢弱化，它终有一天会转化为知识记忆。\n所以，我们要试着经常向别人讲述那些必须能随时想起来的重要知识，通过自己的不断努力，让它们重新转化为经验记忆。\n◆ 作者之见\n人更容易记住位于视野左侧的内容，这大概是右脑在发挥作用。相反，读到或者听到的那些和“语言”相关的内容，则似乎是从右耳进入人脑并由左脑来记忆的。\n◆ 6-4 声音、听觉与记忆\n其实一般来说，使用耳朵学习要比使用眼睛学习效率更高，比如别人说过的一些伤害了我们的话会一直留在我们的心里。通过耳朵获得的记忆是非常牢固的。\n当然，并不是说只使用眼睛和耳朵学习就足够了，人的身体上还有很多其他的感觉器官，我们最好能尽量多地灵活使用它们。请大家记住，学习时一定要动笔写、出声读，通过反复输出知识来加强记忆。\n◆ 6-5 理解记忆的种类和年龄的关系\n知识记忆和经验记忆是“用头脑记住的记忆”，而方法记忆则可以说是“用身体记住的记忆”。当然，方法记忆实际上也是由人脑而并非人体记忆的，这无须多言。虽然运动员们常常说“我的肌肉已经熟记了动作”，但这只是一种比喻，因为肌肉没有记忆力。\n比如骑车的方法、开车的方法、游泳的方法。比知识记忆和经验记忆更牢靠，好比开车从书上看到怎么开是知识记忆，自己上手开是经验记忆，开的时间久了完全掌握是理解了方法。\n◆ 作者之见\n跟随优秀的老师学习，就能掌握适用于各种情况的解决方法\n◆ 6-8 会“膨胀”的记忆方法\n无论学习什么知识，重要的都是理解并掌握其背后的原理。\n大家要试着慢慢地转移学习的重心，尽量不要死记硬背，而是应该去理解知识的“背景理论”。\n◆ 6-9 为什么要持续努力？\n要想获得显著的学习效果，那么至少要从实现最终目标的前 1 年就开始学习。长期性的规划非常重要，另外就是专心致志的努力了。大家不要因为不会立即见效就心灰意冷。每当感到学习很辛苦时，请回忆起“脑的机能是呈几何级数增长的”这一事实，并不断激励自己“效果肯定会出现的，继续努力吧！”\n几何级数增长，原文意思是学习了A知识，又学习了B知识，会到四种效果，\u0026ldquo;A\u0026rdquo; \u0026ldquo;B\u0026rdquo; \u0026ldquo;从A看到的B\u0026rdquo; \u0026ldquo;从B看到的A\u0026rdquo;，知识本身加上知识间的联想即2的平方。学的越多效果越显著。\n只要继续心怀梦想，梦想就一定会实现。——歌德\n◆ 作者之见\n失败并不等于结束，一旦放弃了才是真的结束。——尼克松\n","permalink":"https://ibelieving.com/posts/2022-02-26-book_of_exam_brain_science/","summary":"\u003cp\u003e近期阅读了《考试脑科学：脑科学中的高效记忆法》做个笔记。该书前面讲解了人脑记忆的原理，海马体、杏仁核、θ波等。后面讲解了记忆的种类，人处于什么状态记忆力更好等等。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e《高中生学习法》出版已有十余年。这期间，脑科学研究不断进步，十几年前无法解释的事情现在已\n经开始逐渐明晰。同时，书中有些内容甚至已经被明确证实是错误的。也就是说，《高中生学习法》\n这本书，仅十余年就已落后于时代了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e需要说明的是《考试脑科学》是《高中生学习法》(出版于2002年)的修订版。《考试脑科学》原书于2011年出版，中文翻译版于2019年出版。现在2022年已经又过去十年了，不知道脑科学进步没。\u003c/p\u003e\n\u003cp\u003e◆ 2-4 蛮干终究是徒劳\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e潜在记忆的保存时间只有 1 个月左右，如果不在 1个月以内复习学到的知识，潜在记忆就无法发挥作用了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e意思是一个月之后再去复习和学习新知识没有什么区别\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在复习时也要像初次学习那样用功，不仅要用眼看，还要动笔写、出声读，尽可能地调动自己的感官。这样一来，通过视觉、听觉、触觉等传达的信息都会对刺激海马体起到积极作用。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e刺激方面越多对知识的记忆越深刻\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e结合海马体的性质，我建议大家按照如下计划展开复习。第 1 次复习：学习后的第 2 天第 2 次复习：第 1 次复习 1 周后第 3 次复习：第 2 次复习 2 周后第 4 次复习：第 3 次复习 1 个月后\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e◆ 3-2 童心是提高成绩的“营养素”\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e畅销书作家韦恩·戴尔 5 曾这样说：“一个人在早上醒来后，首先想到的是‘很好，新的一天开始了’，还是‘哎，怎么又要起床了’，完全取决于他的心态。”确实如此。学习也和心情有关，我们要像孩子一样，无论在何时都应该保持一颗易受感动的心。包含好奇心和憧憬心的“童心”，正是促使θ波出现的重要因素。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e大家上学时应该都有过的经历，感兴趣的科目学起来很快，没兴趣的怎么学也不会。这里可以说是做了解释，当你对知识好奇、感兴趣时会出现 θ脑电波，θ波的出现有对记忆力增强的效果，可以事半功倍。\u003c/p\u003e\n\u003cp\u003e◆ 3-5 狮子记忆法\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e通过狮子记忆法，我们可以推测出饥饿、走动和降低室温这 3 种能提高记忆力的技巧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e如果要解释得稍微专业一些，那就是当肚子饿的时候我们的胃会分泌一种名为食欲刺激激素\n(ghrelin)的饥饿激素。这种饥饿激素能随血液循环进入海马体，促使海马体神经元产生LTP。相反，在吃饱后不仅饥饿激素的水平会降低，而且血液还会相对集中于胃部和肠道，这往往会导致脑\n的活动水平降低。\u003c/p\u003e\n\u003cp\u003e来回走动及坐车或脑能感知到正在移动时会自动产生θ波。\u003c/p\u003e\n\u003cp\u003e◆ 4-3 睡眠和记忆\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在睡觉前把题目过一遍也是一种很重要的学习技巧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e◆ 4-6 能有效利用全天时间的学习方案\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e饭前处于饥饿状态，正适合学习。睡觉前也是学习的黄金期。早饭或晚饭后处于饱腹状态时，不学习也不要紧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e睡觉前非常适合学习那些需要记忆的知识，比如数据库原理、调度器原理；上午可以说是人在一天之中最清醒的时间，用来学习对逻辑思维能力要求比较高的比如刷题；最后，因为在早上刚起床的这段时间内不适合背诵，所以只要做一些简单的计算或者复习就可以了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e做了些修改替换，哈哈。\u003c/p\u003e\n\u003cp\u003e◆ 5-2 面对失败，毫不气馁的积极态度最重要\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e每次经历失败后，我们都应该思考下一次要怎么做才能成功。如果还是失败了，就再次思考其他解决方案……像这样不断循环下去。失败的次数越多，就越能形成准确牢固的记忆。即使偶尔取得了几次不错的成绩，对于大家来说其实也并没有什么实质性的收获。所以，即使考试成绩不理想也没必要闷闷不乐，大家可以转换思维，把它当作一件好事而非坏事。失败后最重要的是带着疑问找出失败原因，并想出解决方案\u003c/p\u003e","title":"关于学习和记忆的原理《考试脑科学》"},{"content":"之前用server酱的微信消息推送服务，但是最近老抽风，准备换别的推送服务。\n目前发现企业微信的应用消息很合适优点不少。个人也可注册使用。\n图文消息 mpnews 内容最大支持666K字节 一次可最多发送八条消息，虽然基本都是发单条 可以显示摘要 可以消息免打扰 虽然是企业微信的应用消息，但是通过关注微信插件可以直接在微信app内查看消息。\n简单使用 Golang 编写了一个腾讯 Serverless 云函数，实现了类似于server酱的消息推送，GET、POST方式调用均可。\n腾讯云函数目前每月都有免费额度个人完全够用了，API网关新开会送一年资源包也是够用完全白嫖。可以绑定自有域名，选择香港区域，不用备案。\n一年到期之后，可以转战阿里云。代码很简单，改改也可以直接docker部署。\n详见GitHub wx-msg-push-tencent\n","permalink":"https://ibelieving.com/posts/2021-03-15-wx_work_msg_push/","summary":"\u003cp\u003e之前用server酱的微信消息推送服务，但是最近老抽风，准备换别的推送服务。\u003c/p\u003e\n\u003cp\u003e目前发现企业微信的应用消息很合适优点不少。个人也可注册使用。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e图文消息 mpnews 内容最大支持666K字节\u003c/li\u003e\n\u003cli\u003e一次可最多发送八条消息，虽然基本都是发单条\u003c/li\u003e\n\u003cli\u003e可以显示摘要\u003c/li\u003e\n\u003cli\u003e可以消息免打扰\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg alt=\"图文消息摘要效果\" loading=\"lazy\" src=\"/images/wx_work_msg_push.png\"\u003e\u003c/p\u003e\n\u003cp\u003e虽然是企业微信的应用消息，但是通过关注微信插件可以直接在微信app内查看消息。\u003c/p\u003e\n\u003cp\u003e简单使用 Golang 编写了一个腾讯 Serverless 云函数，实现了类似于server酱的消息推送，GET、POST方式调用均可。\u003c/p\u003e\n\u003cp\u003e腾讯云函数目前每月都有免费额度个人完全够用了，API网关新开会送一年资源包也是够用完全白嫖。可以绑定自有域名，选择香港区域，不用备案。\u003c/p\u003e\n\u003cp\u003e一年到期之后，可以转战阿里云。代码很简单，改改也可以直接docker部署。\u003c/p\u003e\n\u003cp\u003e详见GitHub \u003ca href=\"https://github.com/zyh94946/wx-msg-push-tencent\"\u003ewx-msg-push-tencent\u003c/a\u003e\u003c/p\u003e","title":"通过企业微信构建消息推送服务"},{"content":"nps 是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持 tcp、udp 流量转发，可支持任何 tcp、udp 上层协议（访问内网网站、本地支付接口调试、ssh 访问、远程桌面，内网 dns 解析等等……），此外还支持内网 http 代理、内网 socks5 代理、p2p 等，并带有功能强大的 web 管理端。\n实现结构图 +---------------+ +---------------------------------------+ +--------------------------------------------+ | | | | | | | traffic | | Server x.x.x.x | | | | | | | | | | | | nps web | | | | | | +---------+ +--------------+ | | intranet | | nps.test.com -----\u0026gt; | Traefik | +--\u0026gt; |127.0.0.1:8081| | | | | | | +---------+ +--------------+ | | | | | | | | | | | | | | nps Client | | | | +---------+ x.x.x.x:8024 | +-------------+ :5900 +-------------+ | | x.x.x.x:8001 -----\u0026gt; | nps | \u0026lt;------------------------------\u0026gt; | 10.1.50.100 | +-----\u0026gt; | 10.1.50.101 | | | | | +---------+ | | +-------------+ +-------------+ | | | | | | | +---------------+ +---------------------------------------+ +--------------------------------------------+ 服务端：CentOS 7.9 客户端：MacOS 10.15\ntraefik traefik 之前有过介绍，不再多说。仅作为 nps web 管理的前置路由，解包 https 转发给本地的 nps http 服务。虽然 nps 也是支持 https 的，但是我使用 traefik 作为统一流量入口管理更方便。\n首先解析域名举例 nps.test.com 至服务端主机。 修改 file provider 配置新增 nps 服务和路由。转发 https://nps.test.com/ 请求至 http://127.0.0.1:8081/。\n[http.routers.my-nps] rule = \u0026#34;Host(`nps.test.com`)\u0026#34; service = \u0026#34;nps-server\u0026#34; [http.routers.my-nps.tls] certResolver = \u0026#34;sample\u0026#34; [[http.routers.my-nps.tls.domains]] main = \u0026#34;nps.test.com\u0026#34; [http.services.nps-server] [http.services.nps-server.loadBalancer] [[http.services.nps-server.loadBalancer.servers]] url = \u0026#34;http://127.0.0.1:8081/\u0026#34; 如果你 traefik 配置和我之前的一样修改完成就已经生效了不用重启。\n服务端 nps 从这里下载 nps 服务端，客户端也是从这下。\n修改 conf/nps.conf 配置文件。\nappname = nps runmode = dev # 服务端客户端通信的 协议、端口、ip bridge_type=tcp bridge_port=8024 bridge_ip=0.0.0.0 public_vkey= # log level LevelEmergency-\u0026gt;0 LevelAlert-\u0026gt;1 LevelCritical-\u0026gt;2 LevelError-\u0026gt;3 LevelWarning-\u0026gt;4 LevelNotice-\u0026gt;5 LevelInformational-\u0026gt;6 LevelDebug-\u0026gt;7 log_level=7 log_path=/var/log/nps.log # web 管理的 用户名、密码、监听端口、ip web_username=admin web_password=ow@ner web_port=8081 web_ip=127.0.0.1 disconnect_timeout=60 执行安装命令，启动服务端。\n$ sudo ./nps install $ sudo nps start install 之后，可执行文件和配置文件会复制到 /etc/nps/ 下，同时会安装为系统服务。 启动之后 tail 日志看有无报错，netstat 看端口监听是否正常。 打开 nps.test.com 进入 web 管理后台，新增一个客户端，唯一密钥建议留空自动生成即可。\n客户端(内网) nps 同样下载 nps 客户端，修改客户端配置 conf/npc.conf。\n[common] # 服务端ip 自行修改 server_addr=0.0.0.0:8024 # 唯一密钥 vkey=0000000 # 是否自动重连 auto_reconnection=true conn_type=tcp # 是否加密 crypt=false # 是否压缩 compress=false disconnect_timeout=60 手动执行测试看配置链接是否正常\n$ ./npc -config=/path/conf/npc.conf 链接正常同样安装为服务\n$ sudo ./npc install install 之后可执行文件会复制到 /usr/local/bin/ 下。同时会创建一个 launchctl 配置文件 /Library/LaunchDaemons/Npc.plist 这是 mac 下的定时任务、守护进程管理利器。\n修改下 Npc.plist 加个配置文件参数。\n\u0026lt;?xml version=\u0026#39;1.0\u0026#39; encoding=\u0026#39;UTF-8\u0026#39;?\u0026gt; \u0026lt;!DOCTYPE plist PUBLIC \u0026#34;-//Apple Computer//DTD PLIST 1.0//EN\u0026#34; \u0026#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd\u0026#34; \u0026gt; \u0026lt;plist version=\u0026#39;1.0\u0026#39;\u0026gt; \u0026lt;dict\u0026gt; \u0026lt;key\u0026gt;Label\u0026lt;/key\u0026gt;\u0026lt;string\u0026gt;Npc\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;ProgramArguments\u0026lt;/key\u0026gt; \u0026lt;array\u0026gt; \u0026lt;string\u0026gt;/path/npc\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;-config=/path/conf/npc.conf\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;-debug=false\u0026lt;/string\u0026gt; \u0026lt;/array\u0026gt; \u0026lt;key\u0026gt;SessionCreate\u0026lt;/key\u0026gt;\u0026lt;false/\u0026gt; \u0026lt;key\u0026gt;KeepAlive\u0026lt;/key\u0026gt;\u0026lt;true/\u0026gt; \u0026lt;key\u0026gt;RunAtLoad\u0026lt;/key\u0026gt;\u0026lt;false/\u0026gt; \u0026lt;key\u0026gt;Disabled\u0026lt;/key\u0026gt;\u0026lt;false/\u0026gt; \u0026lt;/dict\u0026gt; \u0026lt;/plist\u0026gt; 启动客户端\n$ sudo npc start 创建 tcp 隧道 tcp 隧道可以实现 ssh、远程桌面等 tcp 连接\n举例实现 mac vnc 远程桌面，在刚才创建的客户端隧道管理中添加一条 tcp 隧道，填写监听的端口8001、内网目标ip和目标端口10.1.50.101:5900 保存(vnc 默认端口5900)。 vnc 客户端链接服务端 1.1.1.1:8001 即可，相当于访问内网ip10.1.50.101:5900。\n更多隧道代理模式自行摸索吧!\n","permalink":"https://ibelieving.com/posts/2021-01-07-nps_use/","summary":"\u003cp\u003e\u003ca href=\"https://github.com/ehang-io/nps\"\u003enps\u003c/a\u003e 是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持 tcp、udp 流量转发，可支持任何 tcp、udp 上层协议（访问内网网站、本地支付接口调试、ssh 访问、远程桌面，内网 dns 解析等等……），此外还支持内网 http 代理、内网 socks5 代理、p2p 等，并带有功能强大的 web 管理端。\u003c/p\u003e\n\u003ch2 id=\"实现结构图\"\u003e实现结构图\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  +---------------+  +---------------------------------------+     +--------------------------------------------+\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |                                       |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |    traffic    |  |   Server  x.x.x.x                     |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |                                       |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |                          nps web      |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |  +---------+        +--------------+  |     |                intranet                    |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  | nps.test.com -----\u0026gt; | Traefik |  +--\u0026gt;  |127.0.0.1:8081|  |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |  +---------+        +--------------+  |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |                                       |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |                                       |     |     nps Client                             |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |  +---------+                  x.x.x.x:8024  |   +-------------+  :5900  +-------------+  |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  | x.x.x.x:8001 -----\u0026gt; |   nps   |  \u0026lt;------------------------------\u0026gt;  | 10.1.50.100 | +-----\u0026gt; | 10.1.50.101 |  |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |  +---------+                          |     |   +-------------+         +-------------+  |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  |               |  |                                       |     |                                            |\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  +---------------+  +---------------------------------------+     +--------------------------------------------+\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e服务端：CentOS 7.9\n客户端：MacOS 10.15\u003c/p\u003e","title":"nps 内网穿透"},{"content":"先说结果：fork 了 swoole 的源码，修复之后打了个 v1.10.7 的版本。\n发现问题 由于各种原因项目在使用 swoole 的 v1.x 远古版本跑 TCP 服务，基础环境如下。\nCentOS 6.9 PHP 5.5.38 然后遇到了程序偶发性超时情况严重。怀疑是版本bug，首先将 swoole 升级到了当前环境可用的最高版本 v1.10.6，问题依然没有解决。但是这个版本已经有了慢日志功能，将慢日志功能开起来，模拟程序阻塞超时，试试看功能可用否。\ntcp_server.php\n\u0026lt;?php class tcpTest { static public function aa() { self::bb(); } static public function bb() { sleep(3); } } class Server { static private $serv = null; private function __construct() { $serv = new \\swoole_server(\u0026#34;0.0.0.0\u0026#34;, 9577); $serv-\u0026gt;set([ \u0026#39;reactor_num\u0026#39; =\u0026gt; 2, \u0026#39;worker_num\u0026#39; =\u0026gt; 8, \u0026#39;task_worker_num\u0026#39; =\u0026gt; 0, \u0026#39;dispatch_mode\u0026#39; =\u0026gt; 2, \u0026#39;daemonize\u0026#39; =\u0026gt; false, \u0026#39;tcp_fastopen\u0026#39; =\u0026gt; true, \u0026#39;request_slowlog_timeout\u0026#39; =\u0026gt; 2, \u0026#39;request_slowlog_file\u0026#39; =\u0026gt; \u0026#39;/tmp/swoole_slow.log\u0026#39;, \u0026#39;trace_event_worker\u0026#39; =\u0026gt; true, ]); $serv-\u0026gt;on(\u0026#39;Start\u0026#39;, array($this, \u0026#39;onStart\u0026#39;)); $serv-\u0026gt;on(\u0026#39;Connect\u0026#39;, array($this, \u0026#39;onConnect\u0026#39;)); $serv-\u0026gt;on(\u0026#39;Receive\u0026#39;, array($this, \u0026#39;onReceive\u0026#39;)); $serv-\u0026gt;on(\u0026#39;Close\u0026#39;, array($this, \u0026#39;onClose\u0026#39;)); $serv-\u0026gt;start(); } public function onStart($serv) { echo __METHOD__ . PHP_EOL; } public function onConnect($serv, $fd, $from_id) { echo __METHOD__ . \u0026#34; worker_id:{$serv-\u0026gt;worker_id} work_pid:{$serv-\u0026gt;worker_pid} fd:{$fd} from_id:{$from_id}\u0026#34; . PHP_EOL; } public function onReceive($serv, $fd, $from_id, $data) { $fdinfo = $serv-\u0026gt;connection_info($fd,$from_id,true); echo __METHOD__ . \u0026#34; ip:{$fdinfo[\u0026#39;remote_ip\u0026#39;]} worker_id:{$serv-\u0026gt;worker_id} work_pid:{$serv-\u0026gt;worker_pid} fd:{$fd} from_id:{$from_id} data:{$data}\u0026#34; . PHP_EOL; \\tcpTest::aa(); $res_data = [\u0026#39;time\u0026#39; =\u0026gt; date(\u0026#39;Y-m-d H:i:s\u0026#39;)]; $serv-\u0026gt;send($fd, json_encode($res_data)); } public function onClose($serv, $fd, $from_id) { echo __METHOD__ . \u0026#34; worker_id:{$serv-\u0026gt;worker_id} work_pid:{$serv-\u0026gt;worker_pid} fd:{$fd} from_id:{$from_id}\u0026#34; . PHP_EOL . PHP_EOL; } static public function inst() { if (!(self::$serv instanceof self)) { self::$serv = new self; } return self::$serv; } } $res = \\Server::inst(); tcp_client.php\n\u0026lt;?php function getTime() { list($micro, $time) = explode(\u0026#39; \u0026#39;, microtime()); return $time + $micro; } $begin = getTime(); $_client = new \\swoole_client(SWOOLE_SOCK_TCP | SWOOLE_KEEP); if (false == $_client-\u0026gt;connect(\u0026#34;127.0.0.1\u0026#34;, 9577, 10)) { printf(\u0026#34;err_msg: %s err_code: %s\u0026#34; . PHP_EOL, var_export($_client-\u0026gt;errMsg, true), var_export($_client-\u0026gt;errCode, true)); } $_client-\u0026gt;send(\u0026#39;hello\u0026#39;); $res = $_client-\u0026gt;recv(); $end = getTime(); $data = json_decode($res, true); printf(\u0026#34;res: %s\u0026#34; . PHP_EOL, var_export($data, true)); echo $end - $begin . PHP_EOL; 分别运行服务端和客户端，slowlog内容出现乱码。 怎么会乱码了，太诡异了。vim 打开各种调编码没用，而且只是一部分乱码，可以猜出每行最后的是行号。 谷歌下好像也没有人遇到这问题，看下github issues发现这个功能后续版本都砍掉了，真是令人痛心。 编译个 PHP 5.6 的试下如果没问题，升级个小版本的 PHP 还是可以接受的，但结果依然是乱码。 这上古版本的扩展，可如何是好，天塌了有高个子顶着，没办法咱就的是那个高个子，下个扩展源码看看到底哪出问题了。\n逻辑梳理与修复 结合swoole slowlog的文档与源码，梳理了slowlog执行逻辑：\n首先在服务端 start 的方法中增加了一个MANAGER_TIMER类型的 hook，通过双向链表存储。在服务端启动后 manage 进程开始事件循环，调用alarm(request_slowlog_timeout)，在 request_slowlog_timeout 秒之后向当前进程发送SIGALRM信号，当 manage 进程收到SIGALRM信号后，会设置一个alarm()，再回调所有MANAGER_TIMER类型的 hook。 在回调函数中，会遍历所有 Work/Task 进程，检查是否超时，如果超时则调用 ptrace 开启跟踪，同时进程进入中止状态。 现在开始slowlog逻辑，使用ptrace通过current_execute_data加上结构体属性的偏移量后的内存地址获取函数名、文件与行号后写入日志文件。 slowlog记录完成再次调用ptrace结束跟踪，进程继续执行。 当获取函数、文件时相当于从一段内存连续的读取然后拼接。而行号一次就行。这块逻辑简单，但是需要对内部结构体指针和内存非常熟悉才行，真是触及到了我的知识盲区。各种尝试修改后发现先获取下一个地址再进行后续处理就可以取到正确的字符串。\nswoole_trace.c中\nstatic int trace_get_strz(pid_t traced_pid, char *buf, size_t sz, long addr) { int i; long l = addr; char *lc = (char *) \u0026amp;l; // 添加这个代码块，先获取下一个地址，再进行处理 if (0 \u0026gt; trace_get_long(traced_pid, addr, \u0026amp;l)) { return -1; } i = l % SIZEOF_LONG; l -= i; for (addr = l;; addr += SIZEOF_LONG) { if (0 \u0026gt; trace_get_long(traced_pid, addr, \u0026amp;l)) { return -1; } for (; i \u0026lt; SIZEOF_LONG; i++) { --sz; if (sz \u0026amp;\u0026amp; lc[i]) { *buf++ = lc[i]; continue; } *buf = \u0026#39;\\0\u0026#39;; return 0; } i = 0; } return 0; } static int trace_get_long(pid_t traced_pid, long addr, long *data) { errno = 0; *data = ptrace(PTRACE_PEEKDATA, traced_pid, (void *) addr, 0); if (*data \u0026lt; 0) { return -1; } return 0; } 重新编译后再运行测试，一切正常了。\n总结 至此，乱码修复了，但可真是没少调试。明白了实现逻辑也就明白了为何后续版本这个功能被砍掉了。\n完全依赖 alarm 所以最小粒度是秒。 循环检测所以跨两个时间窗口的超时是无法记录的。 通过内存地址结构体偏移获取函数、文件，当数据结构变动相当于重新写。 ","permalink":"https://ibelieving.com/posts/2020-05-11-swoole_slowlog/","summary":"\u003cp\u003e先说结果：fork 了 swoole 的源码，修复之后打了个 \u003ca href=\"https://github.com/zyh94946/swoole-src/releases/tag/v1.10.7\"\u003ev1.10.7\u003c/a\u003e 的版本。\u003c/p\u003e\n\u003ch2 id=\"发现问题\"\u003e发现问题\u003c/h2\u003e\n\u003cp\u003e由于各种原因项目在使用 \u003ccode\u003eswoole\u003c/code\u003e 的 v1.x 远古版本跑 TCP 服务，基础环境如下。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCentOS 6.9\u003c/li\u003e\n\u003cli\u003ePHP 5.5.38\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e然后遇到了程序偶发性超时情况严重。怀疑是版本bug，首先将 \u003ccode\u003eswoole\u003c/code\u003e 升级到了当前环境可用的最高版本 \u003ccode\u003ev1.10.6\u003c/code\u003e，问题依然没有解决。但是这个版本已经有了慢日志功能，将慢日志功能开起来，模拟程序阻塞超时，试试看功能可用否。\u003c/p\u003e\n\u003cp\u003etcp_server.php\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-php\" data-lang=\"php\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003e\u0026lt;?\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ephp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003etcpTest\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003eaa\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#1f2328\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e::\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebb\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003ebb\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#1f2328\"\u003esleep\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e3\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eServer\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003enull\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003e__construct\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e\\swoole_server\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;0.0.0.0\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e9577\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eset\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e([\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;reactor_num\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;worker_num\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;task_worker_num\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;dispatch_mode\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;daemonize\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;tcp_fastopen\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;request_slowlog_timeout\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;request_slowlog_file\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;/tmp/swoole_slow.log\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;trace_event_worker\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#1f2328\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eon\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;Start\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003earray\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$this\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;onStart\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eon\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;Connect\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003earray\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$this\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;onConnect\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eon\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;Receive\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003earray\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$this\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;onReceive\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eon\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;Close\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003earray\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$this\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;onClose\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003estart\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003eonStart\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#cf222e\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e__METHOD__\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ePHP_EOL\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003eonConnect\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$from_id\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#cf222e\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e__METHOD__\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34; worker_id:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eworker_id\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e work_pid:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eworker_pid\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e fd:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e from_id:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$from_id\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ePHP_EOL\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003eonReceive\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$from_id\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$fdinfo\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econnection_info\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$from_id\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#cf222e\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e__METHOD__\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34; ip:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$fdinfo\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;remote_ip\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e]\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e worker_id:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eworker_id\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e work_pid:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eworker_pid\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e fd:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e from_id:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$from_id\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e data:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ePHP_EOL\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#1f2328\"\u003e\\tcpTest\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e::\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eaa\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$res_data\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;time\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003edate\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;Y-m-d H:i:s\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003esend\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ejson_encode\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$res_data\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003eonClose\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$from_id\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#cf222e\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e__METHOD__\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34; worker_id:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eworker_id\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e work_pid:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eworker_pid\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e fd:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$fd\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e from_id:\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$from_id\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ePHP_EOL\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ePHP_EOL\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003einst\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e!\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e::\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003einstanceof\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e))\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#1f2328\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e::\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#cf222e\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e::\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$serv\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e\\Server\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e::\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003einst\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003etcp_client.php\u003c/p\u003e","title":"Swoole slowlog 乱码修复"},{"content":"docker 实现应用的容器化 consul 集群实现服务的注册、发现 traefik 处理外部流量的负载均衡与路由\n启动 consul 集群与 docker 通过 vagrant 起三台虚拟机实现基本的 consul 集群环境（为了节约资源把 docker 也运行在这上面了）。 consul 的 vagrant 配置文件如下：\n# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The \u0026#34;2\u0026#34; in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don\u0026#39;t change it unless you know what # you\u0026#39;re doing. Vagrant.configure(\u0026#34;2\u0026#34;) do |config| $script = \u0026lt;\u0026lt;SCRIPT echo \u0026#34;Installing\u0026#34; yum install -y wget wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo yum clean all yum makecache yum install -y jq unzip vim wget net-tools bind-utils dnsmasq sudo cp /vagrant/consul /usr/bin/consul echo \u0026#34;Installing docker..\u0026#34; sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl start docker echo \u0026#34;success\u0026#34; SCRIPT # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. config.vm.box = \u0026#34;centos/7\u0026#34; config.vm.provision \u0026#34;shell\u0026#34;, inline: $script config.vm.define \u0026#34;node1\u0026#34; do |node1| node1.vm.hostname = \u0026#34;node1\u0026#34; node1.vm.network \u0026#34;private_network\u0026#34;, ip: \u0026#34;172.17.17.11\u0026#34; end config.vm.define \u0026#34;node2\u0026#34; do |node2| node2.vm.hostname = \u0026#34;node2\u0026#34; node2.vm.network \u0026#34;private_network\u0026#34;, ip: \u0026#34;172.17.17.12\u0026#34; end config.vm.define \u0026#34;node3\u0026#34; do |node3| node3.vm.hostname = \u0026#34;node3\u0026#34; node3.vm.network \u0026#34;private_network\u0026#34;, ip: \u0026#34;172.17.17.13\u0026#34; end # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs # `vagrant box outdated`. This is not recommended. config.vm.box_check_update = false # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing \u0026#34;localhost:8080\u0026#34; will access port 80 on the guest machine. # NOTE: This will enable public access to the opened port # config.vm.network \u0026#34;forwarded_port\u0026#34;, guest: 80, host: 8080 # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine and only allow access # via 127.0.0.1 to disable public access # config.vm.network \u0026#34;forwarded_port\u0026#34;, guest: 80, host: 8080, host_ip: \u0026#34;127.0.0.1\u0026#34; # Create a private network, which allows host-only access to the machine # using a specific IP. # config.vm.network \u0026#34;private_network\u0026#34;, ip: \u0026#34;192.168.33.10\u0026#34; # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network \u0026#34;public_network\u0026#34; # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. # config.vm.synced_folder \u0026#34;../data\u0026#34;, \u0026#34;/vagrant_data\u0026#34; # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # config.vm.provider \u0026#34;virtualbox\u0026#34; do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: vb.memory = \u0026#34;1024\u0026#34; end # # View the documentation for the provider you are using for more # information on available options. # Enable provisioning with a shell script. Additional provisioners such as # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the # documentation for more information about their specific syntax and use. # config.vm.provision \u0026#34;shell\u0026#34;, inline: \u0026lt;\u0026lt;-SHELL # apt-get update # apt-get install -y apache2 # SHELL end 为了节省时间我直接下载好了 consul 的可执行文件放到了 vagrant 配置文件同目录下，vagrant 会把当前目录下的文件都复制进虚拟机的 /vagrant 目录下，还有三个节点的 consul 配置文件。\nnode1\n{ \u0026#34;datacenter\u0026#34;:\u0026#34;dc1\u0026#34;, \u0026#34;primary_datacenter\u0026#34;:\u0026#34;dc1\u0026#34;, \u0026#34;bootstrap_expect\u0026#34;:3, \u0026#34;advertise_addr\u0026#34;: \u0026#34;172.17.17.11\u0026#34;, \u0026#34;bind_addr\u0026#34;: \u0026#34;172.17.17.11\u0026#34;, \u0026#34;client_addr\u0026#34;:\u0026#34;0.0.0.0\u0026#34;, \u0026#34;server\u0026#34;:true, \u0026#34;node_name\u0026#34;:\u0026#34;node1\u0026#34;, \u0026#34;ui\u0026#34;:true, \u0026#34;data_dir\u0026#34;:\u0026#34;/opt/consul\u0026#34;, \u0026#34;enable_script_checks\u0026#34;:true, \u0026#34;enable_local_script_checks\u0026#34;:true, \u0026#34;log_file\u0026#34;:\u0026#34;/opt/consul/\u0026#34;, \u0026#34;log_level\u0026#34;:\u0026#34;info\u0026#34;, \u0026#34;log_rotate_duration\u0026#34;:\u0026#34;24h\u0026#34; } node2\n{ \u0026#34;datacenter\u0026#34;:\u0026#34;dc1\u0026#34;, \u0026#34;primary_datacenter\u0026#34;:\u0026#34;dc1\u0026#34;, \u0026#34;advertise_addr\u0026#34;: \u0026#34;172.17.17.12\u0026#34;, \u0026#34;bind_addr\u0026#34;: \u0026#34;172.17.17.12\u0026#34;, \u0026#34;client_addr\u0026#34;:\u0026#34;0.0.0.0\u0026#34;, \u0026#34;server\u0026#34;:true, \u0026#34;node_name\u0026#34;:\u0026#34;node2\u0026#34;, \u0026#34;ui\u0026#34;:true, \u0026#34;data_dir\u0026#34;:\u0026#34;/opt/consul\u0026#34;, \u0026#34;enable_script_checks\u0026#34;:true, \u0026#34;enable_local_script_checks\u0026#34;:true, \u0026#34;log_file\u0026#34;:\u0026#34;/opt/consul/\u0026#34;, \u0026#34;log_level\u0026#34;:\u0026#34;info\u0026#34;, \u0026#34;log_rotate_duration\u0026#34;:\u0026#34;24h\u0026#34;, \u0026#34;start_join\u0026#34;:[ \u0026#34;172.17.17.11\u0026#34; ], \u0026#34;retry_join\u0026#34;:[ \u0026#34;172.17.17.11\u0026#34; ] } node3\n{ \u0026#34;datacenter\u0026#34;:\u0026#34;dc1\u0026#34;, \u0026#34;primary_datacenter\u0026#34;:\u0026#34;dc1\u0026#34;, \u0026#34;advertise_addr\u0026#34;: \u0026#34;172.17.17.13\u0026#34;, \u0026#34;bind_addr\u0026#34;: \u0026#34;172.17.17.13\u0026#34;, \u0026#34;client_addr\u0026#34;:\u0026#34;0.0.0.0\u0026#34;, \u0026#34;server\u0026#34;:true, \u0026#34;node_name\u0026#34;:\u0026#34;node3\u0026#34;, \u0026#34;ui\u0026#34;:true, \u0026#34;data_dir\u0026#34;:\u0026#34;/opt/consul\u0026#34;, \u0026#34;enable_script_checks\u0026#34;:true, \u0026#34;enable_local_script_checks\u0026#34;:true, \u0026#34;log_file\u0026#34;:\u0026#34;/opt/consul/\u0026#34;, \u0026#34;log_level\u0026#34;:\u0026#34;info\u0026#34;, \u0026#34;log_rotate_duration\u0026#34;:\u0026#34;24h\u0026#34;, \u0026#34;start_join\u0026#34;:[ \u0026#34;172.17.17.11\u0026#34; ], \u0026#34;retry_join\u0026#34;:[ \u0026#34;172.17.17.11\u0026#34; ] } 三个节点分别是\nnode1 172.17.17.11 node2 172.17.17.12 node3 172.17.17.13 运行 vagrant up --provider=virtualbox 把三个节点启动。\n分别进入三个节点先 sudo su - 切换成 root 用户，然后把 consul 起来，再 exit 退出就会后台运行了。\n[root@node1 ~]# consul agent -config-file /vagrant/node1.json \u0026amp; [root@node2 ~]# consul agent -config-file /vagrant/node2.json \u0026amp; [root@node3 ~]# consul agent -config-file /vagrant/node3.json \u0026amp; 在三个节点上分别通过 docker 运行 web 服务，对外端口是 32768\n[root@node1 ~]# docker run -d -p 32768:80 --name test containous/whoami 服务注册 在三个节点上分别把刚才的 web 服务注册到 consul，这一步在实际项目中可以写到 docker image build 中，然后在容器启动的时候就注册到 consul。\n[root@node1 ~]# curl --request PUT --data @web.json http://127.0.0.1:8500/v1/agent/service/register?replace-existing-checks=true web.json 内容如下\n{ \u0026#34;ID\u0026#34;: \u0026#34;web\u0026#34;, \u0026#34;Name\u0026#34;: \u0026#34;consul_web\u0026#34;, \u0026#34;Tags\u0026#34;: [ \u0026#34;whoami\u0026#34; ], \u0026#34;Check\u0026#34;: { \u0026#34;Args\u0026#34;: [\u0026#34;curl\u0026#34;, \u0026#34;172.17.17.11:32768\u0026#34;], \u0026#34;Interval\u0026#34;: \u0026#34;10s\u0026#34;, \u0026#34;Timeout\u0026#34;: \u0026#34;3s\u0026#34; }, \u0026#34;Address\u0026#34;: \u0026#34;172.17.17.11\u0026#34;, \u0026#34;Port\u0026#34;: 32768 } 其中增加了简单的健康检查, ip 部分每个节点修改成自己的。\n现在通过访问 http://172.17.17.11:8500/ 可以看到如下的信息\n随便找一个节点通过 consul 自带的 dns 查询下服务，可以看到返回了所有健康的服务节点。\n[root@node1 ~]# dig @127.0.0.1 -p 8600 consul_web.service.consul ; \u0026lt;\u0026lt;\u0026gt;\u0026gt; DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 \u0026lt;\u0026lt;\u0026gt;\u0026gt; @127.0.0.1 -p 8600 consul_web.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; -\u0026gt;\u0026gt;HEADER\u0026lt;\u0026lt;- opcode: QUERY, status: NOERROR, id: 11034 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 4 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;consul_web.service.consul.\tIN\tA ;; ANSWER SECTION: consul_web.service.consul. 0\tIN\tA\t172.17.17.11 consul_web.service.consul. 0\tIN\tA\t172.17.17.13 consul_web.service.consul. 0\tIN\tA\t172.17.17.12 ;; ADDITIONAL SECTION: consul_web.service.consul. 0\tIN\tTXT\t\u0026#34;consul-network-segment=\u0026#34; consul_web.service.consul. 0\tIN\tTXT\t\u0026#34;consul-network-segment=\u0026#34; consul_web.service.consul. 0\tIN\tTXT\t\u0026#34;consul-network-segment=\u0026#34; ;; Query time: 0 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Thu Feb 06 13:10:12 UTC 2020 ;; MSG SIZE rcvd: 210 服务发现 dns 通过 dnsmasq 将节点的 dns 修改为 consul 的，先创建配置文件 /etc/dnsmasq.d/10-consul 内容为\nserver=/consul/127.0.0.1#8600 server=223.5.5.5 然后运行 systemctl start dnsmasq 启动 dnsmasq，再把 /etc/resolv.conf dns 服务器地址改成 127.0.0.1。\n通过 curl 访问\n[root@node1 ~]# curl http://consul_web.service.consul:32768 -i HTTP/1.1 200 OK Date: Thu, 06 Feb 2020 13:19:43 GMT Content-Length: 178 Content-Type: text/plain; charset=utf-8 Hostname: 2cc06cae3b6e IP: 127.0.0.1 IP: 172.18.0.2 RemoteAddr: 172.17.17.11:54108 GET / HTTP/1.1 Host: consul_web.service.consul:32768 User-Agent: curl/7.29.0 Accept: */* 把 docker 中 dns 配置修改为当前节点的，配置文件 /etc/docker/daemon.json\n{ \u0026#34;dns\u0026#34;: [\u0026#34;172.17.17.11\u0026#34;], \u0026#34;dns-search\u0026#34;: [\u0026#34;service.consul\u0026#34;], } 这样在 docker 容器内部就可以通过 consul 的 dns 来进行服务发现了。现在服务的注册与内部的服务发现都已经完成了。\ntraefik 对于外部流量的进入与路由使用 Traefik 来管理。\n起一台跑 traefik 的 vagrant 配置文件如下，同样下载了 traefik 的可执行文件到当前目录。\n# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The \u0026#34;2\u0026#34; in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don\u0026#39;t change it unless you know what # you\u0026#39;re doing. Vagrant.configure(\u0026#34;2\u0026#34;) do |config| $script = \u0026lt;\u0026lt;SCRIPT yum install -y wget wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo yum clean all yum makecache yum install -y jq unzip vim wget net-tools bind-utils dnsmasq sudo cp /vagrant/consul /usr/bin/consul sudo cp /vagrant/traefik /usr/bin/traefik echo \u0026#34;success\u0026#34; SCRIPT # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. config.vm.box = \u0026#34;centos/7\u0026#34; config.vm.provision \u0026#34;shell\u0026#34;, inline: $script config.vm.define \u0026#34;traefik\u0026#34; do |traefik| traefik.vm.hostname = \u0026#34;traefik\u0026#34; traefik.vm.network \u0026#34;private_network\u0026#34;, ip: \u0026#34;172.17.17.21\u0026#34; end # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs # `vagrant box outdated`. This is not recommended. config.vm.box_check_update = false # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing \u0026#34;localhost:8080\u0026#34; will access port 80 on the guest machine. # NOTE: This will enable public access to the opened port # config.vm.network \u0026#34;forwarded_port\u0026#34;, guest: 80, host: 8080 # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine and only allow access # via 127.0.0.1 to disable public access # config.vm.network \u0026#34;forwarded_port\u0026#34;, guest: 80, host: 8080, host_ip: \u0026#34;127.0.0.1\u0026#34; # Create a private network, which allows host-only access to the machine # using a specific IP. # config.vm.network \u0026#34;private_network\u0026#34;, ip: \u0026#34;192.168.33.10\u0026#34; # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network \u0026#34;public_network\u0026#34; # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. # config.vm.synced_folder \u0026#34;../data\u0026#34;, \u0026#34;/vagrant_data\u0026#34; # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # config.vm.provider \u0026#34;virtualbox\u0026#34; do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: vb.memory = \u0026#34;1024\u0026#34; end # # View the documentation for the provider you are using for more # information on available options. # Enable provisioning with a shell script. Additional provisioners such as # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the # documentation for more information about their specific syntax and use. # config.vm.provision \u0026#34;shell\u0026#34;, inline: \u0026lt;\u0026lt;-SHELL # apt-get update # apt-get install -y apache2 # SHELL end 节点为\ntraefik 172.17.17.21 在 traefik 上运行一个 client 模式的 consul 的 agent，加入 consul 的集群\n[root@traefik ~]# consul agent -data-dir /opt/consul -node=agent_traefik -bind=172.17.17.21 -join 172.17.17.11 \u0026amp; 然后运行 traefik\n[root@traefik ~]# traefik --configFile=/vagrant/config/traefik.toml 配置文件 /vagrant/config/traefik.toml 内容\n[global] checkNewVersion = true sendAnonymousUsage = false [api] insecure = true debug = true dashboard = true [log] filePath = \u0026#34;/vagrant/logs/traefik.log\u0026#34; level = \u0026#34;DEBUG\u0026#34; # format = \u0026#34;json\u0026#34; [accessLog] filePath = \u0026#34;/vagrant/logs/access.log\u0026#34; [entryPoints] [entryPoints.web] address = \u0026#34;:80\u0026#34; [entryPoints.web-secure] address = \u0026#34;:443\u0026#34; #[certificatesResolvers.sample.acme] # email = \u0026#34;\u0026#34; # storage = \u0026#34;acme.json\u0026#34; # [certificatesResolvers.sample.acme.httpChallenge] # entryPoint = \u0026#34;web\u0026#34; # caServer = \u0026#34;https://acme-staging-v02.api.letsencrypt.org/directory\u0026#34; # [certificatesResolvers.sample.acme.tlsChallenge] [providers] [providers.consulCatalog] exposedByDefault = false refreshInterval = \u0026#34;5s\u0026#34; [providers.file] filename = \u0026#34;/vagrant/config/static.toml\u0026#34; watch = true 配置文件 /vagrant/config/static.toml\n# 强制所有 http 请求转 https #[http.routers.http-catchall] # rule = \u0026#34;hostregexp(`{host:.+}`)\u0026#34; # entrypoints = [\u0026#34;web\u0026#34;] # service = \u0026#34;api@internal\u0026#34; # middlewares = [\u0026#34;toHttps\u0026#34;] # https 路由 #[http.routers.my-api] # rule = \u0026#34;Host(`traefik.haozy.com`)\u0026#34; # service = \u0026#34;api@internal\u0026#34; # middlewares = [\u0026#34;auth\u0026#34;] # [http.routers.my-api.tls] # certResolver = \u0026#34;sample\u0026#34; # [[http.routers.my-api.tls.domains]] # main = \u0026#34;traefik.haozy.com\u0026#34; #[http.middlewares.toHttps.redirectScheme] # scheme = \u0026#34;https\u0026#34; # http 路由 [http.routers.my-api-http] rule = \u0026#34;Host(`traefik.haozy.com`)\u0026#34; entrypoints = [\u0026#34;web\u0026#34;] service = \u0026#34;api@internal\u0026#34; middlewares = [\u0026#34;auth\u0026#34;] [http.middlewares.auth.basicAuth] # 密码生成 echo $(htpasswd -nb haozy 123456) users = [ \u0026#34;haozy:$$apr1$$pfkpgu.w$$jHQtt8T96PdvyojTBgh5E/\u0026#34;, ] 将域名 traefik.haozy.com host 指到 172.17.17.21 ，访问 traefik.haozy.com 因为配了 auth 验证，输入用户名密码后就可以看到管理界面了。https 也很简单，因为本地测试先注释了对应的配置。\n现在将 node1、node2、node3 节点上注册的 web 服务删除，在 web.json 中增加 traefik 相关的 tag，再重新注册。\nweb.json\n{ \u0026#34;ID\u0026#34;: \u0026#34;web\u0026#34;, \u0026#34;Name\u0026#34;: \u0026#34;consul_web\u0026#34;, \u0026#34;Tags\u0026#34;: [ \u0026#34;whoami\u0026#34;, \u0026#34;traefik.enable=true\u0026#34;, \u0026#34;traefik.http.routers.consul_web.rule=Host(`web.haozy.com`)\u0026#34;, \u0026#34;traefik.http.routers.consul_web.entrypoints=web\u0026#34;, \u0026#34;traefik.http.services.consul_web.loadbalancer.passhostheader=true\u0026#34; ], \u0026#34;Check\u0026#34;: { \u0026#34;Args\u0026#34;: [\u0026#34;curl\u0026#34;, \u0026#34;172.17.17.11:32768\u0026#34;], \u0026#34;Interval\u0026#34;: \u0026#34;10s\u0026#34;, \u0026#34;Timeout\u0026#34;: \u0026#34;3s\u0026#34; }, \u0026#34;Address\u0026#34;: \u0026#34;172.17.17.11\u0026#34;, \u0026#34;Port\u0026#34;: 32768 } [root@node1 ~]# curl --request PUT http://127.0.0.1:8500/v1/agent/service/deregister/web [root@node1 ~]# curl --request PUT --data @web.json http://127.0.0.1:8500/v1/agent/service/register?replace-existing-checks=true 现在通过 traefik 管理界面可以看到 web.consul.com 的路由信息，以及对应的后端服务。\n将域名 web.haozy.com 指向 172.17.17.21，请求会轮训请求所有后端服务。至此外部流量的负载均衡与路由就完成了，当然 traefik 中的 Routers 和 Middlewares 还可以实现很多复杂的处理。\n再多说一点，traefik 2.0 开始分成静态配置文件和动态配置，在静态文件中配置的 Routers、Middlewares 之类的是可以在动态配置中调用的，省去了很多定义，比如调用静态配置文件中的 auth。 traefik.http.routers.consul_web.middlewares=auth@file\n","permalink":"https://ibelieving.com/posts/2020-02-06-consul_and_traefik_micro_service/","summary":"\u003cp\u003edocker 实现应用的容器化\nconsul 集群实现服务的注册、发现\ntraefik 处理外部流量的负载均衡与路由\u003c/p\u003e\n\u003ch2 id=\"启动-consul-集群与-docker\"\u003e启动 consul 集群与 docker\u003c/h2\u003e\n\u003cp\u003e通过 vagrant 起三台虚拟机实现基本的 consul 集群环境（为了节约资源把 docker 也运行在这上面了）。\nconsul 的 vagrant 配置文件如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e# -*- mode: ruby -*-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e# vi: set ft=ruby :\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e# All Vagrant configuration is done below. The \u0026#34;2\u0026#34; in Vagrant.configure\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e# configures the configuration version (we support older styles for\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e# backwards compatibility). Please don\u0026#39;t change it unless you know what\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e# you\u0026#39;re doing.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eVagrant\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003econfigure\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;2\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003edo\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003econfig\u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003e$\u003c/span\u003escript \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e\u0026lt;\u0026lt;\u003c/span\u003eSCRIPT\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;Installing\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eyum install \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ey wget\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewget \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003eO \u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eetc\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eyum\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003erepos\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ed\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eCentOS\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003eBase\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003erepo http\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e//\u003c/span\u003emirrors\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ealiyun\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003erepo\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eCentos\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e7.\u003c/span\u003erepo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewget \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003eO \u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eetc\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eyum\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003erepos\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ed\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eepel\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003erepo http\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e//\u003c/span\u003emirrors\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ealiyun\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003erepo\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eepel\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e7.\u003c/span\u003erepo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eyum clean all\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eyum makecache\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eyum install \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ey jq unzip vim wget net\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003etools bind\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003eutils dnsmasq\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo cp \u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003evagrant\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003econsul \u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eusr\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003ebin\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003econsul\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;Installing docker..\u0026#34;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo yum install \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ey yum\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003eutils device\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003emapper\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003epersistent\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003edata lvm2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo yum\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003econfig\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003emanager \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003eadd\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003erepo http\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e//\u003c/span\u003emirrors\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ealiyun\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ece\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003elinux\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003ecentos\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ece\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003erepo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo yum install \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ey docker\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ece docker\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ece\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ecli containerd\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eio\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo systemctl start docker\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;success\u0026#34;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSCRIPT\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# The most common configuration options are documented and commented below.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# For a complete reference, please see the online documentation at\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# https://docs.vagrantup.com.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Every Vagrant development environment requires a box. You can search for\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# boxes at https://vagrantcloud.com/search.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  config\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ebox \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;centos/7\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  config\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eprovision \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;shell\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e inline\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e$\u003c/span\u003escript\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  config\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003edefine \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;node1\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003edo\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003enode1\u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    node1\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ehostname \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;node1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    node1\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003enetwork \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;private_network\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e ip\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;172.17.17.11\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  end\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  config\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003edefine \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;node2\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003edo\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003enode2\u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    node2\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ehostname \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;node2\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    node2\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003enetwork \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;private_network\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e ip\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;172.17.17.12\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  end\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  config\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003edefine \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;node3\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003edo\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003enode3\u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    node3\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ehostname \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;node3\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    node3\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003enetwork \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;private_network\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e ip\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;172.17.17.13\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  end\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Disable automatic box update checking. If you disable this, then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# boxes will only be checked for updates when the user runs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# `vagrant box outdated`. This is not recommended.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  config\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ebox_check_update \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#6a737d\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Create a forwarded port mapping which allows access to a specific port\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# within the machine from a port on the host machine. In the example below,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# accessing \u0026#34;localhost:8080\u0026#34; will access port 80 on the guest machine.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# NOTE: This will enable public access to the opened port\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# config.vm.network \u0026#34;forwarded_port\u0026#34;, guest: 80, host: 8080\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Create a forwarded port mapping which allows access to a specific port\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# within the machine from a port on the host machine and only allow access\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# via 127.0.0.1 to disable public access\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# config.vm.network \u0026#34;forwarded_port\u0026#34;, guest: 80, host: 8080, host_ip: \u0026#34;127.0.0.1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Create a private network, which allows host-only access to the machine\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# using a specific IP.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# config.vm.network \u0026#34;private_network\u0026#34;, ip: \u0026#34;192.168.33.10\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Create a public network, which generally matched to bridged network.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Bridged networks make the machine appear as another physical device on\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# your network.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# config.vm.network \u0026#34;public_network\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Share an additional folder to the guest VM. The first argument is\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# the path on the host to the actual folder. The second argument is\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# the path on the guest to mount the folder. And the optional third\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# argument is a set of non-required options.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# config.vm.synced_folder \u0026#34;../data\u0026#34;, \u0026#34;/vagrant_data\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Provider-specific configuration so you can fine-tune various\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# backing providers for Vagrant. These expose provider-specific options.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Example for VirtualBox:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   config\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003evm\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eprovider \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;virtualbox\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003edo\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003evb\u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#   # Display the VirtualBox GUI when booting the machine\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#   vb.gui = true\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#   # Customize the amount of memory on the VM:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     vb\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ememory \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#34;1024\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   end\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# View the documentation for the provider you are using for more\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# information on available options.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Enable provisioning with a shell script. Additional provisioners such as\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# documentation for more information about their specific syntax and use.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# config.vm.provision \u0026#34;shell\u0026#34;, inline: \u0026lt;\u0026lt;-SHELL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#   apt-get update\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e#   apt-get install -y apache2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#57606a\"\u003e# SHELL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eend\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e为了节省时间我直接下载好了 consul 的可执行文件放到了 vagrant 配置文件同目录下，vagrant 会把当前目录下的文件都复制进虚拟机的 \u003ccode\u003e/vagrant\u003c/code\u003e 目录下，还有三个节点的 consul 配置文件。\u003c/p\u003e","title":"用 Consul 和 Traefik 实现 Docker 容器的服务注册与发现"},{"content":"Intro 在家中除了带娃、看书也无事可做。把节前值班遇到的问题总结下。\n除夕那天我们公司依然正常上班，很多同事都已经提前回家了，在的人也不多，中午吃完饭没什么事就都走了。突然领导发来贺电以为什么好事，居然线上出问题了。前端同事反馈后端无响应，这个反馈也是没谁了，问了下具体调用的后端url，某个同事的 php 项目，没辙硬上吧。找运维查了下对应的机器有四台，先上 kibana 看下 nginx access 日志有大量请求404，error 日志没问题。再看 php error 日志有响应很慢的请求，应该是进来了，再看下 php 慢日志看调用栈应该是走到了一个 redis 类。这时候运维还在先让运维看下 redis 有问题没。我接着追代码，看代码发现这老哥没用框架定义的 redis 实例化类，自己整了个，真难受啊，一行行看 redis 配置从哪取的八成是这 redis 的问题。这时候运维反馈线上 redis 没问题。我接着撸代码，终于看到调的配置名了，去项目下 grep 下。这一搜发现这个配置有测试环境的，有预发环境的，还有个默认的配置，线上配置文件没有，不用说线上环境肯定用的默认的配置，默认的配的是测试环境的 redis。然而测试环境因为春节放假都关机了。\n问题查清楚了，加上了线上环境的 redis 配置。\n但是这个 bug 太tm智障了，全是问题。\n生产环境 调 测试环境 生产环境和测试环境要实现网络隔离，配置文件方式还是有点老，整个配置中心。\n自行实现 redis 类 框架已经提供了 redis 类，还要自行实现，直接影响排查效率。屏蔽了 redis 链接不上，然后给前端扔了个 404。没有规矩不成方圆要多 code review 啊。\n另 最近新型冠状病毒肆虐异常，各地陆续启动公共卫生事件一级响应，春节假期国家也延长到了正月初十。北京这边有的村不让从外回京的人进村，要外隔离，也是没谁了。\n","permalink":"https://ibelieving.com/posts/2020-01-30-last_bug_for_2019/","summary":"\u003ch2 id=\"intro\"\u003eIntro\u003c/h2\u003e\n\u003cp\u003e在家中除了带娃、看书也无事可做。把节前值班遇到的问题总结下。\u003c/p\u003e\n\u003cp\u003e除夕那天我们公司依然正常上班，很多同事都已经提前回家了，在的人也不多，中午吃完饭没什么事就都走了。突然领导发来贺电以为什么好事，居然线上出问题了。前端同事反馈后端无响应，这个反馈也是没谁了，问了下具体调用的后端url，某个同事的 php 项目，没辙硬上吧。找运维查了下对应的机器有四台，先上 kibana 看下 nginx access 日志有大量请求404，error 日志没问题。再看 php error 日志有响应很慢的请求，应该是进来了，再看下 php 慢日志看调用栈应该是走到了一个 redis 类。这时候运维还在先让运维看下 redis 有问题没。我接着追代码，看代码发现这老哥没用框架定义的 redis 实例化类，自己整了个，真难受啊，一行行看 redis 配置从哪取的八成是这 redis 的问题。这时候运维反馈线上 redis 没问题。我接着撸代码，终于看到调的配置名了，去项目下 grep 下。这一搜发现这个配置有测试环境的，有预发环境的，还有个默认的配置，线上配置文件没有，不用说线上环境肯定用的默认的配置，默认的配的是测试环境的 redis。然而测试环境因为春节放假都关机了。\u003c/p\u003e\n\u003cp\u003e问题查清楚了，加上了线上环境的 redis 配置。\u003c/p\u003e\n\u003cp\u003e但是这个 bug 太tm智障了，全是问题。\u003c/p\u003e\n\u003ch3 id=\"生产环境-调-测试环境\"\u003e生产环境 调 测试环境\u003c/h3\u003e\n\u003cp\u003e生产环境和测试环境要实现网络隔离，配置文件方式还是有点老，整个配置中心。\u003c/p\u003e\n\u003ch3 id=\"自行实现-redis-类\"\u003e自行实现 redis 类\u003c/h3\u003e\n\u003cp\u003e框架已经提供了 redis 类，还要自行实现，直接影响排查效率。屏蔽了 redis 链接不上，然后给前端扔了个 404。没有规矩不成方圆要多 code review 啊。\u003c/p\u003e\n\u003ch2 id=\"另\"\u003e另\u003c/h2\u003e\n\u003cp\u003e最近新型冠状病毒肆虐异常，各地陆续启动公共卫生事件一级响应，春节假期国家也延长到了正月初十。北京这边有的村不让从外回京的人进村，要外隔离，也是没谁了。\u003c/p\u003e","title":"年前线上问题总结"},{"content":"Intro 最近在做 Golang 与 PHP 的 RPC 实现。因 PHP 业务端已上线稳定，Golang 方面则需要完全兼容。其中使用了 json 序列化，发现区别还是很大的，见下面代码。\n$ php -a php \u0026gt; echo json_encode(\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;); \u0026#34;\u0026lt;test\\u6211\\u7231\\u4e2d\\u56fd\u0026gt;\u0026#34; package main import ( \u0026#34;encoding/json\u0026#34; \u0026#34;fmt\u0026#34; ) func main() { st := \u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34; res, err := json.Marshal(st) if err != nil { fmt.Println(\u0026#34;json err:\u0026#34;, err.Error()) } fmt.Printf(\u0026#34;json is: %s\u0026#34;, string(res)) // json is: \u0026#34;\\u003ctest我爱中国\\u003e\u0026#34; } PHP 默认的 json_encode() 函数会把多字节字符转成 \\uXXXX 当然通过设置 JSON_UNESCAPED_UNICODE 可以解决这个问题。这里不动 PHP 代码。 Golang 这里用 json 包的 Marshal 方法实现序列化，对多字节字符是不进行处理的。但是这个方法出于安全考虑会将\u0026quot;\u0026lt;\u0026quot;, \u0026ldquo;\u0026gt;\u0026rdquo;, \u0026ldquo;\u0026amp;\u0026ldquo;这三个字符转成 \\uXXXX 形式。这还不是最魔幻的，这个方法没有可选参数进行设置。\n取消转义特殊字符 看官网包说明通过 json.NewEncoder() 可以关闭转义。\npackage main import ( \u0026#34;encoding/json\u0026#34; \u0026#34;fmt\u0026#34; \u0026#34;bytes\u0026#34; ) func main() { st := \u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34; jsonBuf := bytes.NewBuffer([]byte{}) jsonEncode := json.NewEncoder(jsonBuf) jsonEncode.SetEscapeHTML(false) if err := jsonEncode.Encode(st); err != nil { fmt.Println(\u0026#34;json err:\u0026#34;, err.Error()) } fmt.Printf(\u0026#34;json is: %s\u0026#34;, jsonBuf.String()) // json is: \u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34; } 自定义序列化方法 对多字节字符转义，只能通过自定义序列化方法，官网也有包说明非常人性化。\npackage main import ( \u0026#34;encoding/json\u0026#34; \u0026#34;fmt\u0026#34; \u0026#34;bytes\u0026#34; \u0026#34;strconv\u0026#34; ) type cusString string func (cs cusString) MarshalJSON() ([]byte, error) { return []byte(strconv.QuoteToASCII(string(cs))), nil } func main() { st := cusString(\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;) jsonBuf := bytes.NewBuffer([]byte{}) jsonEncode := json.NewEncoder(jsonBuf) jsonEncode.SetEscapeHTML(false) if err := jsonEncode.Encode(st); err != nil { fmt.Println(\u0026#34;json err:\u0026#34;, err.Error()) } fmt.Printf(\u0026#34;json is: %s\u0026#34;, jsonBuf.String()) // json is: \u0026#34;\u0026lt;test\\u6211\\u7231\\u4e2d\\u56fd\u0026gt;\u0026#34; } 这样 json 序列化后的结果就和 PHP 下的一样了。分别计算下 MD5 。\n$ php -a Interactive shell php \u0026gt; echo json_encode(\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;); \u0026#34;\u0026lt;test\\u6211\\u7231\\u4e2d\\u56fd\u0026gt;\u0026#34; php \u0026gt; echo md5(json_encode(\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;)); 5ec1bfc0a2db38f985cdae47b2012ca5 php \u0026gt; php \u0026gt; package main import ( \u0026#34;encoding/json\u0026#34; \u0026#34;fmt\u0026#34; \u0026#34;bytes\u0026#34; \u0026#34;strconv\u0026#34; \u0026#34;crypto/md5\u0026#34; ) type cusString string func (cs cusString) MarshalJSON() ([]byte, error) { return []byte(strconv.QuoteToASCII(string(cs))), nil } func main() { st := cusString(\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;) jsonBuf := bytes.NewBuffer([]byte{}) jsonEncode := json.NewEncoder(jsonBuf) jsonEncode.SetEscapeHTML(false) if err := jsonEncode.Encode(st); err != nil { fmt.Println(\u0026#34;json err:\u0026#34;, err.Error()) } fmt.Printf(\u0026#34;json is: %s\u0026#34;, jsonBuf.String()) // json is: \u0026#34;\u0026lt;test\\u6211\\u7231\\u4e2d\\u56fd\u0026gt;\u0026#34; fmt.Printf(\u0026#34;md5 is: %x\u0026#34;, md5.Sum(jsonBuf.Bytes())) // md5 is: 5543e9185c4bde6311dc9c7605ca92b8 } MD5 值不一样，这就很魔幻了。开始大胆假设，小心求证。\n特殊处理 MD5 算法有问题，太扯了这是不可能的，试了别的 hash 算法也是一样。 json 序列化有问题，转 string 后确实没看出问题，直接输出 bytes 格式。发现是这样的。\n34 60 116 101 115 116 92 117 54 50 49 49 92 117 55 50 51 49 92 117 52 101 50 100 92 117 53 54 102 100 62 34 10 最后面是个10，10在 Ascii 表里是 LR new line 换行符。看来这个 json 序列化果然有问题啊，看看序列化源码怎么写的：\n源码在这里 json stream\n至于为什么会添加一个换行符，注释是这么说的:\nTerminate each value with a newline. This makes the output look a little nicer when debugging, and some kind of space is required if the encoded value was a number, so that the reader knows there aren\u0026#39;t more 说白了 json.NewEncoder() 处理的是流式数据，多个数据间为了分隔加了 \\n。\n最终代码如下，Go Playground。\n如果你看到这里说明你可能遇到了相似的问题，如果没有解决你的问题，从文档或源码中找找答案吧。\npackage main import ( \u0026#34;encoding/json\u0026#34; \u0026#34;fmt\u0026#34; \u0026#34;bytes\u0026#34; \u0026#34;strconv\u0026#34; \u0026#34;crypto/md5\u0026#34; ) type cusString string func (cs cusString) MarshalJSON() ([]byte, error) { return []byte(strconv.QuoteToASCII(string(cs))), nil } func main() { st := cusString(\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;) jsonBuf := bytes.NewBuffer([]byte{}) jsonEncode := json.NewEncoder(jsonBuf) jsonEncode.SetEscapeHTML(false) if err := jsonEncode.Encode(st); err != nil { fmt.Println(\u0026#34;json err:\u0026#34;, err.Error()) } jsonBytes := jsonBuf.Bytes() resultJson := make([]byte, 0) if jsonBytes[len(jsonBytes)-1] == \u0026#39;\\n\u0026#39; { resultJson = jsonBytes[:len(jsonBytes)-1] } else { resultJson = jsonBytes } fmt.Printf(\u0026#34;json is: %s \\r\\n\u0026#34;, string(resultJson)) // json is: \u0026#34;\u0026lt;test\\u6211\\u7231\\u4e2d\\u56fd\u0026gt;\u0026#34; fmt.Printf(\u0026#34;md5 is: %x \\r\\n\u0026#34;, md5.Sum(resultJson)) // md5 is: 5ec1bfc0a2db38f985cdae47b2012ca5 } ","permalink":"https://ibelieving.com/posts/2019-12-23-golang_and_php_json/","summary":"\u003ch1 id=\"intro\"\u003eIntro\u003c/h1\u003e\n\u003cp\u003e最近在做 Golang 与 PHP 的 RPC 实现。因 PHP 业务端已上线稳定，Golang 方面则需要完全兼容。其中使用了 json 序列化，发现区别还是很大的，见下面代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ php -a\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ephp \u0026gt; \u003cspan style=\"color:#6639ba\"\u003eecho\u003c/span\u003e json_encode\u003cspan style=\"color:#0550ae\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;\u0026lt;test\\u6211\\u7231\\u4e2d\\u56fd\u0026gt;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-golang\" data-lang=\"golang\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003epackage\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003emain\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003eimport\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;encoding/json\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;fmt\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003efunc\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003emain\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003est\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;\u0026lt;test我爱中国\u0026gt;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eres\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ejson\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eMarshal\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003est\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e!=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003enil\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintln\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;json err:\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eError\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e())\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintf\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;json is: %s\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003estring\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eres\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e))\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#57606a\"\u003e//  json is: \u0026#34;\\u003ctest我爱中国\\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ePHP 默认的 \u003ccode\u003ejson_encode()\u003c/code\u003e 函数会把多字节字符转成 \u003ccode\u003e\\uXXXX\u003c/code\u003e 当然通过设置 \u003ccode\u003eJSON_UNESCAPED_UNICODE\u003c/code\u003e 可以解决这个问题。这里不动 PHP 代码。\nGolang 这里用 json 包的 Marshal 方法实现序列化，对多字节字符是不进行处理的。但是这个方法出于安全考虑会将\u0026quot;\u0026lt;\u0026quot;, \u0026ldquo;\u0026gt;\u0026rdquo;, \u0026ldquo;\u0026amp;\u0026ldquo;这三个字符转成 \u003ccode\u003e\\uXXXX\u003c/code\u003e 形式。这还不是最魔幻的，这个方法没有可选参数进行设置。\u003c/p\u003e","title":"Golang 与 PHP 的 json 序列化问题"},{"content":"O\u0026rsquo;Reilly 是有名的动物书出版公司，当然他们也不仅仅出电子书还有很多别的业务。O\u0026rsquo;Reilly 在线学习平台上有他们所有出版过的图书都是原版的，但是仅提供在线阅读，虽然也有 App，但是想在 kindle 上看提高阅读体验。\n于是抽时间练习练习 Golang 写了个程序，生成 mobi 格式的电子书。Github 地址 oreilly_kindle_book 。\n使用说明 目前仅支持 macOS、linux, windows 改改应该也可以，但是我手头没有 windows 测不了，或者编个 Docker image 也 ok。 需要 O\u0026rsquo;Reilly 在线学习平台的账号，这是必须的。 安装 kindlegen，mobi 的生成就靠它。 oreilly_kindle_book 编译 基于 golang 1.13 开发，目前没有上传二进制包，自行编译吧。\n推荐 clone 之后直接 make \u0026amp;\u0026amp; make install。\n$ git clone https://github.com/zyh94946/oreilly_kindle_book.git $ cd oreilly_kindle_book $ make \u0026amp;\u0026amp; make install Building oreilly_kindle_book... Building success... Installing oreilly_kindle_book... Install success to /usr/local/bin/oreilly_kindle_book. Usage of oreilly_kindle_book: -email string you login email of https://www.oreilly.com/member/ -help help -n string the num of https://learning.oreilly.com/library/view/BOOK-NAME/*** -p string you login password of https://www.oreilly.com/member/ -version print version and exit 当然 go get 也可以\n$ go get github.com/zyh94946/oreilly_kindle_book $ go install github.com/zyh94946/oreilly_kindle_book oreilly_kindle_book 使用 非常简单\n$ oreilly_kindle_book -n BOOK_NUM -email YOU_EMAIL -p YOU_PASSWORD 完成后 mobi 会生成在当前目录下。\n技术总结 咱要 kindle 用，首先研究下 mobi 的生成。有两个特定格式的文件，一个 ncx (组织目录)，一个 opf (组织所有文件)，按格式来就能生成。开始梳理需要的资源看看可行性。完事准备写程序都爬下来，生成所需的格式，用 kindlegen 测试生成 mobi，大问题没有小问题不少，挨个解决。最后发现实现登录也不难索性加上了。编写过程中看了很多 go 原生包也使用了不少。\ngolang 需要注意的点不完全总结：\ngo func(){}() 实际执行的时间与其所属语句执行时间是不一样的。 通过 chan 控制并发。 大量字符串拼接不要用 + 时间与空间上都复杂。可用使用 strings.Builder{} 字节切片的概念。 os.Exit() 结束程序后，defer 不会执行。 有问题多看看官方文档比什么都强 :)。 ","permalink":"https://ibelieving.com/posts/2019-10-31-golang_generate_oreilly_kindle_book/","summary":"\u003cp\u003eO\u0026rsquo;Reilly 是有名的动物书出版公司，当然他们也不仅仅出电子书还有很多别的业务。O\u0026rsquo;Reilly 在线学习平台上有他们所有出版过的图书都是原版的，但是仅提供在线阅读，虽然也有 App，但是想在 kindle 上看提高阅读体验。\u003c/p\u003e\n\u003cp\u003e于是抽时间练习练习 Golang 写了个程序，生成 mobi 格式的电子书。Github 地址 \u003ca href=\"https://github.com/zyh94946/oreilly_kindle_book\"\u003eoreilly_kindle_book\u003c/a\u003e 。\u003c/p\u003e\n\u003ch2 id=\"使用说明\"\u003e使用说明\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e目前仅支持 macOS、linux, windows 改改应该也可以，但是我手头没有 windows 测不了，或者编个 Docker image 也 ok。\u003c/li\u003e\n\u003cli\u003e需要 O\u0026rsquo;Reilly 在线学习平台的账号，这是必须的。\u003c/li\u003e\n\u003cli\u003e安装 \u003ca href=\"https://www.amazon.com/gp/feature.html?ie=UTF8\u0026amp;docId=1000765211\"\u003ekindlegen\u003c/a\u003e，mobi 的生成就靠它。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"oreilly_kindle_book-编译\"\u003eoreilly_kindle_book 编译\u003c/h2\u003e\n\u003cp\u003e基于 golang 1.13 开发，目前没有上传二进制包，自行编译吧。\u003c/p\u003e\n\u003cp\u003e推荐 clone 之后直接 \u003ccode\u003emake \u0026amp;\u0026amp; make install\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git clone https://github.com/zyh94946/oreilly_kindle_book.git\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ \u003cspan style=\"color:#6639ba\"\u003ecd\u003c/span\u003e oreilly_kindle_book\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ make \u003cspan style=\"color:#0550ae\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e make install\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBuilding oreilly_kindle_book...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBuilding success...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eInstalling oreilly_kindle_book...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eInstall success to /usr/local/bin/oreilly_kindle_book.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eUsage of oreilly_kindle_book:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  -email string\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \tyou login email of https://www.oreilly.com/member/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  -help\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \t\u003cspan style=\"color:#6639ba\"\u003ehelp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  -n string\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \tthe num of https://learning.oreilly.com/library/view/BOOK-NAME/***\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  -p string\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \tyou login password of https://www.oreilly.com/member/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  -version\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \tprint version and \u003cspan style=\"color:#6639ba\"\u003eexit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当然 \u003ccode\u003ego get\u003c/code\u003e 也可以\u003c/p\u003e","title":"Golang 生成 O'Reilly 在线学习平台的电子书"},{"content":"本文参考使用Docker打造自己的云平台编写\n本文基于 Docker Swarm Mode 实现容器化，虽然目前 k8s 更火一些，但实在是太重了，以后再折腾。 使用 traefik 来实现反向代理、负载均衡，traefik 还自带了服务发现、后端断路器、健康检查等，相当于是自带服务发现的 nginx。当然它还支持其他的容器编排工具如，服务发现工具如 Consul。 使用 Portainer 来管理 Docker 容器，可以兼容 Docker Swarm 模式。\nDocker 的安装就不说了。装完初始化 Swarm 模式。\n$ docker swarm init 先设置一下环境变量。\n$ export DOCKER_DEV_PATH=/usr/local/src/docker-dev 日志文件都会统一存到 ${DOCKER_DEV_PATH}/logs。\ntraefik 新建一个编排文件 traefik.yml。\nversion: \u0026#39;3.3\u0026#39; services: reverse-proxy: image: traefik:1.7-alpine command: --web --docker --docker.domain=cloud-labs.io --docker.watch --docker.swarmmode=true --loglevel=INFO --accesslog --accesslog.filepath=/logs/access.log --traefiklog --traefiklog.filepath=/logs/traefik.log deploy: mode: replicated replicas: 1 labels: - traefik.enable=true - traefik.backend=traefik - traefik.frontend.rule=Host:monitor.cloud-labs.io - traefik.port=8080 - traefik.docker.network=traefik_proxy networks: - proxy ports: - 8081:80 volumes: - /var/run/docker.sock:/var/run/docker.sock - ${DOCKER_DEV_PATH}/logs/traefik:/logs - /dev/null:/traefik.toml networks: proxy: 简单解释下 labels 中配置的含义\ntraefik.backend 后端 traefik.frontend.rule 前端规则，满足此规则转发给后端 traefik.port 后端端口 8080 是 traefik web 后台端口 traefik.docker.network 指定网络 更多可用 labels 可用看该Traefik 文档\n因为在腾讯云上做的测试没有域名备案，映射了8081端口到80。\n部署traefik\n$ docker stack deploy -c traefik.yml traefik 完成后访问 monitor.cloud-labs.io:8081 就可以进入 traefik 的后台界面了（当然这个域名是要绑host的）。\nPortainer Portainer是一个轻量级的Docker环境管理UI。\n新建一个编排文件 portainer.yml。\nversion: \u0026#39;3.3\u0026#39; services: server: image: portainer/portainer command: -H unix:///var/run/docker.sock networks: - traefik_proxy deploy: labels: - traefik.enable=true - traefik.backend=portainer - traefik.frontend.rule=Host:console.cloud-labs.io - traefik.docker.network=traefik_proxy - traefik.port=9000 volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer:/data networks: traefik_proxy: external: true volumes: portainer: 部署\n$ docker stack deploy -c portainer.yml portainer 访问 console.cloud-labs.io:8081 就可以管理 Docker 了。\n部署一个PHP服务 php服务部署其实还是有些麻烦的。一般前端起nginx将php请求转发到php-fpm，这个时候用的是FastCGI协议。但是目前traefik不支持FastCGI协议，估计以后也不会支持，所以php和nginx要一块部署。如下配置文件。 新建一个编排文件 nginx_php_web.yml，其中包含nginx和php。\nversion: \u0026#39;3.3\u0026#39; services: nginx: image: nginx:latest volumes: - ${DOCKER_DEV_PATH}/logs/nginx:/data/logs/nginx - ${DOCKER_DEV_PATH}/test_code/php:/code - ./site.conf:/etc/nginx/conf.d/default.conf depends_on: - php networks: - traefik_proxy deploy: mode: replicated replicas: 2 labels: - traefik.backend=nginx - traefik.frontend.passHostHeader=true - traefik.frontend.rule=Host:domain.cloud-labs.io - traefik.docker.network=traefik_proxy - traefik.port=80 php: image: php:5.5.38-fpm volumes: - ./php.ini:/usr/local/etc/php/php.ini - ./php-fpm.conf:/usr/local/etc/php-fpm.conf - ./www.conf:/usr/local/etc/php-fpm.d/www.conf - ${DOCKER_DEV_PATH}/test_code/php:/code - ${DOCKER_DEV_PATH}/logs/php:/data/logs/php networks: - traefik_proxy deploy: mode: replicated replicas: 3 labels: - traefik.enable=false networks: traefik_proxy: external: true 部署\n$ docker stack deploy -c nginx_php_web.yml nginx_php_web 访问 domain.cloud-labs.io:8081 可以看到服务已经起来了。 但是这种方式会有问题\n因为请求是从traefik直接到nginx，做健康检查的话只能在nginx上写规则，这样会有问题。除非将nginx和php构建到一个镜像中，但是这又违反了docker的初衷。 经过traefik-\u0026gt;nginx-\u0026gt;php 性能也会应该有所损耗。 另一种方式通过php的swoole扩展起一个http服务，直接将请求转发过去。\n建一个Dockerfile，build一个带swoole的php镜像。这里用了最新的php版本。\nFROM php:7.3.8-cli RUN pecl channel-update pecl.php.net # 从pecl安装扩展 RUN pecl install swoole-4.4.0 \\ \u0026amp;\u0026amp; docker-php-ext-enable swoole $ docker build -t php7.3.8_swoole4.4.0 . \u0026gt; build.log \u0026amp; 很简单没有遇见任何问题。\n再建一个编排文件 php_web.yml。\nversion: \u0026#39;3.3\u0026#39; services: swoole_http: image: php7.3.8_swoole4.4.0:latest command: php /code/httpServ.php 8888 volumes: - ${DOCKER_DEV_PATH}/test_code/php:/code - ${DOCKER_DEV_PATH}/logs/swoole:/data/logs/swoole networks: - traefik_proxy deploy: mode: replicated replicas: 2 labels: - traefik.backend=swoole_http - traefik.frontend.passHostHeader=true - traefik.frontend.rule=Host:domain.cloud-labs.io - traefik.docker.network=traefik_proxy - traefik.port=8888 - traefik.backend.healthcheck.hostname=domain.cloud-labs.io - traefik.backend.healthcheck.port=8888 - traefik.backend.healthcheck.path=/healthcheck.php - traefik.backend.healthcheck.interval=5s networks: traefik_proxy: external: true 其中做了健康检查每五秒一次。httpServ.php的内容整理完发到github上了，文末有说明。 部署起来。\n$ docker stack rm nginx_php_web $ docker stack deploy -c php_web.yml php_web 效果 traefik 界面 Portainer 界面 跑是跑起来了，但还有些问题。\ndocker swarm目前只是单节点 容器日志、监控处理的不太好 压力测试也没有做 没有关联CI/CD 坑挖的有点多慢慢填吧。。\n文中所有配置文件当时整理到了 docker-dev 仓库，目前该仓库已经不可访问。\n","permalink":"https://ibelieving.com/posts/2019-08-28-docker_traefik_micro_service/","summary":"\u003cp\u003e本文参考\u003ca href=\"https://ronggle.com/2018/cloud-labs/\"\u003e使用Docker打造自己的云平台\u003c/a\u003e编写\u003c/p\u003e\n\u003cp\u003e本文基于 Docker Swarm Mode 实现容器化，虽然目前 k8s 更火一些，但实在是太重了，以后再折腾。\n使用 traefik 来实现反向代理、负载均衡，traefik 还自带了服务发现、后端断路器、健康检查等，相当于是自带服务发现的 nginx。当然它还支持其他的容器编排工具如，服务发现工具如 Consul。\n使用 Portainer 来管理 Docker 容器，可以兼容 Docker Swarm 模式。\u003c/p\u003e\n\u003cp\u003eDocker 的安装就不说了。装完初始化 Swarm 模式。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ docker swarm init\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e先设置一下环境变量。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003e$\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003eexport\u003c/span\u003e DOCKER_DEV_PATH\u003cspan style=\"color:#0550ae\"\u003e=/\u003c/span\u003eusr\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003elocal\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003esrc\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003edev\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e日志文件都会统一存到 ${DOCKER_DEV_PATH}/logs。\u003c/p\u003e\n\u003ch2 id=\"traefik\"\u003etraefik\u003c/h2\u003e\n\u003cp\u003e新建一个编排文件 traefik.yml。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eversion\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;3.3\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eservices\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  reverse\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003eproxy\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    image\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e traefik\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e1.7\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003ealpine\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    command\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003eweb \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003edocker \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003edomain\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003ecloud\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003elabs\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eio \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ewatch \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eswarmmode\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#6a737d\"\u003etrue\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003eloglevel\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003eINFO \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003eaccesslog \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003eaccesslog\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003efilepath\u003cspan style=\"color:#0550ae\"\u003e=/\u003c/span\u003elogs\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003eaccess\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003elog \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003etraefiklog \u003cspan style=\"color:#0550ae\"\u003e--\u003c/span\u003etraefiklog\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003efilepath\u003cspan style=\"color:#0550ae\"\u003e=/\u003c/span\u003elogs\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003etraefik\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003elog\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    deploy\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      mode\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e replicated\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      replicas\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      labels\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e traefik\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eenable\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#6a737d\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e traefik\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ebackend\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003etraefik\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e traefik\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003efrontend\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003erule\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003eHost\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003emonitor\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003ecloud\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003elabs\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eio\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e traefik\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003eport\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e8080\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e traefik\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003enetwork\u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003etraefik_proxy\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    networks\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e proxy\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ports\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e8081\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    volumes\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003erun\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003esock\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003erun\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003edocker\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003esock\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e$\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003eDOCKER_DEV_PATH\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003elogs\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003etraefik\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003elogs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003edev\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003enull\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e/\u003c/span\u003etraefik\u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003etoml\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enetworks\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  proxy\u003cspan style=\"color:#1f2328\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e简单解释下 labels 中配置的含义\u003c/p\u003e","title":"容器服务化方向的一些探索"},{"content":"今天来看看经常使用的数组排序函数如 sort, rsort, asort, arsort, ksort, krsort 。话不多说直接找 sort 函数吧。\n在 php7.3 源码中搜索 PHP_FUNCTION(sort) 可以搜到如下\n其中 .h 文件是C语言的头文件，直接打开 .c 文件。 sort 函数如下，其中我加了一点注释。\nPHP_FUNCTION(sort) { zval *array; zend_long sort_type = PHP_SORT_REGULAR; // 默认的排序规则 compare_func_t cmp; // 这里开始接请求参数 ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY_EX(array, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_LONG(sort_type) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); // 根据排序规则获取使用的排序函数 cmp = php_get_data_compare_func(sort_type, 0); // 进行排序 if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } 不但 rsort, asort, arsort, ksort, krsort 这些函数在 array.c 文件中，PHP数组相关的也都在其中。 先说下 rsort, asort, arsort, ksort, krsort 函数内容与 sort 只有细微的差别。 ksort、krsort 是根据键排序所以排序规则获取排序函数用的是 php_get_key_compare_func 参数与 php_get_data_compare_func 是一样的。 php_get_data_compare_func、php_get_key_compare_func 函数第二个参数意思是是否降序排列，rsort、arsort、krsort 第二个参数都是1。 进行排序时 zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) 第三个参数意思是是否重新排列索引， sort、rsort 传的都是1。 做个表格看下\n获取排序函数 调用排序 sort php_get_data_compare_func(sort_type, 0) zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) rsort php_get_data_compare_func(sort_type, 1) zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) asort php_get_data_compare_func(sort_type, 0) zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) arsort php_get_data_compare_func(sort_type, 1) zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) ksort php_get_key_compare_func(sort_type, 0) zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) krsort php_get_key_compare_func(sort_type, 1) zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) 其中调用 php_get_data_compare_func 与 php_get_key_compare_func 获取的 cmp 后面再说明。\n继续找 zend_hash_sort ，在 zend_hash.h 中。\n#define zend_hash_sort(ht, compare_func, renumber) \\ zend_hash_sort_ex(ht, zend_sort, compare_func, renumber) 看来 zend_hash_sort 中调用了 zend_hash_sort_ex 。 zend_hash_sort_ex 在 zend_hash.c 中。\nZEND_API int ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, compare_func_t compar, zend_bool renumber) { Bucket *p; uint32_t i, j; IS_CONSISTENT(ht); HT_ASSERT_RC1(ht); if (!(ht-\u0026gt;nNumOfElements\u0026gt;1) \u0026amp;\u0026amp; !(renumber \u0026amp;\u0026amp; ht-\u0026gt;nNumOfElements\u0026gt;0)) { /* Doesn\u0026#39;t require sorting */ return SUCCESS; } // 这里获取数组元素数，判断hash table是否没有洞，\u0026#34;洞\u0026#34;意思是数组里面元素被unset过，被unset过的val type是IS_UNDEF，不能通过nNumUsed直接获取数组的元素数。 if (HT_IS_WITHOUT_HOLES(ht)) { i = ht-\u0026gt;nNumUsed; } else { for (j = 0, i = 0; j \u0026lt; ht-\u0026gt;nNumUsed; j++) { p = ht-\u0026gt;arData + j; if (UNEXPECTED(Z_TYPE(p-\u0026gt;val) == IS_UNDEF)) continue; if (i != j) { ht-\u0026gt;arData[i] = *p; } i++; } } // 这个sort是由上面直接传进来的zend_sort，终于到最重要的排序了 sort((void *)ht-\u0026gt;arData, i, sizeof(Bucket), compar, (swap_func_t)(renumber? zend_hash_bucket_renum_swap : ((HT_FLAGS(ht) \u0026amp; HASH_FLAG_PACKED) ? zend_hash_bucket_packed_swap : zend_hash_bucket_swap))); // 后面是根据renumber判断是否需要重排索引内存回收等操作先省略了 } 在 zend_sort.c 中找到 zend_sort ，通过备注发现这个排序是源于 LLVM 的 libc++ 中的 std::sort 实现的。算是快排的优化版，当元素数小于等于16时有特殊的优化，当元素数小于等于5时直接通过 if else 嵌套判断排序，真是优化的极致。zend_sort_2 、 zend_sort_3 、 zend_sort_4 、 zend_sort_5 中是 if else 嵌套的判断排序就不贴出来了。其中基准点(pivot)计算方式也进行了优化。相比 PHP5 时代的标配快排实现要稳定多了。\nZEND_API void zend_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp) { while (1) { if (nmemb \u0026lt;= 16) { zend_insert_sort(base, nmemb, siz, cmp, swp); return; } else { char *i, *j; char *start = (char *)base; char *end = start + (nmemb * siz); size_t offset = (nmemb \u0026gt;\u0026gt; Z_L(1)); char *pivot = start + (offset * siz); if ((nmemb \u0026gt;\u0026gt; Z_L(10))) { size_t delta = (offset \u0026gt;\u0026gt; Z_L(1)) * siz; zend_sort_5(start, start + delta, pivot, pivot + delta, end - siz, cmp, swp); } else { zend_sort_3(start, pivot, end - siz, cmp, swp); } swp(start + siz, pivot); pivot = start + siz; i = pivot + siz; j = end - siz; while (1) { while (cmp(pivot, i) \u0026gt; 0) { i += siz; if (UNEXPECTED(i == j)) { goto done; } } j -= siz; if (UNEXPECTED(j == i)) { goto done; } while (cmp(j, pivot) \u0026gt; 0) { j -= siz; if (UNEXPECTED(j == i)) { goto done; } } swp(i, j); i += siz; if (UNEXPECTED(i == j)) { goto done; } } done: swp(pivot, i - siz); if ((i - siz) - start \u0026lt; end - i) { zend_sort(start, (i - start)/siz - 1, siz, cmp, swp); base = i; nmemb = (end - i)/siz; } else { zend_sort(i, (end - i)/siz, siz, cmp, swp); nmemb = (i - start)/siz - 1; } } } } ZEND_API void zend_insert_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp) { switch (nmemb) { case 0: case 1: break; case 2: zend_sort_2(base, (char *)base + siz, cmp, swp); break; case 3: zend_sort_3(base, (char *)base + siz, (char *)base + siz + siz, cmp, swp); break; case 4: { size_t siz2 = siz + siz; zend_sort_4(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, cmp, swp); } break; case 5: { size_t siz2 = siz + siz; zend_sort_5(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, (char *)base + siz2 + siz2, cmp, swp); } break; default: { char *i, *j, *k; char *start = (char *)base; char *end = start + (nmemb * siz); size_t siz2= siz + siz; char *sentry = start + (6 * siz); for (i = start + siz; i \u0026lt; sentry; i += siz) { j = i - siz; if (!(cmp(j, i) \u0026gt; 0)) { continue; } while (j != start) { j -= siz; if (!(cmp(j, i) \u0026gt; 0)) { j += siz; break; } } for (k = i; k \u0026gt; j; k -= siz) { swp(k, k - siz); } } for (i = sentry; i \u0026lt; end; i += siz) { j = i - siz; if (!(cmp(j, i) \u0026gt; 0)) { continue; } do { j -= siz2; if (!(cmp(j, i) \u0026gt; 0)) { j += siz; if (!(cmp(j, i) \u0026gt; 0)) { j += siz; } break; } if (j == start) { break; } if (j == start + siz) { j -= siz; if (cmp(i, j) \u0026gt; 0) { j += siz; } break; } } while (1); for (k = i; k \u0026gt; j; k -= siz) { swp(k, k - siz); } } } break; } } 最后来说说 cmp 这个函数，当 sort_flags 为 SORT_REGULAR 时 sort 函数的 cmp 调用的是 array.c 中的下面这个函数，返回值分成 小于0(b\u0026gt;1), 0(b==a), 大于0(a\u0026gt;b)对比失败也是0。\nstatic int php_array_data_compare(const void *a, const void *b) { Bucket *f; Bucket *s; zval result; zval *first; zval *second; f = (Bucket *) a; s = (Bucket *) b; first = \u0026amp;f-\u0026gt;val; second = \u0026amp;s-\u0026gt;val; if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) { first = Z_INDIRECT_P(first); } if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) { second = Z_INDIRECT_P(second); } if (compare_function(\u0026amp;result, first, second) == FAILURE) { return 0; } ZEND_ASSERT(Z_TYPE(result) == IS_LONG); return ZEND_NORMALIZE_BOOL(Z_LVAL(result)); } 再往下追就是 compare_function 很长我就不贴了，简单说下其中先判断 first 和 second 类型，再进行各种分支比较。比较好奇其中的都是字符串时对比方法，追了下发现底层使用的是C的 memcmp 比较这两个串的前N个字节，这个N是这两个串中较小的那个。\n最后总结下 PHP7 对比 PHP5 时代数组排序调用逻辑相差不大，但是排序算法优化了很多，更不用说底层的hash table了。\n最后的最后文中如有理解错误的点也请指教。\n","permalink":"https://ibelieving.com/posts/2019-05-22-php7_function_sort/","summary":"\u003cp\u003e今天来看看经常使用的数组排序函数如 \u003ccode\u003esort, rsort, asort, arsort, ksort, krsort\u003c/code\u003e 。话不多说直接找 \u003ccode\u003esort\u003c/code\u003e 函数吧。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003ephp7.3\u003c/code\u003e 源码中搜索 \u003ccode\u003ePHP_FUNCTION(sort)\u003c/code\u003e 可以搜到如下\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/15584996147536.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e其中 \u003ccode\u003e.h\u003c/code\u003e 文件是C语言的头文件，直接打开 \u003ccode\u003e.c\u003c/code\u003e 文件。\n\u003ccode\u003esort\u003c/code\u003e 函数如下，其中我加了一点注释。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePHP_FUNCTION(sort)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tzval *array;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tzend_long sort_type = PHP_SORT_REGULAR; // 默认的排序规则\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tcompare_func_t cmp;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t// 这里开始接请求参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tZEND_PARSE_PARAMETERS_START(1, 2)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tZ_PARAM_ARRAY_EX(array, 0, 1)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tZ_PARAM_OPTIONAL\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tZ_PARAM_LONG(sort_type)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t// 根据排序规则获取使用的排序函数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tcmp = php_get_data_compare_func(sort_type, 0);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t// 进行排序\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tif (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tRETURN_FALSE;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tRETURN_TRUE;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e不但 \u003ccode\u003ersort, asort, arsort, ksort, krsort\u003c/code\u003e 这些函数在 \u003ccode\u003earray.c\u003c/code\u003e 文件中，\u003ca href=\"https://www.php.net/manual/zh/book.array.php\"\u003ePHP数组\u003c/a\u003e相关的也都在其中。\n先说下 \u003ccode\u003ersort, asort, arsort, ksort, krsort\u003c/code\u003e 函数内容与 \u003ccode\u003esort\u003c/code\u003e 只有细微的差别。\n\u003ccode\u003eksort、krsort\u003c/code\u003e 是根据键排序所以排序规则获取排序函数用的是 \u003ccode\u003ephp_get_key_compare_func\u003c/code\u003e 参数与 \u003ccode\u003ephp_get_data_compare_func\u003c/code\u003e 是一样的。\n\u003ccode\u003ephp_get_data_compare_func、php_get_key_compare_func\u003c/code\u003e 函数第二个参数意思是是否降序排列，\u003ccode\u003ersort、arsort、krsort\u003c/code\u003e 第二个参数都是1。\n进行排序时 \u003ccode\u003ezend_hash_sort(Z_ARRVAL_P(array), cmp, 1)\u003c/code\u003e 第三个参数意思是是否重新排列索引， \u003ccode\u003esort、rsort\u003c/code\u003e 传的都是1。\n做个表格看下\u003c/p\u003e","title":"PHP7 数组排序函数源码解析"},{"content":"之前用Beyond Compare对比文件，功能非常强大。但是试用期到了就用不了了，而且授权非常的贵，很多功能一般也用不到。\n一般文件对比直接用系统自带的diff命令就可以了。但是，如果临时复制粘贴不同版本文件对比，又不想为了对比而创建文件，JetBrains家IDE对比功能就派上用场了。\nMac下按 ⇧⌘A ，搜索 open diff ，回车。 左右两边可以随意复制粘贴对比了。 ⇧⌘A这其实是一个功能搜索快捷键，可以搜索任何功能。也可以快速开关一个功能。 ","permalink":"https://ibelieving.com/posts/2019-05-07-jetbrains_ide_compare_text/","summary":"\u003cp\u003e之前用Beyond Compare对比文件，功能非常强大。但是试用期到了就用不了了，而且授权非常的贵，很多功能一般也用不到。\u003c/p\u003e\n\u003cp\u003e一般文件对比直接用系统自带的diff命令就可以了。但是，如果临时复制粘贴不同版本文件对比，又不想为了对比而创建文件，JetBrains家IDE对比功能就派上用场了。\u003c/p\u003e\n\u003cp\u003eMac下按 \u003ccode\u003e⇧⌘A\u003c/code\u003e ，搜索 \u003ccode\u003eopen diff\u003c/code\u003e ，回车。\n\u003cimg loading=\"lazy\" src=\"/images/15572093570374.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e左右两边可以随意复制粘贴对比了。\n\u003cimg loading=\"lazy\" src=\"/images/15573665970343.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e⇧⌘A\u003c/code\u003e这其实是一个功能搜索快捷键，可以搜索任何功能。也可以快速开关一个功能。\n\u003cimg loading=\"lazy\" src=\"/images/15572097029571.jpg\"\u003e\u003c/p\u003e","title":"JetBrains IDE 文件对比功能"},{"content":"背景说明 目前公司采用微服务架构，主要开发语言为PHP，通过Swoole开启TCP服务供业务端调用。通过公司内部编写的PHP扩展封装客户端调用逻辑。\n需求 暂定使用Go语言开发新的业务，并提供TCP服务。其中老的PHP项目要通过原有的客户端扩展实现无修改调用。\n解决方案 通过阅读客户端扩展源码了解调用逻辑。编写简单的测试如下。\n\u0026lt;?php $_client = new \\swoole_client(SWOOLE_SOCK_TCP | SWOOLE_KEEP); $_client-\u0026gt;set([ \u0026#39;open_length_check\u0026#39; =\u0026gt; true, \u0026#39;package_length_type\u0026#39; =\u0026gt; \u0026#39;N\u0026#39;, \u0026#39;package_length_offset\u0026#39; =\u0026gt; 0, \u0026#39;package_body_offset\u0026#39; =\u0026gt; 4, \u0026#39;package_max_length\u0026#39; =\u0026gt; 24657920, ]); if (false == $_client-\u0026gt;connect(\u0026#34;127.0.0.1\u0026#34;, 8880)) { printf(\u0026#34;err_msg: %s err_code: %s\u0026#34; . PHP_EOL, var_export($_client-\u0026gt;errMsg, true), var_export($_client-\u0026gt;errCode, true)); } // 随便测试个请求参数 $data = [ \u0026#39;api\u0026#39; =\u0026gt; \u0026#39;getUserInfo\u0026#39;, \u0026#39;params\u0026#39; =\u0026gt; [ \u0026#39;user_id\u0026#39; =\u0026gt; 123 ] ]; $data = json_encode($data); $data = gzcompress($data, 9); $_client-\u0026gt;send(pack(\u0026#34;N\u0026#34;, strlen($data)) . $data); $res = $_client-\u0026gt;recv(); $end = getTime(); $data = json_decode($res, true); 其中前4个字节是head，表示body长度，采用二进制大端字节序编码。body先进行json编码再进行了zlib压缩。这都是编写Go的TCP服务时需要处理的。\n写个简单的Go TCP服务试试，先不考虑过多的错误边界处理。\npackage main import ( \u0026#34;bytes\u0026#34; \u0026#34;compress/zlib\u0026#34; \u0026#34;encoding/binary\u0026#34; \u0026#34;fmt\u0026#34; \u0026#34;io\u0026#34; \u0026#34;net\u0026#34; ) func main() { ln, err := net.Listen(\u0026#34;tcp\u0026#34;, \u0026#34;:8880\u0026#34;) if err != nil { fmt.Printf(\u0026#34;%s\u0026#34;, err) } for { conn, err := ln.Accept() if err != nil { fmt.Printf(\u0026#34;accept err:%s\u0026#34;, err) } go handleConnection(conn) } } func handleConnection(conn net.Conn) { fmt.Println(\u0026#34;on conn\u0026#34;) var err error headLen := 4 head := make([]byte, headLen) if _, err = conn.Read(head); err != nil { fmt.Println(err.Error()) return } // 解码大端字节序获取body长度 bodyLen := binary.BigEndian.Uint32(head) allBody := make([]byte, 0) readLen := 0 for bodyLen \u0026gt; 0 { body := make([]byte, bodyLen) readLen, err = conn.Read(body) if err != nil { fmt.Println(err.Error()) return } bodyLen = bodyLen - uint32(readLen) allBody = append(allBody, body[:readLen]...) } // 解压zlib压缩的数据 RFC 1950 b := bytes.NewReader(allBody) uncompressRead, err := zlib.NewReader(b) if err != nil { fmt.Printf(\u0026#34;uncompress data err:%s\u0026#34;, err) } var uncompressData bytes.Buffer io.Copy(\u0026amp;uncompressData, uncompressRead) // 解出的json字符串 fmt.Printf(\u0026#34;Received:%s\u0026#34;, uncompressData.Bytes()) // 路由调用实际业务逻辑处理 ... // conn.Write() conn.Close() return } 运行Go的TCP服务，跑一个PHP请求测试。\non conn Received:{\u0026#34;api\u0026#34;:\u0026#34;getUserInfo\u0026#34;,\u0026#34;params\u0026#34;:{\u0026#34;user_id\u0026#34;:123}} 经过多次修改测试终于成功。\n","permalink":"https://ibelieving.com/posts/2019-04-30-swoole_to_go_serv/","summary":"\u003ch2 id=\"背景说明\"\u003e背景说明\u003c/h2\u003e\n\u003cp\u003e目前公司采用微服务架构，主要开发语言为PHP，通过Swoole开启TCP服务供业务端调用。通过公司内部编写的PHP扩展封装客户端调用逻辑。\u003c/p\u003e\n\u003ch2 id=\"需求\"\u003e需求\u003c/h2\u003e\n\u003cp\u003e暂定使用Go语言开发新的业务，并提供TCP服务。其中老的PHP项目要通过原有的客户端扩展实现无修改调用。\u003c/p\u003e\n\u003ch2 id=\"解决方案\"\u003e解决方案\u003c/h2\u003e\n\u003cp\u003e通过阅读客户端扩展源码了解调用逻辑。编写简单的测试如下。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-php\" data-lang=\"php\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003e\u0026lt;?\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ephp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$_client\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e\\swoole_client\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eSWOOLE_SOCK_TCP\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eSWOOLE_KEEP\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$_client\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eset\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e([\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;open_length_check\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;package_length_type\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;N\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;package_length_offset\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;package_body_offset\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;package_max_length\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e24657920\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efalse\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$_client\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econnect\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;127.0.0.1\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e8880\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e))\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003eprintf\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;err_msg: %s err_code: %s\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ePHP_EOL\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003evar_export\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$_client\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerrMsg\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e),\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003evar_export\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$_client\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerrCode\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e// 随便测试个请求参数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;api\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;getUserInfo\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;params\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;user_id\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e123\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ejson_encode\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003egzcompress\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e9\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$_client\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003esend\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003epack\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;N\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003estrlen\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e))\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e.\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$_client\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003erecv\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$end\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003egetTime\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$data\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ejson_decode\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中前4个字节是head，表示body长度，采用二进制大端字节序编码。body先进行json编码再进行了zlib压缩。这都是编写Go的TCP服务时需要处理的。\u003c/p\u003e\n\u003cp\u003e写个简单的Go TCP服务试试，先不考虑过多的错误边界处理。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-Go\" data-lang=\"Go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003epackage\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003emain\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003eimport\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;bytes\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;compress/zlib\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;encoding/binary\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;fmt\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;io\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;net\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003efunc\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003emain\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eln\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003enet\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eListen\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;tcp\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;:8880\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e!=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003enil\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintf\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;%s\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econn\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eln\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eAccept\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e!=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003enil\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintf\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;accept err:%s\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003ego\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ehandleConnection\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econn\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003efunc\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ehandleConnection\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econn\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003enet\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eConn\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintln\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;on conn\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003eerror\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eheadLen\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ehead\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003emake\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e([]\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003ebyte\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eheadLen\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e_\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econn\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eRead\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ehead\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e!=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003enil\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintln\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eError\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e())\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#57606a\"\u003e// 解码大端字节序获取body长度\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebodyLen\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebinary\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eBigEndian\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eUint32\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ehead\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eallBody\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003emake\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e([]\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003ebyte\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ereadLen\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebodyLen\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebody\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003emake\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e([]\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003ebyte\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebodyLen\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ereadLen\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econn\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eRead\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebody\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e!=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003enil\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintln\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eError\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e())\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebodyLen\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebodyLen\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003euint32\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ereadLen\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eallBody\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eappend\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eallBody\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebody\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[:\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ereadLen\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e]\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e...\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#57606a\"\u003e// 解压zlib压缩的数据 RFC 1950\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eb\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebytes\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eNewReader\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eallBody\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003euncompressRead\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e:=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ezlib\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eNewReader\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eb\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e!=\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003enil\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintf\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;uncompress data err:%s\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eerr\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003euncompressData\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ebytes\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eBuffer\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003eio\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eCopy\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003euncompressData\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003euncompressRead\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#57606a\"\u003e// 解出的json字符串\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003efmt\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003ePrintf\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#34;Received:%s\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e \u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003euncompressData\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eBytes\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e())\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#57606a\"\u003e// 路由调用实际业务逻辑处理 ...\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#57606a\"\u003e// conn.Write()\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003econn\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#6639ba\"\u003eClose\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e()\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#fff\"\u003e\t\u003c/span\u003e\u003cspan style=\"color:#cf222e\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#fff\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e运行Go的TCP服务，跑一个PHP请求测试。\u003c/p\u003e","title":"编写Go的TCP服务来替代PHP的Swoole"},{"content":"背景说明 来说说当PHP出现E_ERROR级别致命的运行时错误的问题定位方法。例如像Fatal error: Allowed memory size of内存溢出这种。当出现这种错误时会导致程序直接退出，PHP的error log中会记录一条错误日志说明报错的具体文件和代码行数，其它的任何信息都没有了。如果是PHP7的话还可以像捕获异常一样捕获错误，PHP5的话就不行了。\n一般想到的方法就是看看报错的具体代码，如果报错文件是CommonReturn.class.php像下面这个样子。\n\u0026lt;?php /** * 公共返回封装 * Class CommonReturn */ class CommonReturn { /** * 打包函数 * @param $params * @param int $status * * @return mixed */ static public function packData($params, $status = 0) { $res[\u0026#39;status\u0026#39;] = $status; $res[\u0026#39;data\u0026#39;] = json_encode($params); return $res; } } 其中json_encode那一行报错了，然后你查了下packData这个方法，有很多项目的类中都有调用，这时要怎么定位问题呢？\n场景复现 好，首先我们复现下场景。假如实际调用的程序bug.php如下\n\u0026lt;?php require_once \u0026#39;./CommonReturn.class.php\u0026#39;; $res = ini_set(\u0026#39;memory_limit\u0026#39;, \u0026#39;1m\u0026#39;); $res = []; $char = str_repeat(\u0026#39;x\u0026#39;, 999); for ($i = 0; $i \u0026lt; 900 ; $i++) { $res[] = $char; } $get_pack = CommonReturn::packData($res); // something else 运行bug.php PHP错误日志中会记录\n[08-Jan-2019 11:22:52 Asia/Shanghai] PHP Fatal error: Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes) in /CommonReturn.class.php on line 20 复现成功，错误日志中只是说明了报错的文件和哪行代码，无法知道程序的上下文堆栈信息，不知道具体是哪块业务逻辑调用的，这样一来就无法定位修复错误。如果是偶尔出现，并且没有来自前端业务的反馈要怎么排查呢。\n解决思路 有人想到了修改memory_limit增加内存分配，但这种方法治标不治本。做开发肯定要找到问题的根源。 开启core dump，如果生成code文件可以进行调试，但是发现code只有进程异常退出才会生成。像E_ERROR级别的错误不一定会生成code文件，内存溢出这种可能PHP内部自己就处理了。 使用register_shutdown_function注册一个PHP终止时的回调函数，再调用error_get_last如果获取到了最后发生的错误，就通过debug_print_backtrace获取程序的堆栈信息，我们试试看。 修改CommonReturn.class.php文件如下\n\u0026lt;?php /** * 公共返回封装 * Class CommonReturn */ class CommonReturn { /** * 打包函数 * @param $params * @param int $status * * @return mixed */ static public function packData($params, $status = 0) { register_shutdown_function([\u0026#39;CommonReturn\u0026#39;, \u0026#39;handleFatal\u0026#39;]); $res[\u0026#39;status\u0026#39;] = $status; $res[\u0026#39;data\u0026#39;] = json_encode($params); return $res; } /** * 错误处理 */ static protected function handleFatal() { $err = error_get_last(); if ($err[\u0026#39;type\u0026#39;]) { ob_start(); debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); $trace = ob_get_clean(); $log_cont = \u0026#39;time=%s\u0026#39; . PHP_EOL . \u0026#39;error_get_last:%s\u0026#39; . PHP_EOL . \u0026#39;trace:%s\u0026#39; . PHP_EOL; @file_put_contents(\u0026#39;/tmp/debug_\u0026#39; . __FUNCTION__ . \u0026#39;.log\u0026#39;, sprintf($log_cont, date(\u0026#39;Y-m-d H:i:s\u0026#39;), var_export($err, 1), $trace), FILE_APPEND); } } } 再次运行bug.php，日志如下。\nerror_get_last:array ( \u0026#39;type\u0026#39; =\u0026gt; 1, \u0026#39;message\u0026#39; =\u0026gt; \u0026#39;Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes)\u0026#39;, \u0026#39;file\u0026#39; =\u0026gt; \u0026#39;/CommonReturn.class.php\u0026#39;, \u0026#39;line\u0026#39; =\u0026gt; 23, ) trace:#0 CommonReturn::handleFatal() 回溯信息没有来源，尴尬了。猜测因为backtrace信息保存在内存中，当出现致命错误时会清空。没办法，把backtrace从外面传进来试试。再次修改CommonReturn.class.php。\n\u0026lt;?php /** * 公共返回封装 * Class CommonReturn */ class CommonReturn { /** * 打包函数 * @param $params * @param int $status * * @return mixed */ static public function packData($params, $status = 0) { ob_start(); debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); $trace = ob_get_clean(); register_shutdown_function([\u0026#39;CommonReturn\u0026#39;, \u0026#39;handleFatal\u0026#39;], $trace); $res[\u0026#39;status\u0026#39;] = $status; $res[\u0026#39;data\u0026#39;] = json_encode($params); return $res; } /** * 错误处理 * @param $trace */ static protected function handleFatal($trace) { $err = error_get_last(); if ($err[\u0026#39;type\u0026#39;]) { $log_cont = \u0026#39;time=%s\u0026#39; . PHP_EOL . \u0026#39;error_get_last:%s\u0026#39; . PHP_EOL . \u0026#39;trace:%s\u0026#39; . PHP_EOL; @file_put_contents(\u0026#39;/tmp/debug_\u0026#39; . __FUNCTION__ . \u0026#39;.log\u0026#39;, sprintf($log_cont, date(\u0026#39;Y-m-d H:i:s\u0026#39;), var_export($err, 1), $trace), FILE_APPEND); } } } 再次运行bug.php，日志如下。\nerror_get_last:array ( \u0026#39;type\u0026#39; =\u0026gt; 1, \u0026#39;message\u0026#39; =\u0026gt; \u0026#39;Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes)\u0026#39;, \u0026#39;file\u0026#39; =\u0026gt; \u0026#39;/CommonReturn.class.php\u0026#39;, \u0026#39;line\u0026#39; =\u0026gt; 26, ) trace:#0 CommonReturn::packData() called at [/bug.php:13] 成功定位到了调用来源，在bug.php的13行。将最终的CommonReturn.class.php发布到生产环境，再次出现出现错误时候看日志就可以了。但是这样的话所有调用packData的程序都会执行trace函数，肯定也会影响性能的。\n总结 对于其中使用到的register_shutdown_function函数需要注意，可以注册多个不同的回调，但是如果某一个回调函数中exit了，那么后面注册的回调函数都不会执行。 debug_print_backtrace这个获取回溯信息函数第一个是否包含请求参数，第二个是回溯记录层数，我们这里是不返回请求参数，可以节省些内存，而且如果请求参数巨大的话调这个函数可能就直接内存溢出了。 最好的办法就是升级PHP7，可以像异常一样捕获错误。 ","permalink":"https://ibelieving.com/posts/2019-01-08-php5_error_handle/","summary":"\u003ch2 id=\"背景说明\"\u003e背景说明\u003c/h2\u003e\n\u003cp\u003e来说说当PHP出现E_ERROR级别致命的运行时错误的问题定位方法。例如像\u003ccode\u003eFatal error: Allowed memory size of\u003c/code\u003e内存溢出这种。当出现这种错误时会导致程序直接退出，PHP的error log中会记录一条错误日志说明报错的具体文件和代码行数，其它的任何信息都没有了。如果是PHP7的话还可以像捕获异常一样捕获错误，PHP5的话就不行了。\u003c/p\u003e\n\u003cp\u003e一般想到的方法就是看看报错的具体代码，如果报错文件是\u003ccode\u003eCommonReturn.class.php\u003c/code\u003e像下面这个样子。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-php\" data-lang=\"php\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003e\u0026lt;?\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ephp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e * 公共返回封装\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e * Class CommonReturn\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eCommonReturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#0a3069\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e     * 打包函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e     * @param     $params\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e     * @param int $status\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e     * @return mixed\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0a3069\"\u003e     */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#cf222e\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#cf222e\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#6639ba\"\u003epackData\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$params\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$status\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;status\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e]\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$status\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;data\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e]\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003ejson_encode\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$params\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#cf222e\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中\u003ccode\u003ejson_encode\u003c/code\u003e那一行报错了，然后你查了下\u003ccode\u003epackData\u003c/code\u003e这个方法，有很多项目的类中都有调用，这时要怎么定位问题呢？\u003c/p\u003e\n\u003ch2 id=\"场景复现\"\u003e场景复现\u003c/h2\u003e\n\u003cp\u003e好，首先我们复现下场景。假如实际调用的程序\u003ccode\u003ebug.php\u003c/code\u003e如下\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-php\" data-lang=\"php\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#0550ae\"\u003e\u0026lt;?\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003ephp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003erequire_once\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;./CommonReturn.class.php\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eini_set\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;memory_limit\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0a3069\"\u003e\u0026#39;1m\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e[];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$char\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003estr_repeat\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#0a3069\"\u003e\u0026#39;x\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e999\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#cf222e\"\u003efor\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$i\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$i\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e900\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$i\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e++\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e[]\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#953800\"\u003e$char\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#1f2328\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#953800\"\u003e$get_pack\u003c/span\u003e \u003cspan style=\"color:#0550ae\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#1f2328\"\u003eCommonReturn\u003c/span\u003e\u003cspan style=\"color:#0550ae\"\u003e::\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003epackData\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#953800\"\u003e$res\u003c/span\u003e\u003cspan style=\"color:#1f2328\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#57606a\"\u003e// something else\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e运行bug.php PHP错误日志中会记录\u003c/p\u003e","title":"PHP5下的Error错误处理及问题定位"},{"content":"队列的参数即声明Queues时的Arguments。 消息的属性即向Exchange发布消息时的Properties。\nQueues Arguments Message TTL 消息的存活时间，写入队列后被消费前可以存活的时间单位毫秒，通过x-message-ttl属性设置。\nAuto expire 队列的存活时间，指定时间内没有consumer或get方式请求队列消息则会自动删除，通过x-expires属性设置。\nDead letter exchange 死信消息的exchange，通过x-dead-letter-exchange属性设置。\nDead letter routing key 死信消息的路由键，通过x-dead-letter-routing-key属性设置。\nMaximum priority 消息支持的最大优先级，可实现优先级消息队列，通过x-max-priority属性设置。\nMax length 队列的最大消息数，通过x-max-length属性设置。\nMax length bytes 队列的消息的最大字节数，通过x-max-length-bytes属性设置。\nLazy mode 懒惰队列模式，将队列内容移动到磁盘上，当消息者请求时加载入内存，这样可以支持非常长的队列，通过x-queue-mode属性设置。\nMaster locator 在RabbitMQ的高可用镜像模式中，队列消息首先会写入主节点再依次备份至从节点，通过x-queue-master-locator属性设置队列的主节点选择策略。\n选择承担主节点最少的节点min-masters 选择声明队列客户端连接到的节点client-local 随机挑选一个节点random 死信相关 当消息满足以下三种情况之一时会当做死信来处理：\n消息被拒绝 (basic.reject or basic.nack) 消息未消费超时 超出队列长度限制 队列最大长度相关 通过x-max-length、x-max-length-bytes来设置队列的最大长度。一个可以控制队列消息的个数，一个可以控制队列占用的空间。如果两个都设置任何一个触发都会执行队列溢出行为，默认的队列溢出后会从队列头开始丢弃消息或进行死信处理。通过x-overflow可以设置队列溢出后的行为，值为drop-head(默认值)或reject-publish(拒绝新消息)。\nMessage Properties 属性 说明 content_type MIME类型 content_encoding MIME编码 priority 消息优先级 correlation_id 业务应用关联标识 reply_to 回复队列名称 expiration 过期时间 message_id 业务应用消息标识 timestamp 消息写入时间戳 type 消息类型 user_id 用户id app_id 应用id cluster_id 集群id ","permalink":"https://ibelieving.com/posts/2018-01-31-rabbitmq2/","summary":"\u003cp\u003e队列的参数即声明Queues时的Arguments。\n消息的属性即向Exchange发布消息时的Properties。\u003c/p\u003e\n\u003ch2 id=\"queues-arguments\"\u003eQueues Arguments\u003c/h2\u003e\n\u003cp\u003eMessage TTL\n消息的存活时间，写入队列后被消费前可以存活的时间单位毫秒，通过\u003ccode\u003ex-message-ttl\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eAuto expire\n队列的存活时间，指定时间内没有consumer或get方式请求队列消息则会自动删除，通过\u003ccode\u003ex-expires\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eDead letter exchange\n死信消息的exchange，通过\u003ccode\u003ex-dead-letter-exchange\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eDead letter routing key\n死信消息的路由键，通过\u003ccode\u003ex-dead-letter-routing-key\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eMaximum priority\n消息支持的最大优先级，可实现优先级消息队列，通过\u003ccode\u003ex-max-priority\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eMax length\n队列的最大消息数，通过\u003ccode\u003ex-max-length\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eMax length bytes\n队列的消息的最大字节数，通过\u003ccode\u003ex-max-length-bytes\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eLazy mode\n懒惰队列模式，将队列内容移动到磁盘上，当消息者请求时加载入内存，这样可以支持非常长的队列，通过\u003ccode\u003ex-queue-mode\u003c/code\u003e属性设置。\u003c/p\u003e\n\u003cp\u003eMaster locator\n在RabbitMQ的高可用镜像模式中，队列消息首先会写入主节点再依次备份至从节点，通过\u003ccode\u003ex-queue-master-locator\u003c/code\u003e属性设置队列的主节点选择策略。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e选择承担主节点最少的节点\u003ccode\u003emin-masters\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e选择声明队列客户端连接到的节点\u003ccode\u003eclient-local\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e随机挑选一个节点\u003ccode\u003erandom\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e死信相关\n当消息满足以下三种情况之一时会当做死信来处理：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e消息被拒绝 (basic.reject or basic.nack)\u003c/li\u003e\n\u003cli\u003e消息未消费超时\u003c/li\u003e\n\u003cli\u003e超出队列长度限制\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e队列最大长度相关\n通过\u003ccode\u003ex-max-length\u003c/code\u003e、\u003ccode\u003ex-max-length-bytes\u003c/code\u003e来设置队列的最大长度。一个可以控制队列消息的个数，一个可以控制队列占用的空间。如果两个都设置任何一个触发都会执行队列溢出行为，默认的队列溢出后会从队列头开始丢弃消息或进行死信处理。通过\u003ccode\u003ex-overflow\u003c/code\u003e可以设置队列溢出后的行为，值为\u003ccode\u003edrop-head\u003c/code\u003e(默认值)或\u003ccode\u003ereject-publish\u003c/code\u003e(拒绝新消息)。\u003c/p\u003e\n\u003ch2 id=\"message-properties\"\u003eMessage Properties\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e属性\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003econtent_type\u003c/td\u003e\n          \u003ctd\u003eMIME类型\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003econtent_encoding\u003c/td\u003e\n          \u003ctd\u003eMIME编码\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003epriority\u003c/td\u003e\n          \u003ctd\u003e消息优先级\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ecorrelation_id\u003c/td\u003e\n          \u003ctd\u003e业务应用关联标识\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ereply_to\u003c/td\u003e\n          \u003ctd\u003e回复队列名称\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eexpiration\u003c/td\u003e\n          \u003ctd\u003e过期时间\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003emessage_id\u003c/td\u003e\n          \u003ctd\u003e业务应用消息标识\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003etimestamp\u003c/td\u003e\n          \u003ctd\u003e消息写入时间戳\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003etype\u003c/td\u003e\n          \u003ctd\u003e消息类型\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003euser_id\u003c/td\u003e\n          \u003ctd\u003e用户id\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eapp_id\u003c/td\u003e\n          \u003ctd\u003e应用id\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ecluster_id\u003c/td\u003e\n          \u003ctd\u003e集群id\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e","title":"RabbitMQ 消息队列：队列的参数与消息的属性"},{"content":"简介 消息队列用来解决不同项目间通信、业务解耦。消息队列有很多种比如用Redis实现的轻量级消息队列。RabbitMQ是消息队列的一种，基于AMQP协议，用Erlang语言编写，属于一种消息队列中间件。\n消息机制 Connection 链接 真实的TCP链接\nChannel 信道 基于Connection创建的Channel，所有的数据传输都是基于Channel的。大家都知道TCP链接需要三次握手，业务频繁每次开TCP链接对性能也会有不小的损耗，TCP链接数也有限制。Channel的存在主要是为了复用TCP链接。\nExchange 交换机 消息生产者生产的所有消息都会先写入Exchange中，再路由到Queues中，如果Exchange没有绑定或未匹配到Queues则消息会被丢弃。\nQueues 队列 生产者生产的消息会从Exchange中路由到Queues中，消费者从Queues中消费消息。\nBinding 绑定 Binding将Exchange与Queues关联起来。\nRouting key 路由键 路由键是消息从Exchange进入到某个Queues的规则。 在将Queues绑定至Exchange时会设置消息从Exchange路由至Queues的绑定路由键规则。 在将消息写入Exchange时会附带消息的路由键。\nExchange类型为direct或topic时，消息的投递会根据消息的路由键和绑定的路由键进行匹配，Exchange将消息投递给所有匹配上的Queues。\n路由键写法 路由键可以由. 进行分隔，如computer.mac或computer.win。 路由键还支持通配符来模糊匹配，*与# *匹配一个分隔的单词 #匹配多个或零个分隔的单词\n应用举例\nExchange Routing key Queues X *.*.imac apple X apple.# apple X *.phone.* phone 此时写入一条消息路由键为apple.phone.iphone4会被投递到队列apple与phone。 再写入一条消息路由键为apple.computer.imac仅会被投递到apple，此时apple队列匹配了两个路由键，但是也只会投递到apple一次。 再写入一条消息路由键为micro.computer.win因为没有匹配的路由键队列该消息会被丢弃。 Exchange Types 交换机类型 fanout 广播 fanout类型的Exchange会无视路由键，将消息投递给所有绑定到该Exchange上的Queues。\ndirect 单播 direct类型的Exchange会将消息投递给路由键完全匹配的Queues中。\ntopic 组播 topic类型的Exchange会将消息投递给路由键模糊匹配的Queues中。\nheaders headers类型的Exchange也会无视路由键，会根据headers中的属性来进行匹配。该类型应用较少，不过在RabbitMQ内部还是有使用。\n","permalink":"https://ibelieving.com/posts/2017-12-28-rabbitmq1/","summary":"\u003ch2 id=\"简介\"\u003e简介\u003c/h2\u003e\n\u003cp\u003e消息队列用来解决不同项目间通信、业务解耦。消息队列有很多种比如用Redis实现的轻量级消息队列。RabbitMQ是消息队列的一种，基于AMQP协议，用Erlang语言编写，属于一种消息队列中间件。\u003c/p\u003e\n\u003ch2 id=\"消息机制\"\u003e消息机制\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/15143024048456.jpg\"\u003e\u003c/p\u003e\n\u003ch3 id=\"connection---链接\"\u003eConnection   链接\u003c/h3\u003e\n\u003cp\u003e真实的TCP链接\u003c/p\u003e\n\u003ch3 id=\"channel------信道\"\u003eChannel      信道\u003c/h3\u003e\n\u003cp\u003e基于Connection创建的Channel，所有的数据传输都是基于Channel的。大家都知道TCP链接需要三次握手，业务频繁每次开TCP链接对性能也会有不小的损耗，TCP链接数也有限制。Channel的存在主要是为了复用TCP链接。\u003c/p\u003e\n\u003ch3 id=\"exchange-----交换机\"\u003eExchange     交换机\u003c/h3\u003e\n\u003cp\u003e消息生产者生产的所有消息都会先写入Exchange中，再路由到Queues中，如果Exchange没有绑定或未匹配到Queues则消息会被丢弃。\u003c/p\u003e\n\u003ch3 id=\"queues-------队列\"\u003eQueues       队列\u003c/h3\u003e\n\u003cp\u003e生产者生产的消息会从Exchange中路由到Queues中，消费者从Queues中消费消息。\u003c/p\u003e\n\u003ch3 id=\"binding------绑定\"\u003eBinding      绑定\u003c/h3\u003e\n\u003cp\u003eBinding将Exchange与Queues关联起来。\u003c/p\u003e\n\u003ch3 id=\"routing-key--路由键\"\u003eRouting key  路由键\u003c/h3\u003e\n\u003cp\u003e路由键是消息从Exchange进入到某个Queues的规则。\n在将Queues绑定至Exchange时会设置消息从Exchange路由至Queues的绑定路由键规则。\n在将消息写入Exchange时会附带消息的路由键。\u003c/p\u003e\n\u003cp\u003eExchange类型为direct或topic时，消息的投递会根据消息的路由键和绑定的路由键进行匹配，Exchange将消息投递给所有匹配上的Queues。\u003c/p\u003e\n\u003ch4 id=\"路由键写法\"\u003e路由键写法\u003c/h4\u003e\n\u003cp\u003e路由键可以由\u003ccode\u003e.\u003c/code\u003e 进行分隔，如\u003ccode\u003ecomputer.mac\u003c/code\u003e或\u003ccode\u003ecomputer.win\u003c/code\u003e。\n路由键还支持通配符来模糊匹配，\u003ccode\u003e*\u003c/code\u003e与\u003ccode\u003e#\u003c/code\u003e\n\u003ccode\u003e*\u003c/code\u003e匹配一个分隔的单词\n\u003ccode\u003e#\u003c/code\u003e匹配多个或零个分隔的单词\u003c/p\u003e\n\u003cp\u003e应用举例\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eExchange\u003c/th\u003e\n          \u003cth\u003eRouting key\u003c/th\u003e\n          \u003cth\u003eQueues\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eX\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e*.*.imac\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eapple\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eX\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eapple.#\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eapple\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eX\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e*.phone.*\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ephone\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e此时写入一条消息路由键为\u003ccode\u003eapple.phone.iphone4\u003c/code\u003e会被投递到队列apple与phone。\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e再写入一条消息路由键为\u003ccode\u003eapple.computer.imac\u003c/code\u003e仅会被投递到apple，此时apple队列匹配了两个路由键，但是也只会投递到apple一次。\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e再写入一条消息路由键为\u003ccode\u003emicro.computer.win\u003c/code\u003e因为没有匹配的路由键队列该消息会被丢弃。\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e \u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"exchange-types---交换机类型\"\u003eExchange Types   交换机类型\u003c/h3\u003e\n\u003ch4 id=\"fanout-广播\"\u003efanout 广播\u003c/h4\u003e\n\u003cp\u003efanout类型的Exchange会无视路由键，将消息投递给所有绑定到该Exchange上的Queues。\u003c/p\u003e\n\u003ch4 id=\"direct-单播\"\u003edirect 单播\u003c/h4\u003e\n\u003cp\u003edirect类型的Exchange会将消息投递给路由键完全匹配的Queues中。\u003c/p\u003e\n\u003ch4 id=\"topic-组播\"\u003etopic 组播\u003c/h4\u003e\n\u003cp\u003etopic类型的Exchange会将消息投递给路由键模糊匹配的Queues中。\u003c/p\u003e\n\u003ch4 id=\"headers\"\u003eheaders\u003c/h4\u003e\n\u003cp\u003eheaders类型的Exchange也会无视路由键，会根据headers中的属性来进行匹配。该类型应用较少，不过在RabbitMQ内部还是有使用。\u003c/p\u003e","title":"RabbitMQ 消息队列：浅谈"}]