<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on hwholiday</title>
    <link>http://hwholiday.github.io/posts/</link>
    <description>Recent content in Posts on hwholiday</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 28 Feb 2023 00:00:00 +0000</lastBuildDate><atom:link href="http://hwholiday.github.io/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>无脑式 hugo 博客通过 github actions 自动发布</title>
      <link>http://hwholiday.github.io/2023/hufo-action/</link>
      <pubDate>Tue, 28 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2023/hufo-action/</guid>
      <description>github actions 简介 Github Actions 是GitHub的持续集成服务。持续集成由很多操作组成，比如登录远程服务器，发布内容到第三方服务等等，GitHub把这些操作称为actions。 流程 本文适用为，一个github仓库为博客源码存放地址，一个github仓库为博客发布
在你的github账户里面创建 token https://github.com/settings/tokens 将生成的token放在你的 https://github.com/你的博客源码仓库名/settings/secrets/actions 中设置变量名为 ACTION_ACCESS_TOKENS 在你的博客源码仓库中新建 目录 .github/workflows 文件 ci.yaml 推送代码，等待构建，几分钟后就可以在你的 github 仓库为博客发布中找到你的发布内容了 构建过程可以在 https://github.com/你的博客源码仓库名/actions 中查看 ci.yaml 代码 name: hugo blog github pages on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: submodules: true fetch-depth: 0 - name: Setup Hugo uses: peaceiris/actions-hugo@v2 with: hugo-version: &amp;#39;latest&amp;#39; - name: Build run: hugo --buildDrafts - uses: finnp/create-file-action@master #如果你不需要自定义域名直接删除 env: FILE_NAME: .</description>
    </item>
    
    <item>
      <title>用golang实现一个timewheel时间轮</title>
      <link>http://hwholiday.github.io/2023/timewheel/</link>
      <pubDate>Sun, 26 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2023/timewheel/</guid>
      <description>timewheel简介 时间轮是一个环形队列，底层实现就是一个固定长度的数组，数组中的每个元素存储一个双向列表，这个列表存放着该时间内需要执行的所有任务 例子 抽象点来说时钟表盘就是1秒为一个时间刻度，一共（一天）会有86400个刻度的时间轮，当指针走到那个刻度的时候就可以把对应的任务全部取出执行 也就是说这里我们定义了一个可以延迟86400秒的时候轮，不过当我们定一个86401秒后执行的任务怎么办 方案一 多级时间轮 （这里不展开描述） 方案二 定义circle参数 （本文）, 一轮是86400秒的话，86401= 86400 + 1 也就是 1circle（一轮）加上一个刻度就可以取出该任务执行 结构体 type TimeWheel struct { interval time.Duration slots []*list.List slotsNum int64 currentSlots int64 ticker *time.Ticker mt sync.Mutex isRun bool tasks sync.Map addTaskCh chan *Task removeTaskCh chan string closeCh chan struct{} } type Task struct { ID string createTime time.Time delay time.Duration slots int64 circle int64 // 多少圈 job Job times int64 //执行多少次 -1 一直执行 } 启动时间轮 //定义定时器驱动时间轮 t.</description>
    </item>
    
    <item>
      <title>OAuth 2.0-授权码模式（authorization code）仿微信设计（战术篇）</title>
      <link>http://hwholiday.github.io/2022/auth2_tactics/</link>
      <pubDate>Mon, 17 Jan 2022 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2022/auth2_tactics/</guid>
      <description>归档 OAuth 2.0-授权码模式（authorization code）仿微信设计（战略篇） OAuth 2.0-授权码模式（authorization code）仿微信设计（战术篇） (DDD 领域驱动设计实现代码 Golang ) DDD（领域设计驱动）+ 六边形架构 APPID 必须是10位 因为使用了 ase126 来作为 OpenId的生成 （key=APPID(10)+SALT(6) 16 = 126） 代码地址 完整示例可直接运行 请点击 代码结构参考 请点击 如有任何疑问 请点击联系 . ├── adpter │ ├── adpter.go │ └── http │ ├── auth_handles │ │ ├── auth_code_handles.go │ │ ├── auth_token_handles.go │ │ └── handers.go │ ├── http.go │ └── routers │ ├── middleware.go │ └── routers.go ├── cmd │ ├── app.</description>
    </item>
    
    <item>
      <title>OAuth 2.0-授权码模式（authorization code）仿微信设计（战略篇）</title>
      <link>http://hwholiday.github.io/2022/auth2_strategy/</link>
      <pubDate>Sun, 16 Jan 2022 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2022/auth2_strategy/</guid>
      <description>归档 OAuth 2.0-授权码模式（authorization code）仿微信设计（战略篇） OAuth 2.0-授权码模式（authorization code）仿微信设计（战术篇） (DDD 领域驱动设计实现代码 Golang ) 在听到 OAuth 2.0 这个名词时可能很多人只知道这个是用来授权的协议，具体是怎么实现的，以及解决了什么问题，可能大家还不是很了解，下面我给大家一个场景来体会下 假设我们有个 APP 来统计用户 github 的使用情况 要从 Github 获取数据，用户必须同意把自己的 Github 信息给 APP，APP 才能得到 Github 的数据进行统计数据 一般来说只有把用户名密码或者用户在 Github 的 Token ,Session 给 APP ，APP才能通过 Github 获取数据，但是当前的操作可能存在以下问题 Token , Session 这两兄弟的有效期不长，可能刚给了APP ，一会就又失效了 给了用户名密码 APP 会把用户名密码都存在自己的服务器上，要是被破解或者拖库会造成密码泄露用这个密码进行保护的资源全部有泄露的风险 APP 获取了用户在 Github 的全部权限，用户没办法限制授权的范围和时间 想要回收在这个 APP 的权限，用户必须改密码，这样的话其他 APP 也不行使用了，造成很大的麻烦 什么是 OAuth 2.0 在了解上面的例子后大家也应该清楚为什么会出现 OAuth 2.0 ，以及 OAuth 2.0 的作用 使用方=&amp;ldquo;APP&amp;rdquo; | 提供方 = &amp;ldquo;Github&amp;rdquo; | 授权层 =&amp;ldquo;OAuth 2.</description>
    </item>
    
    <item>
      <title>hconfig 一个可插拔的 Golang 配置管理工具 支持（etcd/k8s(kubernetes)/apollo）</title>
      <link>http://hwholiday.github.io/2022/hconfig/</link>
      <pubDate>Wed, 05 Jan 2022 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2022/hconfig/</guid>
      <description>hconfig 一个可插拔的 Golang 配置管理工具 支持（etcd/k8s(kubernetes)/apollo） 什么是可插拔式程序 一个统计的可插拔内核 各个组件相互独立 可插拔式程序 在设计一个可插拔式程序时我们应该想到的是怎么把我们的需求给实现了，然后我们再搞一波抽象（统计的可插拔内核
不同的模块只要实现了这内核中的方法，我们的主程序就能去调用模块中对应的方法 假设我们打算修一个房子睡觉，我们只需要把大体的框架修好（这个就是一个统计的可插拔内核），然后我们在里面规划 不同的模块比如次卧，主卧，客卧，（各个组件相互独立），对于我们需求来说都是用来睡觉的只是实现的方式不同而已，而且相互独立 hconfig 详解 hconfig 在设计上主要有2个功能
读取配置信息 监听配置信息的变化 conf, err := NewHConfig( WithDataSource(c),//c 不同的源 ) // 加载配置 conf.Load() //读取配置 val, err := conf.Get(&amp;#34;test.yaml&amp;#34;) t.Logf(&amp;#34;val %+v\n&amp;#34;, val.String()) //监听配置变化 conf.Watch(func(path string, v HVal) { t.Logf(&amp;#34;path %s val %+v\n&amp;#34;, path, v.String()) }) 在了解到什么是可插拔程序时，我们再来看一看hconfig的结构
一个统计的可插拔内核 type DataSource interface { Load() ([]*Data, error) Watch() (DataWatcher, error) } type DataWatcher interface { Change() ([]*Data, error) Close() error } 各个组件相互独立 etcd cli, err := clientv3.</description>
    </item>
    
    <item>
      <title>2022 你好 2021 再见</title>
      <link>http://hwholiday.github.io/2022/2022/</link>
      <pubDate>Sat, 01 Jan 2022 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2022/2022/</guid>
      <description>2021 再见 不知不觉一年的时间又过去了，今年又水了一年 瞄了一眼博客，就发布了11篇文章，然后闭眼5分钟使劲想想我这一年到底干了多少事情终于灵光一现想起一些琐事 learning_tools 项目从几百star到了1.6K kubernetes 学习使用并写了一些插件 DDD（领域驱动设计-使用并落地） 对插拔式组件开发有了新的认识并写了一些组件（hconfig , hgrpc） 看了几本书（代码简洁之道 , 领域驱动设计 , 人类起源） 2022 你好 新的一年开始了，flag 这个东西真的每年都立每年都摸瞎，不过这个东西感觉不立一个对不起这一年的开始，哈哈哈 所以我希望（flag）在2022里面 为新家庭保驾护航 对云原生的技术加深一些 每周产出一篇博客 搞一个自己的公众号 ghost-im 这个项目在新的一年内完成 不立了不立了，立太多等到来年再写这个的时候，又是摸瞎 </description>
    </item>
    
    <item>
      <title>封装 zap 日志注入 trace 信息 Trace Id（内含 gin 例子）</title>
      <link>http://hwholiday.github.io/2021/hlog/</link>
      <pubDate>Tue, 14 Dec 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/hlog/</guid>
      <description>hlog (源码地址) 实现自动切割文件 (基于 lumberjack 实现) 实现可传递 trace 信息 （基于 Context 实现） 配置 Development bool // 是否开发模式 LogFileDir string // 日志路径 AppName string // APP名字 MaxSize int //文件多大开始切分 MaxBackups int //保留文件个数 MaxAge int //文件保留最大实际 Level string // 日志打印等级 CtxKey string //通过 ctx 传递 hlog 信息 WriteFile bool // 是否写入文件 WriteConsole bool // 是否控制台打印 实现自动切割文件核心代码 zapcore.AddSync(&amp;amp;lumberjack.Logger{ Filename: l.opts.LogFileDir + &amp;#34;/&amp;#34; + l.opts.AppName + &amp;#34;.log&amp;#34;, MaxSize: l.opts.MaxSize, MaxBackups: l.opts.MaxBackups, MaxAge: l.opts.MaxAge, Compress: true, LocalTime: true, }) 实现可传递 trace 信息核心代码 func (l *Logger) GetCtx(ctx context.</description>
    </item>
    
    <item>
      <title> gRPC负载均衡（自定义负载均衡策略--etcd 实现）</title>
      <link>http://hwholiday.github.io/2021/etcd_grpc/</link>
      <pubDate>Fri, 23 Jul 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/etcd_grpc/</guid>
      <description>背景 在工作学习中使用gRPC的地方比较多，通常我们都使用的是自带的负载均衡算法，但是在某些场景下我们需要对服务的版本进行控制 比如 [app V2 只能去链接 user V3],在这样的情况下就只能选自定义负载均衡策略
目标 实现基于版本（version）的grpc负载均衡器，了解过程后可自己实现更多的负载均衡功能
注册中心 Etcd Lease 是一种检测客户端存活状况的机制。 群集授予具有生存时间的租约。 如果etcd 群集在给定的TTL 时间内未收到keepAlive，则租约到期。 为了将租约绑定到键值存储中，每个key 最多可以附加一个租约 服务注册 (注册服务) 定时把本地服务（APP）地址,版本等信息注册到服务器 服务发现 (客户端发起服务解析请求（APP）) 查询注册中心（APP）下有那些服务 并向所有的服务建立HTTP2长链接 通过Etcd watch 监听服务（APP），通过变化更新链接 负载均衡 (客户端发起请求（APP）) 负载均衡选择合适的服务（APP HTTP2长链接） 发起调用 服务注册 (注册服务) 源码 register.go
func NewRegister(opt ...RegisterOptions) (*Register, error) { s := &amp;amp;Register{ opts: newOptions(opt...), } var ctx, cancel = context.WithTimeout(context.Background(), time.Duration(s.opts.RegisterTtl)*time.Second) defer cancel() data, err := json.Marshal(s.opts) if err != nil { return nil, err } etcdCli, err := clientv3.</description>
    </item>
    
    <item>
      <title>Filebeat 收集 K8S 日志</title>
      <link>http://hwholiday.github.io/2021/k8s-filebeat/</link>
      <pubDate>Mon, 31 May 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/k8s-filebeat/</guid>
      <description>介绍 每个Node节点上的容器应用日志，默认都会在/var/log/containers （标准输出） Pod -&amp;gt; /var/log/containers/*.log -&amp;gt; Filebeat -&amp;gt; Logstash -&amp;gt; 其他输出 app-*.log 是你的应用日志文件（可在宿主机的/var/log/containers/目录下查看自己的日志格式） 使用DaemonSet安装 filebeat （filebeat.yaml） apiVersion: apps/v1 kind: DaemonSet metadata: labels: app: filebeat name: filebeat-daemonset spec: selector: matchLabels: app: filebeat template: metadata: labels: app: filebeat spec: containers: - name: filebeat-daemonset image: docker.elastic.co/beats/filebeat:7.12.1 args: [ &amp;#34;-c&amp;#34;, &amp;#34;/usr/share/filebeat/filebeat.yml&amp;#34;, &amp;#34;-e&amp;#34;, ] securityContext: runAsUser: 0 volumeMounts: - mountPath: /usr/share/filebeat/filebeat.yml name: volume-configmap subPath: filebeat.yml readOnly: true - mountPath: /data/app/docker/containers name: varlibdockercontainers readOnly: true - name: varlog mountPath: /var/log readOnly: true volumes: - name: volume-configmap configMap: defaultMode: 420 name: filebeat-configmap - name: varlibdockercontainers hostPath: path: /data/app/docker/containers - name: varlog hostPath: path: /var/log --- apiVersion: v1 data: filebeat.</description>
    </item>
    
    <item>
      <title>Kubernetes 集群挂载高可用 NFS 网络文件存储</title>
      <link>http://hwholiday.github.io/2021/k8s-nsf/</link>
      <pubDate>Tue, 18 May 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/k8s-nsf/</guid>
      <description>安装NFS高可用集群 安装 nfs-client-provisioner curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh helm repo add azure http://mirror.azure.cn/kubernetes/charts/ helm install nfs-storage azure/nfs-client-provisioner --set nfs.server=&amp;#34;172.12.17.200&amp;#34; --set nfs.path=/fs/nsf-data --set storageClass.name=nfs-hw 创建PVC kubectl apply -f nfs-pvc.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc-test spec: storageClassName: &amp;#34;nfs-hw&amp;#34; accessModes: - ReadWriteMany resources: requests: storage: 10Gi 测试 kubectl apply -f nfs-test.yaml
apiVersion: batch/v1 kind: Job metadata: name: nfsjob spec: template: spec: containers: - name: bbox1 image: busybox args: - /bin/sh - -c - echo &amp;#34;1231231231&amp;#34; &amp;gt; /nfs-data/hello volumeMounts: - mountPath: &amp;#34;/nfs-data&amp;#34; name: nfsdata restartPolicy: Never volumes: - name: nfsdata persistentVolumeClaim: claimName: nfs-pvc-test end 接下来去看看 NFS 服务器上是否有对应文件文件 K8S 集群是 v1.</description>
    </item>
    
    <item>
      <title>NFS (Kubernetes) 高可用方案（NFS&#43;keepalived&#43;Sersync)</title>
      <link>http://hwholiday.github.io/2021/nsf/</link>
      <pubDate>Mon, 17 May 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/nsf/</guid>
      <description>简介 本方案 NFS 的高可用方案，客户端为 k8s集群 ，三台文件服务器分别Master和 Slave，使用 keepalived 生成一个虚拟 IP，使用 Sersync 进行 Master 与 Slave 之间文件相互同步，确保高可用。
角色 系统 IP 虚拟IP 172.12.17.200 Client k8s集群 172.12.17.163,172.12.17.164,172.12.17.165 Master centos 7.5 172.12.17.166 Slave centos 7.5 172.12.17.167 查看内核版本 uname -smr 建议升级到最新的长期支持版本 升级内核
安装nfs 在master和slave上面创建共享目录 mkdir -p /fs/nsf-data 在master和slave上安装nfs服务 // 下载nfs yum -y install nfs-utils rpcbind //写入配置（配置要改动需要reload nfs 服务） echo &amp;#39;/fs/nsf-data 172.12.17.163 172.12.17.164 172.12.17.165(rw,sync,all_squash)&amp;#39; &amp;gt;&amp;gt; /etc/exports //开启服务 systemctl start rpcbind &amp;amp;&amp;amp; systemctl start nfs //设置开机自启动 systemctl enable rpcbind &amp;amp;&amp;amp; systemctl enable nfs 在k8s集群里面找个node 测试是否能链接上nfs服务 // 下载nfs yum -y install nfs-utils rpcbind // 挂载目录 mkdir /test-nsf-data // 挂载nfs mount -t nfs 172.</description>
    </item>
    
    <item>
      <title>Golang （V2）分布式ID生成系统，高性能、高可用、易扩展的id生成服务</title>
      <link>http://hwholiday.github.io/2021/gidv2/</link>
      <pubDate>Mon, 01 Mar 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/gidv2/</guid>
      <description>简介 gid 是使用golang开发的生成分布式Id系统，基于数据库号段算法实现
gid V2版本实现了高可用，主从架构，简化了调用逻辑 GRPC 对外服务 性能 id 从内存生成，如果(step)步长设置的足够大,qps可达到千万+ 可用性 id 分配依赖mysql ,当mysql不可用的,如果内存上还有的可以继续分配 特性 全局唯一的int64型id 分配ID只访问内存 可无限横向扩展 依赖mysql恢复服务迅速 依赖etcd实现服务的高可用 &amp;hellip;&amp;hellip; 高可用 server 基于 ETCD Lease 实现了自动抢主，主节点挂了，从节点自动申请为主节点 简化调用逻辑 go get github.com/hwholiday/gid/v2@gidV2 //go mod 内 //github.com/hwholiday/gid/v2 v2.0.6 封住了 client 实现了自动识别服务主节点 只需要实现 client 并调用 GetId(GRPC方法)，无需其他接口，自动创建BizTag，并预加载 package main import ( &amp;#34;context&amp;#34; &amp;#34;fmt&amp;#34; gidSrv &amp;#34;github.com/hwholiday/gid/v2/api&amp;#34; ) func main() { cli, err := InitGrpc([]string{&amp;#34;127.0.0.1:2379&amp;#34;}, 15) c, _ := cli.GetGidGrpcClient() res, err := c.GetId(context.TODO(), &amp;amp;gidSrv.ReqId{ BizTag: &amp;#34;111&amp;#34;, }) fmt.</description>
    </item>
    
    <item>
      <title>安装 Rancher 控制面板到 K8s 集群</title>
      <link>http://hwholiday.github.io/2021/install_rancher_rke2/</link>
      <pubDate>Wed, 03 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/install_rancher_rke2/</guid>
      <description>Helm 一键安装脚本
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash cert-manager 证书 kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.crds.yaml kubectl create namespace cert-manager helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.0.4 kubectl get pods --namespace cert-manager NAME READY STATUS RESTARTS AGE cert-manager-756bb56c5-gl7j9 1/1 Running 0 87s cert-manager-cainjector-86bc6dc648-sv897 1/1 Running 0 87s cert-manager-webhook-66b555bb5-2q996 1/1 Running 0 87s 安装 Rancher kubectl create namespace rancher-system helm repo add rancher-stable https://releases.rancher.com/server-charts/stable helm install rancher rancher-stable/rancher --namespace rancher-system --set hostname=rancher.</description>
    </item>
    
    <item>
      <title>centos7 升级内核</title>
      <link>http://hwholiday.github.io/2021/centos7/</link>
      <pubDate>Tue, 02 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/centos7/</guid>
      <description>查看内核版本 &amp;mdash;这里的内核版本（3.10）和系统架构（64位） uname -smr 更新软件包仓库 yum update 启用Elrepo库 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org 安装 Elrepo 软件库 rpm -Uvh https://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm 列出可用的内核版本 yum list available --disablerepo=&amp;#39;*&amp;#39; --enablerepo=elrepo-kernel kernel-lt表示一个稳定的LTS（长期支持）版本，而kernel-ml表示一个提供短期支持但提供更频繁更新的主线版本 Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * elrepo-kernel: mirror.rackspace.com elrepo-kernel | 3.0 kB 00:00:00 elrepo-kernel/primary_db | 2.0 MB 00:00:00 Available Packages elrepo-release.noarch 7.0-5.el7.elrepo elrepo-kernel kernel-lt.x86_64 5.4.94-1.el7.elrepo elrepo-kernel kernel-lt-devel.x86_64 5.4.94-1.el7.elrepo elrepo-kernel kernel-lt-doc.noarch 5.4.94-1.el7.elrepo elrepo-kernel kernel-lt-headers.x86_64 5.4.94-1.el7.elrepo elrepo-kernel kernel-lt-tools.x86_64 5.4.94-1.el7.elrepo elrepo-kernel kernel-lt-tools-libs.x86_64 5.4.94-1.el7.elrepo elrepo-kernel kernel-lt-tools-libs-devel.x86_64 5.</description>
    </item>
    
    <item>
      <title>安装 k8s 集群 Rancher RKE</title>
      <link>http://hwholiday.github.io/2021/install_rancher_rke1/</link>
      <pubDate>Tue, 02 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/install_rancher_rke1/</guid>
      <description>内核 K8S 1.18开始使用了IPVS 所以4.x以下的内核无法再运行K8S 网络会有BUG 官方推荐4.19LTS及以上的内核
查看内核版本 uname -smr 建议升级到最新的长期支持版本
升级内核 安装 Docker yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install docker-ce-19.03.9 docker-ce-cli-19.03.9 containerd.io 启动 Docker systemctl enable docker systemctl start docker 安装 Rancher RKE 禁用 SELinux /usr/sbin/sestatus -v |grep &amp;#34;SELinux status&amp;#34; #结果为 enabled 为启用状态 vim /etc/selinux/config 将SELINUX=enforcing改为SELINUX=disabled 禁用 swap free -h #total used free shared buff/cache available #Mem: 7.8G 205M 6.9G 8.7M 715M 7.3G #Swap: 5.0G 0B 5.0G #Swap 有值代表启用了swap vim /etc/fstab 使用 # 注释掉有 swap 的一行 关闭防火墙 firewall-cmd --state systemctl stop firewalld.</description>
    </item>
    
    <item>
      <title>Docker-compose 安装 redis-cluster 集群</title>
      <link>http://hwholiday.github.io/2021/docker_redis/</link>
      <pubDate>Mon, 01 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/docker_redis/</guid>
      <description>安装 redis 集群 172.13.3.160 为宿主机IP redis1.conf 同样的配置只需要改prot
port 7001 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.13.3.160 cluster-announce-port 7001 cluster-announce-bus-port 17001 appendonly yes pidfile /var/run/redis_7001.pid redis2.conf 同样的配置只需要改prot
port 7002 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.13.3.160 cluster-announce-port 7002 cluster-announce-bus-port 17002 appendonly yes pidfile /var/run/redis_7002.pid 生成6份
docker-compose.yml version: &amp;#39;3.7&amp;#39; x-image: &amp;amp;redis-image redis:5.0.7 services: redis1: image: *redis-image container_name: redis1 command: [&amp;#34;redis-server&amp;#34;, &amp;#34;/home/redis/cluster/redis.conf&amp;#34;] volumes: - ./redis1.conf:/home/redis/cluster/redis.conf - ./7001/data:/data ports: - 7001:7001 - 17001:17001 redis2: image: *redis-image container_name: redis2 command: [&amp;#34;redis-server&amp;#34;, &amp;#34;/home/redis/cluster/redis.</description>
    </item>
    
    <item>
      <title>通过 istio 部署ws,grpc服务并链接外部redis集群</title>
      <link>http://hwholiday.github.io/2021/istio/</link>
      <pubDate>Tue, 19 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2021/istio/</guid>
      <description>安装 docker https://docs.docker.com/engine/install/ 安装单节点 k8s 环境 sudo docker run --privileged -d --restart=unless-stopped -p 88:80 -p 433:443 rancher/rancher 访问 https://宿主机IP:433 新建集群单结点要把 etcd ， control plane ，worker 都给勾选上 复制命令启动，等待就好了 软件架构 准备镜像 网关：ws 服务 在目录 gateway 下 服务 V1:grpc 服务 在目录 logic_v1 下 服务 V2:grpc 服务 在目录 logic_v2 下 服务 V3:grpc 服务 在目录 logic_v3 下 链接了 Reids 集群 关于k8s和istio的配置文件 在目录 kube 下
├── gateway.yaml 部署 gateway(Deployment[k8s]) 服务和对应的 Service(k8s) ├── logic.yaml 部署 logic(Deployment[k8s]) 服务和对应的 Service(k8s) ├── net-gateway.</description>
    </item>
    
    <item>
      <title>一键安装 K8s 以及在K8s上部署Go服务</title>
      <link>http://hwholiday.github.io/2020/k8s_v1/</link>
      <pubDate>Fri, 13 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/k8s_v1/</guid>
      <description>通过Rancher一键部署k8s服务 地址: https://rancher.com/quick-start/ 命令 sudo docker run --privileged -d --restart=unless-stopped -p 80:80 -p 443:443 rancher/rancher 然后访问你的docker机器的IP地址就可以看到一个叫local的k8s环境，不过不知道是不是我操作不对,我不能使用这个集群 点击添加集群,自定义一通默认到最后给你一个docker命令执行后我们就又得到一个自定义的k8s集群了（弄一个单节点集群的话最后一步把3个都要勾选上） 下载kubectl https://kubernetes.io/docs/tasks/tools/install-kubectl/ 创建一个～/.kube/config文件，把https://k8s集群部署IP/c/local/monitoring 里面的Kubeconfig File按钮里面的文本拷贝进去OK 部署一个 nginx nginx.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: selector: matchLabels: app: nginx replicas: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 运行 &amp;gt;kubectl apply -f nginx.yml deployment.apps/nginx configured &amp;gt;kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deployment-7f4768c97b-69t65 1/1 Running 0 105s //删除 deployment kubectl delete deployment nginx-deployment //删除 pod kubectl.</description>
    </item>
    
    <item>
      <title>领域驱动设计(DDD)战术上一些实践</title>
      <link>http://hwholiday.github.io/2020/go_ddd_v1/</link>
      <pubDate>Mon, 09 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_ddd_v1/</guid>
      <description>领域驱动设计(DDD)战术上一些实践 个人能力有限,如有问题欢迎指导 程序设计谈不上什么最好,无论是面向过程编程,还是面向对象编程，我们都是在追求完美的道路上 不设计和过度设计都会对我们产生一些影响,最合适自己的设计才是最好的设计 DDD（Domain-Driven Design）领域驱动设计 领域驱动设计并不是什么银弹，简单的项目并不需要 DDD，引入后反而增加项目难度 DDD 更加适合解决复杂的业务问题，并不是说DDD设计模式有什么压倒性的优势也不是说它就是完美无缺的只是说它更适合干这事 要不要DDD 在业务刚开始的时候,我们的功能都相对于比较简单，就通过CRUD大法就能满足我们的业务需求， 随着产品的各种需求加入，业务逻辑变的越来越复杂，各个模块相互依赖，修改一个功能时需要花大量的时候去理解当时为什么这些写后，然后再编写代码，甚至开发者自己都不知道这样写会不会影响其他模块，这里我想对测试人员说一句你们辛苦了！
产生这些问题的原因就是在于系统架构不清晰，划分出来的模块内聚度低、高耦合项目到达这个地步的时候我们就可以考虑要不要引入 DDD 来解决一些问题
贫血模型 VS 充血模型 贫血模型: 比如在用户类中我们定义了User的实体，但是操作User的并不是用户类，而是 UserService,这样的设计就是贫血模型简单来说就是（只包含数据，不包含业务逻辑的类） ,就好比我们大学老师说的你有一个车但是不能开只能其他人去开破坏了面向对象的特性，是一种典型的面向过程的编程风格。
充血模型: 我们知道了贫血模型是（只包含数据，不包含业务逻辑的类），那我们把数据和对应的业务逻辑被封装到同一个类中是不是就是充血模型，Bingo 回答正确,你现在不仅拥有了车还可以开这就是面向对象编程风格
面向过程 VS 面向对象 需求把东西全部放到柜子你里面 面向过程: 我们把整个东西放到一个大柜子里面堆在一起。如果修改了那个部分，可以需要修改其他部分，如果放的东西太多还不知道是否会产生一些不可以预知的错误,有可能就会出现祖传bug！ 面向对象: 我们把整个东西分类到一个一个的放在小柜子里面然后再放入一个大柜子，如果要修改也是修改需要修改的那个柜子，不会影响其他柜子 实体 用于个性特征或区分不同对象，判断是不是同一个实体主要依据身份标识（identity），唯一身份标识和可变性（mutability）特征将实体对象和值对象（Value Object）区分开来。
总结下来就是,实体是一个唯一的东西，可以在一段时间内持续变化 值对象 值对象用于度量和描述事务，当我们只关心某个对象的属性时，该对象就可以作为一个值对象
比如在快递单的上的地址，你的地址可以和其他人的地址相同我们只需要关注地址的属性就可以,并不需要给地址一个唯一标识 值对象具有不变性,如果要修改的话直接替换整个值对象就行 聚合 将实体和值对象在一致性边界内组成聚合,不变性和一致性边界即是聚合的设计依据
不变性: 不变性表示的是一个业务规则,该规则应该总是保持一致 一致性边界:单个事务只修改一个聚合实例 领域服务 领域中的服务表示一个无状态的操作,它用于实现特定于某个领域的任务。当某个操作不适合放在聚合、值对象、实体上时,最好的方式便是使用领域服务
在我的理解中上面那一句话就是，需要调用多个模型进行处理的就放在领域服务 eg: 应用服务：获取输入，发送消息给领域层，监听确认消息 领域服务：协调账户模型和邮件进行交互，执行相应的领域行为。 基础服务：按照应用服务的指示发送邮件。 不过在实际开发过程中,最好吧领域对象封装在领域服务中，领域知识限制在领域服务当中 工厂 将创建复杂对象和聚合的职责分配给一个单独的对象,该对象本身并不承担领域模型中的职责,但是依然是领域设计的一部分。 工厂应该提供一个创建对象的接口,该接口封装了所有创建对象的复杂操作过程,同时,它并不需要客户去引用那个实际被创建的对象。对于聚合来说,我们应该一次性地创建整个聚合、并且确保它的不变条件得到满足
资源库 简单理解就是一个持久化机制,在DDD设计中一般将聚合实例放在资源库中
比如用户实体，和地址值对象可以组合成一个聚合实例 探讨项目结构 golang ├── api ├── cmd	项目启动文件 │ └── user	项目名称 │ └── main.</description>
    </item>
    
    <item>
      <title>Golang 文件服务器支持多线程上传下载</title>
      <link>http://hwholiday.github.io/2020/file_storage/</link>
      <pubDate>Mon, 17 Aug 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/file_storage/</guid>
      <description>简介 参照 Telegram Uploading and Downloading Files
写的文件服务器（断点续传，分片上传下载,自动生成缩略图等）
申请上传文件 请求
文件名 文件大小 （字节） 文件扩展名 是否需要缩略图 文件MD5 返回
文件id 上传过期时间，到时间未上传完，自动清理 取消上传文件 请求
文件ID 返回
成功 or 失败 获取文件信息 请求
文件ID 返回
文件信息 上传文件 请求
文件ID 文件分片ID file_part 文件MD5 文件内容 part_size 是否是最后一片 所有分片必须具有相同的大小（part_size），并且必须满足以下条件：part_size % 1024 = 0 （可被1KB整除524288 % part_size = 0（512KB必须可以被part_size整除）如果最后一部分的大小小于part_size，则不必满足这些条件。每个部分都应具有序列号file_part，其值的范围为1到3000。 服务器处理
每个分片接收完毕的时候都检查下服务器接受文件MD5是否相等 检查该分片是否已经上传，是则不做任何处理,不是则把文件存入内存，再将已上传文件大小累加 判断已上传文件大小是否等于文件总大小 （标记文件已经完成） 按照文件分片顺序拼接文件 检查文件MD5是否相等，上传到文件服务器,文件上传结束 返回
成功 or 失败 下载文件 请求
文件ID limit 可被1024整除 offset 可被1024整除 offset 不能超过 1048576（1 MB） 服务器处理</description>
    </item>
    
    <item>
      <title>Golang 分布式ID生成系统，高性能、高可用、易扩展的id生成服务</title>
      <link>http://hwholiday.github.io/2020/gid/</link>
      <pubDate>Wed, 10 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/gid/</guid>
      <description>简介 gid 是使用golang开发的生成分布式Id系统，基于数据库号段算法实现
性能 id 从内存生成，如果(step)步长设置的足够大,qps可达到千万+ 可用性 id 分配依赖mysql ,当mysql不可用的,如果内存上还有的可以继续分配 特性 全局唯一的int64型id 分配ID只访问内存 可无限横向扩展 依赖mysql恢复服务迅速
&amp;hellip;&amp;hellip; 安装 初始化 mysql create database gid; use gid; create table segments ( biz_tag varchar(128) not null, max_id bigint null, step int null, remark varchar(200) null, create_time bigint null, update_time bigint null, constraint segments_pk primary key (biz_tag) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_bin; INSERT INTO segments(`biz_tag`, `max_id`, `step`, `remark`, `create_time`, `update_time`) VALUES (&amp;#39;test&amp;#39;, 0, 100000, &amp;#39;test&amp;#39;, 1591706686, 1591706686); 编译运行项目 git clone https://github.</description>
    </item>
    
    <item>
      <title>Docker 安装(mysql,redis,redis 集群，etcd,zookeeper,kafka,nginx,Jaeger)持续更新</title>
      <link>http://hwholiday.github.io/2020/docker_install_development_tool/</link>
      <pubDate>Mon, 18 May 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/docker_install_development_tool/</guid>
      <description>$PWD 获取当前路径 安装 mysql docker run --name mysql -p 3306:3306 -v $PWD/docker_data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=设置密码 -d mysql:latest 安装 redis docker run --name redis -p 6379:6379 -v $PWD/docker_data/redis:/data -d redis redis-server --appendonly yes --requirepass &amp;#34;设置密码&amp;#34; 安装 单点etcd docker run -d \ -p 2379:2379 \ -p 2380:2380 \ --mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \ --name etcd-gcr-v3.4.14 \ gcr.io/etcd-development/etcd:v3.4.14 \ /usr/local/bin/etcd \ --name s1 \ --data-dir /etcd-data \ --listen-client-urls http://0.0.0.0:2379 \ --advertise-client-urls http://0.0.0.0:2379 \ --listen-peer-urls http://0.0.0.0:2380 \ --initial-advertise-peer-urls http://0.</description>
    </item>
    
    <item>
      <title>GitLab CI 实现 Golang 自动构建为 Docker 镜像 </title>
      <link>http://hwholiday.github.io/2020/gitlab_ci_docker/</link>
      <pubDate>Mon, 30 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/gitlab_ci_docker/</guid>
      <description>实现目标 提交代码自动构建,自动打包为docker镜像 前期准备 Makefile 学习并使用 MakeFile .gitlab-ci.yml .gitlab-ci.yml介绍 安装 gitlab_runner (docker) 下载地址 docker pull gitlab/gitlab-runner #/run/docker.sock 容器中可以执行宿主机的Docker命令 docker run -d --name gitlab-runner --restart always -v /srv/runner/config:/etc/gitlab-runner -v /run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner 工程目录 目录 ├── buildDockerImage.sh ├── Dockerfile ├── main.go ├── Makefile .gitlab-ci.yml 内容 # 所有任务基于这个镜像 image: golang:1.14.0 # 在每个任务执行前运行 before_script: - export VERSION=`echo ${CI_COMMIT_TAG} | awk -F&amp;#34;_&amp;#34; &amp;#39;{print $1}&amp;#39;` # 安装 docker，由于需要在容器里面使用宿主的docker命令，这里就需要安装一个docker的可执行文件，然后在启动容器的时候，将宿主的 docker.sock 文件挂载到容器内的同样位置。 - curl -O https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz &amp;amp;&amp;amp; tar zxvf docker-latest.tgz &amp;amp;&amp;amp; cp docker/docker /usr/local/bin/ &amp;amp;&amp;amp; rm -rf docker docker-latest.</description>
    </item>
    
    <item>
      <title>GitLab CI 实现 Golang 自动构建</title>
      <link>http://hwholiday.github.io/2020/gitlab_ci/</link>
      <pubDate>Fri, 27 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/gitlab_ci/</guid>
      <description>实现目标 提交代码自动构建,并把文件放到指定目录 （也可以上传到运维服务器，这里看自己选择） 前期准备 Makefile 学习并使用 MakeFile .gitlab-ci.yml .gitlab-ci.yml介绍 安装 gitlab_runner (二进制安装) 下载地址 sudo chmod +x gitlab-runner sudo ./gitlab-runner install --user=当前用户 --working-directory=/home/当前用户/gitlabRunner sudo ./gitlab-runner start 工程目录 目录 ├── .gitlab-ci.yml ├── main.go └── Makefile .gitlab-ci.yml 内容 # 在每个任务执行前运行 before_script: - export VERSION=`echo ${CI_COMMIT_TAG} | awk -F&amp;#34;_&amp;#34; &amp;#39;{print $1}&amp;#39;` stages: - test - build # 定义 job test: stage: test tags: - test script: - echo &amp;#34;我是 tast 任务&amp;#34; - echo &amp;#34;git 提交的 tag&amp;#34; - echo ${CI_COMMIT_TAG} - echo ${CI_PROJECT_NAME} - echo ${VERSION} - echo $GOPATH only: - tags # 定义 job build: stage: build tags: - test script: - echo &amp;#34;开始构建程序&amp;#34; - make pack ENV=&amp;#34;prod&amp;#34; VERSION=${VERSION} - pwd - if [ !</description>
    </item>
    
    <item>
      <title>学习并使用 MakeFile</title>
      <link>http://hwholiday.github.io/2020/makefile/</link>
      <pubDate>Thu, 26 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/makefile/</guid>
      <description>什么是MakeFile Makefile文件的作用是告诉make工具需要如何去编译和链接程序，在需要编译工程时只需要一个make命令即可，避免了每次编译都要重新输入完整命令的麻烦，大大提高了效率，也减少了出错率。
目录 ├── main.go ├── Makefile └── README.md Makefile 例子 #环境变量 export VERSION=1.0.0 export ENV=prod export PROJECT=test #变量 PWD=$(shell pwd) OUT_DIR=$(PWD)/cmd OUT_NAME=$(PROJECT)_$(VERSION) OUT_FILE=$(OUT_DIR)/$(OUT_NAME) MAIN_FILE=main.go PACK_FILE=$(OUT_NAME).tar.gz build: @echo &amp;#34;移除老项目&amp;#34; @ rm -rf $(OUT_DIR)/* @go build -o $(OUT_FILE) $(MAIN_FILE) @echo &amp;#34;构建项目成功 : &amp;#34; $(OUT_NAME) run:build @# 执行pack前先执行一次build @echo &amp;#34;运行项目&amp;#34; @$(OUT_FILE) pack:build @# 执行pack前先执行一次build tar -czvf $(PACK_FILE) -C $(OUT_DIR) . @echo &amp;#34;打包结束 :&amp;#34; 构建命令 # 带上环境变量 make build ENV=&amp;#34;prod&amp;#34; VERSION=&amp;#34;2.0.0&amp;#34; PROJECT=&amp;#34;test_makefile&amp;#34; 打包命令 make pack 运行命令 make run </description>
    </item>
    
    <item>
      <title>golang 解决 protobuf 因为 XXX 插入数据库报错的情况</title>
      <link>http://hwholiday.github.io/2020/go_protoc_gen_go/</link>
      <pubDate>Tue, 17 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_protoc_gen_go/</guid>
      <description>起因 在一个老项目里面直接用的 protobuf 生成的结构体与数据库交互 在 protoc 2 生成的 protobuf 没有 XXX 这些东西生成故能正常运行 因为版本升级到 protoc 3 后编译的 protobuf 就不能正常运行了，会出现数据库找不到 XXX_ 这些字段的情况 解决方案 把每张表单独生成 struct 放在 models 层里面，这样的话老服务改动太大我肯定是不能接受的 因为我们使用的 orm ,在xorm 中如果 struct 某个字段不需要映射的话就可以用 xorm:&amp;quot;-&amp;quot; gorm 也可以这样操作 gorm:&amp;quot;-&amp;quot; 那我们就可以在 XXX_ 这些字段后面的 tag 中添加忽略，就可以实现我们的目表 开始搞事情 获取代码 go get github.com/golang/protobuf/protoc-gen-go 修改代码 在路径 github.com/golang/protobuf/protoc-gen-go/generator/generator.go 下找到 generateInternalStructFields 方法 在XXX_ 后添加 xorm:&amp;quot;-&amp;quot; or gorm:&amp;quot;-&amp;quot; // generateInternalStructFields just adds the XXX_&amp;lt;something&amp;gt; fields to the message struct. func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) { g.</description>
    </item>
    
    <item>
      <title>golang 通过 Redis GEO 实现 LBS 功能</title>
      <link>http://hwholiday.github.io/2020/redis_geo/</link>
      <pubDate>Tue, 17 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/redis_geo/</guid>
      <description>LBS 基于位置的服务（Location Based Services，LBS），是利用各类型的定位技术来获取定位设备当前的所在位置，通过移动互联网向定位设备提供信息资源和基础服务。LBS首先读者可利用定位技术确定自身的空间位置，随后读者便可通过移动互联网来获取与位置相关资源和信息。LBS服务中融合了移动通讯、互联网络、空间定位、位置信息、大数据等多种信息技术，利用移动互联网络服务平台进行数据更新和交互，使用户可以通过空间定位来获取相应的服务。 redis 中关于 GEO 的方法 geoadd：增加某个位置的坐标。 geopos：获取某个位置的坐标。 geohash：获取某个位置的geohash值。 geodist：获取两个位置的距离。 georadius：根据给定位置坐标获取指定范围内的位置集合。 georadiusbymember：根据给定位置获取指定范围内的位置集合。 geoadd 使用方法 res, err := GlobalClient.GeoAdd(&amp;#34;geo_hash_test&amp;#34;, &amp;amp;redis.GeoLocation{ Name: &amp;#34;天府广场&amp;#34;, Longitude: 104.072833, Latitude: 30.663422, }, &amp;amp;redis.GeoLocation{ Name: &amp;#34;四川大剧院&amp;#34;, Longitude: 104.074378, Latitude: 30.664804, }, &amp;amp;redis.GeoLocation{ Name: &amp;#34;新华文轩&amp;#34;, Longitude: 104.070084, Latitude: 30.664649, }, &amp;amp;redis.GeoLocation{ Name: &amp;#34;手工茶&amp;#34;, Longitude: 104.072402, Latitude: 30.664121, }, &amp;amp;redis.GeoLocation{ Name: &amp;#34;宽窄巷子&amp;#34;, Longitude: 104.059826, Latitude: 30.669883, }, &amp;amp;redis.GeoLocation{ Name: &amp;#34;奶茶&amp;#34;, Longitude: 104.06085, Latitude: 30.670054, }, &amp;amp;redis.GeoLocation{ Name: &amp;#34;钓鱼台&amp;#34;, Longitude: 104.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 日志分析管理 （ELK &#43; Filebeat）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v12/</link>
      <pubDate>Fri, 13 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v12/</guid>
      <description>ELK ELK 不是一款软件，而是 Elasticsearch、Logstash 和 Kibana 三种软件产品的首字母缩写 Elasticsearch：分布式搜索和分析引擎，具有高可伸缩、高可靠和易管理等特点 Logstash：数据收集引擎,它支持动态的从各种数据源搜集数据并处理数据 Kibana：数据分析，可视化平台 Filebeat Filebeat 是一个轻量型的服务对服务器压力比较小，用于采集数据，并上报到Logstash或Elasticsearch Beats Packetbeat =&amp;gt; 搜集网络流量数据 Topbeat =&amp;gt; 搜集系统、进程和文件系统级别的 CPU 和内存使用情况等数据 Filebeat =&amp;gt; 搜集文件数据 Winlogbeat =&amp;gt; 搜集 Windows 事件日志数据 Metricbeat =&amp;gt; Ship and analyze metrics. Heartbeat =&amp;gt; Ping your Infrastructure. Auditbeat =&amp;gt; Send audit data to Elasticsearch. Functionbeat =&amp;gt; Ship cloud data with serverless infrastructure. Journalbeat =&amp;gt; Analyze Journald logs. 架构 Filebeat -&amp;gt; -&amp;gt; Filebeat -&amp;gt; -&amp;gt; -&amp;gt; -&amp;gt; Logstash -&amp;gt; Elasticsearch -&amp;gt; Kibana -&amp;gt; Filebeat -&amp;gt; 安装 elasticsearch 下载 地址</description>
    </item>
    
    <item>
      <title>golang 消息推送系统</title>
      <link>http://hwholiday.github.io/2020/go_push/</link>
      <pubDate>Mon, 09 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_push/</guid>
      <description>Golang 消息推送系统 使用 websocket 协议，实现全局推送，和分房间推送,实现用户加入房间，退出房间
gateway 长连接网关服务器，管理全部的链接，以及房间等相关操作
logic 逻辑服务器 管理发送全局推送，单个房间推送，加入房间，离开房间等相关操作
代码目录详情
├── gateway // 长连接网关服务器 │ ├── push_job.go // 分发任务 │ ├── room.go // 房间，可作为某一类型的推送管理中心 │ ├── room_manage.go // 房间管理 │ ├── ws_conn.go // 简单封装的websocket方法 │ ├── ws_handle.go // 处理websocket协议方法 │ └── ws_server.go // websocket服务 ├── logic //逻辑服务器 │ ├── http_handle.go // 推送，房间相关 │ └── http_server.go // http服务 └── main.go websocket相关 定义WsConnection结构体 type WsConnection struct { mu sync.Mutex connId string // 链接ID ws *websocket.</description>
    </item>
    
    <item>
      <title>golang 插上docker_compose的翅膀</title>
      <link>http://hwholiday.github.io/2020/golang_for_docker_compose/</link>
      <pubDate>Sun, 19 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/golang_for_docker_compose/</guid>
      <description>为你的golang程序插上docker_compose的翅膀 构建一个简单的http服务,使用redis的get，set方法 使用docker_compose构建一个agent服务，redis服务并使用networks 服务端代码 var rd *redis.Client func main() { InitRedis() http.HandleFunc(&amp;#34;/&amp;#34;, func(writer http.ResponseWriter, request *http.Request) { _, _ = fmt.Fprintf(writer, &amp;#34;hello world&amp;#34;) }) http.HandleFunc(&amp;#34;/set&amp;#34;, func(writer http.ResponseWriter, request *http.Request) { _ = request.ParseForm() key := request.Form.Get(&amp;#34;key&amp;#34;) val := request.Form.Get(&amp;#34;val&amp;#34;) fmt.Println(&amp;#34;set &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;#34;, &amp;#34;key&amp;#34;, key, &amp;#34;val&amp;#34;, val) if key == &amp;#34;&amp;#34; { _, _ = writer.Write([]byte(&amp;#34;参数错误&amp;#34;)) return } if err := rd.Set(key, val, time.Second*60).Err(); err != nil { _, _ = writer.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 系列文章归档</title>
      <link>http://hwholiday.github.io/2020/go_kit_11/</link>
      <pubDate>Tue, 14 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_11/</guid>
      <description>go-kit 微服务 系列文章归档 go-kit 里面核心的东西有三层分别是：Transport、Endpoint、Service Transport 层主要负责与网络层相关逻辑 Endpoint 层主要负责请求数据与返回数据格式的转换，以及公用中间件逻辑 Service 层业务逻辑 go-kit 更像是一个微服务的工具集，而不是一个完整的框架，里面包含了限流，日志，服务注册与发现，熔断，服务监控，链路追踪等相关工具方法 归档 go-kit 微服务 基础使用 （HTTP）
go-kit 微服务 添加日志（user/zap ,并为每个请求添加UUID）
go-kit 微服务 身份认证 （JWT）
go-kit 微服务 限流 （uber/ratelimit 和 golang/rate 实现）
go-kit 微服务 使用GRPC（并为每个请求添加UUID）
go-kit 微服务 服务注册与发现（etcd实现）
go-kit 微服务 服务监控（prometheus 实现）
go-kit 微服务 服务熔断（hystrix-go 实现）
go-kit 微服务 服务链路追踪（jaeger 实现）(1)
go-kit 微服务 服务链路追踪（jaeger 实现）(2)
go-kit 微服务 日志分析管理 （ELK + Filebeat）
完整代码示例 (go-kit微服务) 联系 QQ: 3355168235 </description>
    </item>
    
    <item>
      <title>go-kit 微服务 服务链路追踪（jaeger 实现）（2）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v10/</link>
      <pubDate>Mon, 13 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v10/</guid>
      <description>go-kit 微服务 服务链路追踪（jaeger 实现）（2） 《go-kit 微服务 服务链路追踪（jaeger 实现）（1）》 中实现了grpc服务端，客户端的链路追踪 在以前的1.0版本的基础上我们加上对service,endpoint层的链路追踪 endpoint层 中间件 func NewTracerEndpointMiddleware(tracer opentracing.Tracer) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { span, ctxContext := opentracing.StartSpanFromContextWithTracer(ctx, tracer, &amp;#34;endpoint&amp;#34;, opentracing.Tag{ Key: string(ext.Component), Value: &amp;#34;NewTracerEndpointMiddleware&amp;#34;, }) defer span.Finish() return next(ctxContext, request) } } } 添加到登录EndPoint中 func NewEndPointServer(svc Service, limit *rate.Limiter,tracer opentracing.Tracer) EndPointServer { var loginEndPoint endpoint.Endpoint { loginEndPoint = MakeLoginEndPoint(svc) loginEndPoint = NewGolangRateAllowMiddleware(limit)(loginEndPoint) loginEndPoint = NewTracerEndpointMiddleware(tracer)(loginEndPoint) } return EndPointServer{LoginEndPoint: loginEndPoint} } service层修改 中间件 type tracerMiddlewareServer struct { next Service tracer opentracing.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 服务熔断（hystrix-go 实现）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v8/</link>
      <pubDate>Fri, 10 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v8/</guid>
      <description>go-kit 微服务 服务熔断（hystrix-go 实现） 对客户端请求login方法添加熔断 Hystrix 在微服务架构中，每个服务都是相互关联的，比如我们下单服务和扣钱服务是分开的，现在扣钱服务出现的bug不能正常服务 Hystrix可以让我们在在微服务架构中对服务间的调用进行控制，加入一些调用延迟或者服务降级的容错机制。 Hystrix的设计原则 对依赖服务调用时出现的调用延迟和调用失败进行控制和容错保护 在复杂的分布式系统中，阻止某一个依赖服务的故障在整个系统中蔓延 提供fail-fast（快速失败）和快速恢复的支持 提供fallback优雅降级的支持 支持近实时的监控、报警以及运维操作 编写Hystrix类 import ( &amp;#34;errors&amp;#34; &amp;#34;github.com/afex/hystrix-go/hystrix&amp;#34; &amp;#34;sync&amp;#34; ) var config = hystrix.CommandConfig{ Timeout: 5000, //执行command的超时时间(毫秒) MaxConcurrentRequests: 8, //command的最大并发量 SleepWindow: 1000, //过多长时间，熔断器再次检测是否开启。单位毫秒 ErrorPercentThreshold: 30, //错误率 请求数量大于等于RequestVolumeThreshold并且错误率到达这个百分比后就会启动 RequestVolumeThreshold: 5, //请求阈值(一个统计窗口10秒内请求数量) 熔断器是否打开首先要满足这个条件；这里的设置表示至少有5个请求才进行ErrorPercentThreshold错误百分比计算 } type runFunc func() error type Hystrix struct { loadMap *sync.Map //储存每个调用函数对应的 Hystrix fallback string //降级信息 } func NewHystrix(msg string) *Hystrix { return &amp;amp;Hystrix{ loadMap: new(sync.Map), fallback: msg, } } func (s *Hystrix) Run(name string, run runFunc) error { if _, ok := s.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 服务链路追踪（jaeger 实现）（1）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v9/</link>
      <pubDate>Fri, 10 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v9/</guid>
      <description>go-kit 微服务 服务链路追踪（jaeger 实现）（1） 对grpc调用添加链路追踪 部署 jaeger 生产环境部署
Docker Hub 中有官方打好的 Image https://hub.docker.com/u/jaegertracing/ 本地测试
可以直接用 Jaeger 的 all-in-one
```base sudo docker pull jaegertracing/all-in-one sudo docker run -d -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p5775:5775/udp -p6831:6831/udp -p6832:6832/udp -p5778:5778 -p16686:16686 -p14268:14268 -p9411:9411 jaegertracing/all-in-one:latest ```
能正常访问 http://127.0.0.1:16686/ 则安装成功
编写jaeger 关于grpc代码 初始化客户端 func NewJaegerTracer(serviceName string) (tracer opentracing.Tracer, closer io.Closer, err error) { cfg := &amp;amp;jaegerConfig.Configuration{ Sampler: &amp;amp;jaegerConfig.SamplerConfig{ Type: &amp;#34;const&amp;#34;, //固定采样 Param: 1, //1=全采样、0=不采样 }, Reporter: &amp;amp;jaegerConfig.ReporterConfig{ LogSpans: true, LocalAgentHostPort: &amp;#34;127.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 服务监控（prometheus 实现）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v7/</link>
      <pubDate>Thu, 09 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v7/</guid>
      <description>go-kit 微服务 服务监控（prometheus 实现） 实现对登录方法的请求次数,与请求耗时进行监控 prometheus 相关介绍使用请看文章《docker安装prometheus（普罗米修斯）》 Prometheus 的四种数据类型 Counter(计数器) 它是一个只能递增的数值,重启进程后会被重置 (例如记录：请求次数、任务完成数、错误发生次数) Gauge(测量器) 它表示一个既可以递增, 又可以递减的值,重启进程后，会被重置 (例如 温度变化、CPU,内存,网络使用变化) Histogram(柱状图) 每个采样点进行统计，打到各个分类值中(bucket) 对每个采样点值累计和(sum) 对采样点的次数累计和(count) 例如：请求耗时、响应大小。 Summary 类似histogram柱状图，summary是采样点分位图统计 有一个quantiles的功能，可以按%比划分跟踪的结果。例如：quantile取值0.85，表示取采样值里面的85%数据。 例如：请求耗时、响应大小。 具体区别可看文档histogram和summaries 定义统计服务中间件 创建metricsMiddlewareServer结构体 type metricsMiddlewareServer struct { next Service counter metrics.Counter histogram metrics.Histogram } 创建NewMetricsMiddlewareServer把统计对象嵌入中间件（其实就是对Service添加了一层装饰） func NewMetricsMiddlewareServer(counter metrics.Counter, histogram metrics.Histogram) NewMiddlewareServer { return func(service Service) Service { return metricsMiddlewareServer{ next: service, counter: counter, histogram: histogram, } } } 让metricsMiddlewareServer实现Service中的全部方法 func (l metricsMiddlewareServer) Login(ctx context.Context, in *pb.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 服务注册与发现（etcd实现）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v6/</link>
      <pubDate>Wed, 08 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v6/</guid>
      <description>go-kit 微服务 服务注册与发现 (etcd 实现 ) etcd 相关介绍使用请看文章《Golang etcd 服务发现与负载均衡》 对服务注册，发现，与负载均衡提供了思路 简介 通过grpc实现一个用户中心实现简单的鉴权中心并返回用户token 上篇文章《go-kit 微服务 使用Grpc（并传递请求ID）》，我们已经实现了一个grpc的服务 我们这次主要是添加基于 go-kit 服务注册,发现,负载均衡 服务注册 使用go-kit初始化一个etcdV3客户端 options := etcdv3.ClientOptions{ DialTimeout: ttl, DialKeepAlive: ttl, } etcdClient, err := etcdv3.NewClient(context.Background(), etcdAddrs, options) if err != nil { utils.GetLogger().Error(&amp;#34;[user_agent] NewClient&amp;#34;, zap.Error(err)) return } Registar := etcdv3.NewRegistrar(etcdClient, etcdv3.Service{ Key: fmt.Sprintf(&amp;#34;%s/%s&amp;#34;,serName,grpcAddr), Value: grpcAddr, }, log.NewNopLogger()) 将节点注册到服务器 Registar.Register() 将节点注销 Registar.Deregister() 服务发现与负载均衡 在基于《go-kit 微服务 使用Grpc（并传递请求ID）》 我们已经实现了一个grpc客户端，现在我们只需要为这个客户端添加服务发现，与负载均衡等相关操作
创建一个UserAgent结构体，里面包含一个 etcdv3.Instancer 对象和一个 log.Logger对象
type UserAgent struct { instancerm *etcdv3.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 使用GRPC（并为每个请求添加UUID） </title>
      <link>http://hwholiday.github.io/2020/go_kit_v5/</link>
      <pubDate>Tue, 07 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v5/</guid>
      <description>go-kit 微服务 使用Grpc（并传递请求ID） grpc gRPC是一个高性能、通用的开源RPC框架，其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计，基于ProtoBuf(Protocol Buffers)序列化协议开发 grpc使用 案例 简介 通过grpc实现一个用户中心实现简单的鉴权中心并返回用户token 上篇文章《go-kit 微服务 身份认证（JWT）》已经实现的一个http的鉴权中心，所以我们只需要改变transport层逻辑 编写ProtoBuf //service.proto syntax = &amp;#34;proto3&amp;#34;; package pb; import &amp;#34;user.proto&amp;#34;; service User { rpc RpcUserLogin (Login) returns (LoginAck) { } } //user.proto message Login { string Account = 1; string Password = 2; } message LoginAck { string Token = 1; } 编译ProtoBuf protoc --go_out=plugins=grpc:. *.proto transport层修改 定义grpcServer结构体 type grpcServer struct { login grpctransport.Handler } 实现RpcUserLogin接口 func (s *grpcServer) RpcUserLogin(ctx context.</description>
    </item>
    
    <item>
      <title>Golang etcd 服务发现与负载均衡</title>
      <link>http://hwholiday.github.io/2020/etcd_registry_selector/</link>
      <pubDate>Mon, 06 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/etcd_registry_selector/</guid>
      <description>Golang etcd 服务发现与负载均衡 注册： 同一服务下的所有节点注册到相同目录下，节点启动后将自己的信息注册到所属服务的目录中。 健康： 服务节点定时发送心跳，注册到服务目录中的信息设置一个较短的 TTL，运行正常的服务节点每隔一段时间会去更新信息的 TTL。 发现： 通过名称能查询到服务提供外部访问的 IP 和端口号。比如网关代理服务时能够及时的发现服务中新增节点、丢弃不可用的服务节点，同时各个服务间也能感知对方的存在。 etcd 是由CoreOS开发，用于可靠地存储集群的配置数据的一种持久性，轻量型的，分布式的键-值数据存储组件。该组件可表示在任何给定时间点处的集群的整体状态。其他组件在注意到存储的变化之后，会变成相应的状态。采用raft协议作为一致性算法，etcd基于Go语言实现。 服务注册 下载依赖 go get go.etcd.io/etcd/clientv3 创建注册接口 type Registry interface { RegistryNode(node PutNode) error UnRegistry() } 具体代码实现 var prefix = &amp;#34;/registry/server/&amp;#34; type Registry interface { RegistryNode(node PutNode) error UnRegistry() } type registryServer struct { cli *clientv3.Client stop chan bool isRegistry bool options Options leaseID clientv3.LeaseID } type PutNode struct { Addr string `json:&amp;#34;addr&amp;#34;` } type Node struct { Id uint32 `json:&amp;#34;id&amp;#34;` Addr string `json:&amp;#34;addr&amp;#34;` } type Options struct { name string ttl int64 config clientv3.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 限流 （uber/ratelimit 和 golang/rate 实现）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v4/</link>
      <pubDate>Sat, 04 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v4/</guid>
      <description>go-kit 微服务 限流 (uber/ratelimit 和 golang/rate 实现) golang/rate 简介（golang.org/x/time/rate） golang 标准库中就自带的限流算法 该限流器是基于 Token Bucket(令牌桶) 实现的 //第一个参数是 r Limit。代表每秒可以向 Token 桶中产生多少 token //第二个参数是 b int。b 代表 Token 桶的容量大小 golangLimit := rate.NewLimiter(10, 1) //golangLimit 其令牌桶大小为 1, 以每秒 10 个 Token 的速率向桶中放置 Token。 Wait/WaitN Wait 实际上就是 WaitN(ctx,1) 当使用 Wait 方法时，如果令牌桶内Token（大于or等于 N）直接返回，如果当时令牌桶内 Token 不足(小于 N)，那么 Wait 方法将会阻塞，直到能从令牌桶内获得 Token Allow/AllowN Allow 实际上就是 AllowN(time.Now(),1)。 当使用使用 AllowN 方法时，截止到time.Now()这一时刻(time可以自己传入)令牌桶中数目必须（大于or等于 N），满足则返回正确，同时从令牌桶中消费 N 个 Token 应用场景请求速度太快就直接丢掉一些请求 Reserve/ReserveN Reserve 相当于 ReserveN(time.Now(), 1) 当使用使用 ReserveN 方法时，不管能不能从令牌桶内获取到Token都会返回一个Reservation对象 Reservation对象的 Ok() 方法返回了令牌桶是否可以在最大等待时间内提供请求的令牌数量，如果OK为false，则Delay()返回InfDuration Reservation对象的 Delay() 方法返回了需要等待的时间，如果时间为0则不需要等待 如果不想等待就调用 Reservation对象的 Cancel() uber/ratelimit 简介（go.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 身份认证 （JWT）</title>
      <link>http://hwholiday.github.io/2020/go_kit_v3/</link>
      <pubDate>Fri, 03 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/go_kit_v3/</guid>
      <description>go-kit 微服务 身份认证（JWT） Jwt官网介绍 JSON Web令牌（JWT）是一个开放标准（RFC 7519），它定义了一种紧凑且自包含的方式，用于在各方之间作为JSON对象安全地传输信息。由于此信息是经过数字签名的，因此可以被验证和信任。可以使用秘密（使用HMAC算法）或使用RSA或ECDSA的公钥/私钥对对JWT进行签名。 简介 在上篇文章中go-kit 微服务 添加日志（并为每个请求添加UUID）中我们学会了如何使用中间件 这次我们在程序中加入jwt身份验证 使sum接口需要传入token才能实现访问 开始 下载依赖
jwt库 go get github.com/dgrijalva/jwt-go jwt编写 jwtSecret 生成token的密钥 CreateJwtToken 生成token ParseToken 解析token var jwtSecret = []byte(&amp;#34;jwtSecret_v3&amp;#34;) const JWT_CONTEXT_KEY = &amp;#34;jwt_context_key&amp;#34; type Token struct { Name string DcId int jwt.StandardClaims } func CreateJwtToken(name string, dcId int) (string, error) { var token Token token.StandardClaims = jwt.StandardClaims{ Audience: &amp;#34;&amp;#34;, // 受众群体 ExpiresAt: time.Now().Add(30 * time.Second).Unix(), // 到期时间 Id: &amp;#34;&amp;#34;, // 编号 IssuedAt: time.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 添加日志（user/zap ,并为每个请求添加UUID） </title>
      <link>http://hwholiday.github.io/2020/git_kit_v2/</link>
      <pubDate>Thu, 02 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2020/git_kit_v2/</guid>
      <description>go-kit 微服务 添加日志（并为每个请求添加UUID） 通过日志我们可以了解到我们关心的数据在软件内的执行情况，同时出问题时可以分析与定位系统故障 用户的每个请求都添加请求ID(我使用的UUID)，我们可以更好的了解到每个请求的执行过程，更利于分析与定位问题 简介 在上篇文章中go-kit 微服务 基础使用（HTTP）我们实现了使用go-kit 构建一个简单的加法的http服务 这篇文章中我们将实现使用go-kit中间件机制为其增加日志功能 开始 下载依赖
uuid库 go get github.com/satori/go. 日志库使用的是以前文章 Golang 高性能日志库 zap 封装工具类的日志工具 Server层修改 在Server层文件夹中创建middleware.go文件 定义服务中间件 type NewMiddlewareServer func(Service) Service 创建logMiddlewareServer结构体 type logMiddlewareServer struct { logger *zap.Logger next Service } 创建NewLogMiddlewareServer把日志记录对象嵌入中间件（其实就是对Service添加了一层装饰） func NewLogMiddlewareServer(log *zap.Logger) NewMiddlewareServer { return func(service Service) Service { return logMiddlewareServer{ logger: log, next: service, } } } 让logMiddlewareServer实现Service中的全部方法 func (l logMiddlewareServer) TestAdd(ctx context.Context, in Add) (out AddAck) { defer func() { l.</description>
    </item>
    
    <item>
      <title>go-kit 微服务 基础使用 （HTTP）</title>
      <link>http://hwholiday.github.io/2019/go_kit_v1/</link>
      <pubDate>Mon, 30 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/go_kit_v1/</guid>
      <description>使用go-kit 构建一个简单的加法，对方暴露一个请求接口 URL格式为：http://127.0.0.1:8888/sum?a=参数&amp;amp;b=参数 请求方法为 GET 开始 go-kit 安装：go get github.com/go-kit/kit 创建Service 定义接口 type Service interface { TestAdd(ctx context.Context,in Add) AddAck } 定义model type Add struct { A int `json:&amp;#34;a&amp;#34;` B int `json:&amp;#34;b&amp;#34;` } type AddAck struct { Res int `json:&amp;#34;res&amp;#34;` } 创建结构体baseServer来实现Service接口 type baseServer struct { } func NewService() Service { return &amp;amp;baseServer{} } func (s baseServer) TestAdd(ctx context.Context,in Add) AddAck { return AddAck{Res:in.A+in.B} } 创建Endpoint 把Service的方法封装到Endpoint中
把Service中的TestAdd，转换成endpoint.Endpoint func MakeAddEndPoint(s v1_service.</description>
    </item>
    
    <item>
      <title>trie_tree原理及Golang实现(模糊查询)</title>
      <link>http://hwholiday.github.io/2019/trie_tree/</link>
      <pubDate>Fri, 27 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/trie_tree/</guid>
      <description>Trie Tree 在计算机科学中，trie，又称前缀树或字典树，是一种有序树，用于保存关联数组，其中的键通常是字符串。与二叉查找树不同，键不是直接保存在节点中，而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀，也就是这个节点对应的字符串，而根节点对应空字符串。一般情况下，不是所有的节点都有对应的值，只有叶子节点和部分内部节点所对应的键才有相关的值。
实现 type Trie struct { node map[rune]*Trie val string isLast bool } func Constructor() Trie { return Trie{node: make(map[rune]*Trie, 26), isLast: false} } func (t *Trie) Insert(word string) { for _, v := range word { if t.node[v] == nil { //没找到该节点 vt := &amp;amp;Trie{node: make(map[rune]*Trie, 26), isLast: false} t.node[v] = vt } t = t.node[v] //找到节点，跳到下一个节点 } t.val = word t.isLast = true } func (t *Trie) Search(word string) bool { for _, v := range word { if t.</description>
    </item>
    
    <item>
      <title>Golang 基于interface 实现中间件(middleware)</title>
      <link>http://hwholiday.github.io/2019/middleware/</link>
      <pubDate>Wed, 25 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/middleware/</guid>
      <description>背景 我们在开发接口时会写大量的interface Service,但是有时候需要提供一个功能对已经写好的接口提供一个中间件进行业务处理
我们已经写好的接口 type Service interface { Add(a, b int) int } type baseServer struct{} func NewBaseServer() Service { return baseServer{} } func (s baseServer) Add(a, b int) int { return a + b } 添加中间件1 type logServer struct { next Service log string } func LogMiddleware(name string) ServiceMiddleware { return func(next Service) Service { return logServer{ next: next, log: &amp;#34;日志中间件V1&amp;#34;, } } } 添加中间件2 type logV2Server struct { next Service log string } func LogV2Middleware(name string) ServiceMiddleware { return func(next Service) Service { return logV2Server{ next: next, log: &amp;#34;日志中间件V2&amp;#34;, } } } 结果 svc := NewService(&amp;#34;&amp;#34;) fmt.</description>
    </item>
    
    <item>
      <title>Golang 实现时间轮</title>
      <link>http://hwholiday.github.io/2019/simple_timing_wheel/</link>
      <pubDate>Wed, 25 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/simple_timing_wheel/</guid>
      <description>简单时间轮(simple_timing_wheel) 一个 简单时间轮 就是一个循环列表，列表中的每一格包含一个定时任务列表（双向链表）。一个时间单位为 u、大小为 n 的简单时间轮，可以包含的定时任务的最大到期间隔为 n*u。 以 u 为 1ms、n 为 3 的简单时间轮为例，可以包含的定时任务的最大到期间隔为 3ms。 初始时，假设当前时间指向第 1 格（此时：到期间隔为 [0ms, 1ms) 的定时任务放第 1 格，[1ms, 2ms) 的放第 2 格，[2ms, 3ms) 的放第 3 格）。 此时我们创建一个到期间隔为 1ms 的定时任务 task1，按规则该任务会被插入到第 2 格。 随着时间的流逝，过了 1ms 后当前时间指向第 2 格，这一格包含的定时任务 task1 会被删除并执行。 当前时间指向第 2 格（此时：到期间隔为 [0ms, 1ms) 的定时任务放第 2 格，[1ms, 2ms) 的放第 3 格，[2ms, 3ms) 的放第 1 格），我们继续创建一个到期间隔为 2ms 的定时任务 task2，按规则该任务被插入到第 1 格。 简单时间轮的优点是实现简单，缺点是： 选定 n 后，就不能包含到期间隔超过 n*u 的定时任务。 如果定时任务的到期时间跨度较大，就会选择较大的 n，在定时任务较少时会造成很大的空间浪费。 变体实现，它们通过在定时任务中增加记录 round 轮次信息，可以有效弥补上述两个缺点。同样以上面 u 为 1ms、n 为 3 的简单时间轮为例，初始时间指向第 1 格；此时如果要创建到期时间为 4ms 的定时任务，可以在该任务中设置 round 为 1（4/3 取整），剩余到期时间用 4ms 减去 round*3ms 等于 1ms，因此放到第 2 格；等到当前时间指向第 2 格时，判断任务中的 round 大于 0，所以不会删除并执行该任务，而是对其 round 减一（于是 round 变为 0）；等到再过 3ms 后，当前时间再次指向第 2 格，判断任务中的 round 为 0，进而删除并执行该任务。 func (s *SimpleTimingWheel) getPositionAndCircle(d time.</description>
    </item>
    
    <item>
      <title>Golang 实践归档</title>
      <link>http://hwholiday.github.io/2019/archive/</link>
      <pubDate>Tue, 24 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/archive/</guid>
      <description>learning_tools 源码地址 go-kit 微服务实践，从入门到精通系列 go-kit (go-kit微服务) 1: v1 go-kit 微服务 基础使用 （HTTP） 2: v2 go-kit 微服务 添加日志（user/zap ,并为每个请求添加UUID） 3: v3 go-kit 微服务 身份认证 （JWT） 4: v4 go-kit 微服务 限流 （uber/ratelimit 和 golang/rate 实现） 5: v5 go-kit 微服务 使用GRPC（并为每个请求添加UUID） 6: v6 go-kit 微服务 服务注册与发现（etcd实现） 7: v7 go-kit 微服务 服务监控（prometheus 实现） 8: v8 go-kit 微服务 服务熔断（hystrix-go 实现） 9: v9 go-kit 微服务 服务链路追踪（jaeger 实现）(1) 10: v9 go-kit 微服务 服务链路追踪（jaeger 实现）(2) 11: v11 go-kit 微服务 添加一个简单网关 go_push 一个实用的消息推送服务 go_push (推送服务) ├── gateway // 长连接网关服务器 │ ├── push_job.</description>
    </item>
    
    <item>
      <title>Golang 高性能日志库 zap 封装工具类</title>
      <link>http://hwholiday.github.io/2019/how_user_zap/</link>
      <pubDate>Tue, 10 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/how_user_zap/</guid>
      <description>zap是uber开源的Go高性能日志库 //安装 go get -u go.uber.org/zap 封装日志库 支持日志文件分等级存放 支付日志文件自动分割 支持日志文件自动压缩 支持日志文件自定义目录 type Options struct { LogFileDir string //文件保存地方 AppName string //日志文件前缀 ErrorFileName string WarnFileName string InfoFileName string DebugFileName string Level zapcore.Level //日志等级 MaxSize int //日志文件小大（M） MaxBackups int // 最多存在多少个切片文件 MaxAge int //保存的最大天数 Development bool //是否是开发模式 zap.Config } 使用 lg := NewLogger(SetAppName(&amp;#34;test_app&amp;#34;), SetDevelopment(true), SetLevel(zap.DebugLevel), SetErrorFileName(&amp;#34;error_e_e_e_e.log&amp;#34;)) lg.Debug(fmt.Sprint(&amp;#34;debug log &amp;#34;, 1), zap.Int(&amp;#34;line&amp;#34;, 47)) lg.Info(fmt.Sprint(&amp;#34;Info log &amp;#34;, 2), zap.Any(&amp;#34;level&amp;#34;, &amp;#34;1231231231&amp;#34;)) lg.Warn(fmt.Sprint(&amp;#34;warn log &amp;#34;, 3), zap.</description>
    </item>
    
    <item>
      <title>Golang 实现向量空间余弦相似度(Cosine Similarity)</title>
      <link>http://hwholiday.github.io/2019/cosine_similarity/</link>
      <pubDate>Tue, 03 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/cosine_similarity/</guid>
      <description>什么是向量空间余弦相似度 余弦相似性通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0度角的余弦值是1，而其他任何角度的余弦值都不大于1；并且其最小值是-1。从而两个向量之间的角度的余弦值确定两个向量是否大致指向相同的方向。两个向量有相同的指向时，余弦相似度的值为1；两个向量夹角为90°时，余弦相似度的值为0；两个向量指向完全相反的方向时，余弦相似度的值为-1。这结果是与向量的长度无关的，仅仅与向量的指向方向相关。余弦相似度通常用于正空间，因此给出的值为-1到1之间。
代码实现 func Cosine(a []float64, b []float64) float64 { var ( aLen = len(a) bLen = len(b) s = 0.0 sa = 0.0 sb = 0.0 count = 0 ) if aLen &amp;gt; bLen { count = aLen } else { count = bLen } for i := 0; i &amp;lt; count; i++ { if i &amp;gt;= bLen { sa += math.Pow(a[i], 2) continue } if i &amp;gt;= aLen { sb += math.</description>
    </item>
    
    <item>
      <title>Golang 实现LRU算法</title>
      <link>http://hwholiday.github.io/2019/lru/</link>
      <pubDate>Sun, 01 Dec 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/lru/</guid>
      <description>缓存文件置换机制是计算机处理缓存存储器的一种机制。 计算机存储器空间的大小固定，无法容纳服务器上所有的文件，所以当有新的文件要被置换入缓存时，必须根据一定的原则来取代掉适当的文件。此原则即所谓缓存文件置换机制。
缓存文件置换方法有：
先进先出算法（FIFO）：最先进入的内容作为替换对象 最近最少使用算法（LFU）：最近最少使用的内容作为替换对象 最久未使用算法（LRU）：最久没有访问的内容作为替换对象 非最近使用算法（NMRU）：在最近没有使用的内容中随机选择一个作为替换对象 代码实现 type Lru struct { max int l *list.List Call func(key interface{}, value interface{}) cache map[interface{}]*list.Element mu *sync.Mutex } type Node struct { Key interface{} Val interface{} } func NewLru(len int) *Lru { return &amp;amp;Lru{ max: len, l: list.New(), cache: make(map[interface{}]*list.Element), mu: new(sync.Mutex), } } func (l *Lru) Add(key interface{}, val interface{}) error { if l.l == nil { return errors.New(&amp;#34;not init NewLru&amp;#34;) } l.</description>
    </item>
    
    <item>
      <title>一致性hash算法原理及Golang实现</title>
      <link>http://hwholiday.github.io/2019/consistency_hash/</link>
      <pubDate>Tue, 26 Nov 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/consistency_hash/</guid>
      <description>需求 当集群提供缓存服务时，key应该路由到哪一个服务.这里假如采用最通用的方式key%N(N为服务器数目)，看上去是没问题的但是一旦服务器数目发生增加或减少时, 分配方式则变为key%(N+1)或key%(N-1).这里将会有大量的key失效, 为了解决类问题,一致性hash算法应运而生.
一致性hash算法特点 均衡性(Balance) 单调性(Monotonicity) 分散性(Spread) 负载(Load) 一致性hash详解 一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后，哈希表槽位数（大小）的改变平均只需要对 K/n个关键字重新映射，其中 K是关键字的数量，n是槽位数量。然而在传统的哈希表中，添加或删除一个槽位的几乎需要对所有关键字进行重新映射。 一致性哈希算法将整个哈希值空间映射成一个虚拟的圆环，整个哈希空间的取值范围为0~2的32次方-1。整个空间按顺时针方向组织。0~2的32次方-1在零点中方向重合。接下来使用如下算法对服务请求进行映射，将服务请求使用哈希算法算出对应的hash值，然后根据hash值的位置沿圆环顺时针查找，第一台遇到的服务器就是所对应的处理请求服务器。当增加一台新的服务器，受影响的数据仅仅是新添加的服务器到其环空间中前一台的服务器（也就是顺着逆时针方向遇到的第一台服务器）之间的数据，其他都不会受到影响。综上所述，一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据，具有较好的容错性和可扩展性 改进 如果服务器节点较少，存在某些节点所在位置周围有大量的hash点从而导致分配到这些节点到key要比其他节点多的多，这样会导致集群中各节点负载不均衡，为解决这个问题，引入虚拟节点， 即一个实节点对应多个虚拟节点。缓存的key作映射时，先找到对应的虚拟节点，再对应到实节点
代码实现 type Consistent struct { nodesReplicas int //添加虚拟节点数量 hashSortNodes []uint32 //所有节点的排序数组 circle map[uint32]string //所有节点对应的node nodes map[string]bool //node是否存在 } func NewConsistent() *Consistent { return &amp;amp;Consistent{ nodesReplicas: 20, circle: make(map[uint32]string), nodes: make(map[string]bool), } } func (c *Consistent) Add(node string) error { if _, ok := c.nodes[node]; ok { //判断新加节点是否存在 return fmt.Errorf(&amp;#34;%s already existed&amp;#34;, node) } c.</description>
    </item>
    
    <item>
      <title>Golang 实现Google 内购以及订阅代码</title>
      <link>http://hwholiday.github.io/2019/google_py/</link>
      <pubDate>Thu, 24 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/google_py/</guid>
      <description>内购 先检查签名是否正确 再查询google该订单信息是否正确 具体细节请联系我的QQ func VerifyGoogleSign(data, id string, sign string) (bool, error) { decodePublic, err := base64.StdEncoding.DecodeString(publicKey) if err != nil { return false, err } pubInterface, err := x509.ParsePKIXPublicKey(decodePublic) if err != nil { return false, err } pub := pubInterface.(*rsa.PublicKey) decodeSign, err := base64.StdEncoding.DecodeString(sign) if err != nil { return false, err } sh1 := sha1.New() sh1.Write([]byte(data)) hashData := sh1.Sum(nil) result := rsa.VerifyPKCS1v15(pub, crypto.SHA1, hashData, decodeSign) if result !</description>
    </item>
    
    <item>
      <title>Golang 双棘轮算法</title>
      <link>http://hwholiday.github.io/2019/signal_prorocol/</link>
      <pubDate>Wed, 03 Jul 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/signal_prorocol/</guid>
      <description>什么是双棘轮算法 双棘轮算法用于通信双方基于共享密钥交换加密消息。通常，通信双方将先使用某种密钥协商协议（例如 X3DH1）以协商共享密钥。此后，通信双方即可使用双棘轮算法发送接收加密消息了。
通信双方将为每一个双棘轮消息派生出新的密钥，使得旧的密钥不能从新的密钥计算得到。通信双方还将在消息中附上迪菲-赫尔曼公钥值。迪菲-赫尔曼计算的结果将被混入派生出的密钥中，使得新的密钥不能从旧的密钥计算得到。这些特性将在某一方的密钥泄漏后保护此前或此后的加密消息。
代码实现 var a PseronA a.IdentityPri, a.IdentityPub = GetCurve25519KeypPair() a.SignedPri, a.SignedPub = GetCurve25519KeypPair() a.OneTimePri, a.OneTimePub = GetCurve25519KeypPair() a.EphemeralPri, a.EphemeralPub = GetCurve25519KeypPair() var b PseronB b.IdentityPri, b.IdentityPub = GetCurve25519KeypPair() b.SignedPri, b.SignedPub = GetCurve25519KeypPair() b.OneTimePri, b.OneTimePub = GetCurve25519KeypPair() b.EphemeralPri, b.EphemeralPub = GetCurve25519KeypPair() //DH1 = DH(IPK-A私钥, SPK-B公钥) //DH2 = DH(EPK-A私钥, IPK-B公钥) //DH3= DH(EPK-A私钥, SPK-B公钥) //DH4 = DH(IPK-A私钥, OPK--B公钥) a.DH1 = GetCurve25519Key(a.IdentityPri, b.SignedPub) a.DH2 = GetCurve25519Key(a.EphemeralPri, b.IdentityPub) a.DH3 = GetCurve25519Key(a.EphemeralPri, b.SignedPub) a.</description>
    </item>
    
    <item>
      <title>Golang 椭圆加密算法实现</title>
      <link>http://hwholiday.github.io/2019/ecc/</link>
      <pubDate>Wed, 03 Jul 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/ecc/</guid>
      <description>什么是椭圆加密算法 椭圆曲线密码学（英语：Elliptic Curve Cryptography，缩写：ECC）是一种基于椭圆曲线数学的公开密钥加密算法。椭圆曲线在密码学中的使用是在1985年由Neal Koblitz和Victor Miller分别独立提出的。 ECC的主要优势是在某些情况下它比其他的算法（比如RSA加密算法）使用更小的密钥并提供相当的或更高等级的安全。ECC的另一个优势是可以定义群之间的双线性映射，基于Weil对或是Tate对；双线性映射已经在密码学中发现了大量的应用，例如基于身份的加密。不过一个缺点是加密和解密操作的实现比其他机制花费的时间长。
代码实现 var Aprivate, Apublic [32]byte //产生随机数 if _, err := io.ReadFull(rand.Reader, Aprivate[:]); err != nil { os.Exit(0) } curve25519.ScalarBaseMult(&amp;amp;Apublic, &amp;amp;Aprivate) fmt.Println(&amp;#34;A私钥&amp;#34;, base64.StdEncoding.EncodeToString(Aprivate[:])) fmt.Println(&amp;#34;A公钥&amp;#34;, base64.StdEncoding.EncodeToString(Apublic[:])) //作为椭圆起点 var Bprivate, Bpublic [32]byte //产生随机数 if _, err := io.ReadFull(rand.Reader, Bprivate[:]); err != nil { os.Exit(0) } curve25519.ScalarBaseMult(&amp;amp;Bpublic, &amp;amp;Bprivate) fmt.Println(&amp;#34;B私钥&amp;#34;, base64.StdEncoding.EncodeToString(Bprivate[:])) fmt.Println(&amp;#34;B公钥&amp;#34;, base64.StdEncoding.EncodeToString(Bpublic[:])) //作为椭圆起点 var Akey, Bkey [32]byte //A的私钥加上Ｂ的公钥计算A的key curve25519.ScalarMult(&amp;amp;Akey, &amp;amp;Aprivate, &amp;amp;Bpublic) //B的私钥加上A的公钥计算B的key curve25519.ScalarMult(&amp;amp;Bkey, &amp;amp;Bprivate, &amp;amp;Apublic) fmt.Println(&amp;#34;A交互的KEY&amp;#34;, base64.StdEncoding.EncodeToString(Akey[:])) fmt.</description>
    </item>
    
    <item>
      <title>Golang 生成短链接服务</title>
      <link>http://hwholiday.github.io/2019/short_url/</link>
      <pubDate>Tue, 02 Jul 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/short_url/</guid>
      <description>什么是短链接 就是把普通网址，转换成比较短的网址。比如：https://dwz.cn/XzhYJMkZ
原理解析 当我们在浏览器里输入 https://dwz.cn/XzhYJMkZ DNS首先解析获得 https://dwz.cn/ 的 IP 地址 当 DNS 获得 IP 地址以后，会向这个地址发送 HTTP请求，查询短码 XzhYJMkZ https://dwz.cn/ 服务器会通过短码 XzhYJMkZ 获取对应的长 URL 请求通过 HTTP 301 转到对应的长 URL http://www.baidu.com
本文采用 自增序列算法 + 用户自定义短码 设置 id 自增，一个 10进制 id 对应一个 62进制的数值，1对1，也就不会出现重复的情况。这个利用的就是低进制转化为高进制时，字符数会减少的特性。 可使用redis Incr 实现id自增。
数据表设计 CREATE TABLE `links` ( `id` int(11) NOT NULL AUTO_INCREMENT, `url` varchar(200) COLLATE utf8mb4_bin NOT NULL COMMENT &amp;#39;长连接&amp;#39;, `keyword` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT &amp;#39;短链接码&amp;#39;, `status` tinyint(1) NOT NULL COMMENT &amp;#39;1系统分配 2用户自定义&amp;#39;, `create_time` bigint(20) NOT NULL, `update_time` bigint(20) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `links_UN` (`url`), UNIQUE KEY `links_keyword` (`keyword`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 服务使用 生成短链接 post http://127.</description>
    </item>
    
    <item>
      <title>Golang Time包的方法解析</title>
      <link>http://hwholiday.github.io/2019/how_use_time/</link>
      <pubDate>Mon, 20 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/how_use_time/</guid>
      <description>基础使用 //获取秒级时间戳 time.Now().Unix() //获取毫秒级时间戳 time.Now().UnixNano()/1e6 //格式化时间 time.Now().Format(&amp;#34;2006-01-02 15:04&amp;#34;) //字符串转时间格式 t, err := time.Parse(&amp;#34;2006-01-02 15:04:05&amp;#34;, &amp;#34;2019-05-20 18:30:50&amp;#34;) //时间戳转为字符串 t := time.Unix(&amp;#34;1558348250&amp;#34;, 0).Format(&amp;#34;2006-01-02 15:04&amp;#34;) 设置时区(中国) //在windows系统上，没有安装go语言环境的情况下，time.LoadLocation会加载失败。 var sh, _ = time.LoadLocation(&amp;#34;Asia/Shanghai&amp;#34;) time.Now().In(sh).Format(&amp;#34;2006-01-02 15:04:05&amp;#34;) //time.FixedZone各个系统都能很好的设置时区 time.Now().In(time.FixedZone(&amp;#34;CST&amp;#34;, 8*3600)).Format(&amp;#34;2006-01-02 15:04:05&amp;#34;)) time 时间的加减法 Add方法 Add用于计算某个时间之前和之后的时间点 //h -- &amp;gt; 时 //m -- &amp;gt; 分 //s -- &amp;gt; 秒 //ms -- &amp;gt; 毫秒 //us -- &amp;gt; 纳秒 //µs -- &amp;gt; 纳秒 //ns -- &amp;gt; 微秒 //10分钟前的时间 m, _ := time.</description>
    </item>
    
    <item>
      <title>docker安装prometheus（普罗米修斯）</title>
      <link>http://hwholiday.github.io/2019/docker_install_prometheus/</link>
      <pubDate>Tue, 07 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2019/docker_install_prometheus/</guid>
      <description>Prometheus简介 Prometheus是一个开源监控系统，它前身是SoundCloud的警告工具包 从2012年开始，许多公司和组织开始使用Prometheus。该项目的开发人员和用户社区非常活跃，越来越多的开发人员和用户参与到该项目中。目前它是一个独立的开源项目，且不依赖与任何公司 为了强调这点和明确该项目治理结构，Prometheus在2016年继Kurberntes之后，加入了Cloud Native Computing Foundation。 以下命令都需要管理员权限 sudo 搜索 gitlab Docker镜像 sudo docker search prometheus //输出结果部分截图 NAME DESCRIPTION STARS OFFICIAL AUTOMATED prom/prometheus 726 [OK] infinityworks/prometheus-rancher-exporter Exposes Service/Stack/Host status from the R… 7 [OK] basi/prometheus-swarm A sample image that can be used as a base fo… 7 [OK] linuxtips/prometheus_alpine Image to run Prometheus on Alpine Linux. #VA… 7 [OK] sscaling/jmx-prometheus-exporter A docker image containing a released version… 6 [OK] bitnami/prometheus Bitnami Docker Image for Prometheus 6 [OK] stefanprodan/swarmprom-prometheus Prometheus Docker Swarm 5 functions/prometheus prometheus 5 [OK] 拉取 gitlab Docker镜像 sudo docker pull prom/prometheus 配置 Prometheus使用YAML进行配置(prometheus.</description>
    </item>
    
    <item>
      <title>mongodb官方的golang驱动基础使用</title>
      <link>http://hwholiday.github.io/2018/how_use_mongo-go-driver/</link>
      <pubDate>Tue, 11 Dec 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/how_use_mongo-go-driver/</guid>
      <description>导入 go get github.com/mongodb/mongo-go-driver/mongo struct里面获取ObjectID 点击这里 链接mongo服务 if client, err = mongo.Connect(getContext(), url); err != nil { checkErr(err) } 判断服务是否可用 if err = client.Ping(getContext(), readpref.Primary()); err != nil { checkErr(err) } 选择数据库和集合 collection = client.Database(&amp;#34;testing_base&amp;#34;).Collection(&amp;#34;howie&amp;#34;) 设置集合内数据过期时间 k := mongo.IndexModel{ Keys: bsonx.Doc{{&amp;#34;expiredtime&amp;#34;, bsonx.Int32(1)}}, Options: options.Index().SetExpireAfterSeconds(1 * 60),//60秒后过期，详细请查询完整的代码演示 } _, err = collection.Indexes().CreateOne(getContext(), k) 删除这个集合 collection.Drop(getContext()) 插入一条数据 if insertOneRes, err = collection.InsertOne(getContext(), howieArray[0]); err != nil { checkErr(err) } fmt.Printf(&amp;#34;InsertOne插入的消息ID:%v\n&amp;#34;, insertOneRes.InsertedID) 批量插入数据 if insertManyRes, err = collection.</description>
    </item>
    
    <item>
      <title>Golang 中的并发限制与超时控制</title>
      <link>http://hwholiday.github.io/2018/golang_limit_req/</link>
      <pubDate>Mon, 10 Dec 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/golang_limit_req/</guid>
      <description>代码地址 点击这里 并发限制(一种常见的做法就是利用 channel 的缓冲机制) var limitChan = make(chan bool, n) 如果 channel 没有缓冲，或者缓冲区满了。goroutine 会自动阻塞，直到 channel 里的数据被读走为止 代码演示 var addr = flag.String(&amp;#34;p&amp;#34;, &amp;#34;192.168.2.28:8099&amp;#34;, &amp;#34;port&amp;#34;) func main() { flag.Parse() perf.StartPprof([]string{&amp;#34;192.168.2.28:9022&amp;#34;}) logtool.InitZapLogger(&amp;#34;ghost.log&amp;#34;, true) //http服务 mux := http.NewServeMux() mux.HandleFunc(&amp;#34;/limit_api&amp;#34;, limitApi) s := &amp;amp;http.Server{ Handler: mux, Addr: *addr, WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, MaxHeaderBytes: 1 &amp;lt;&amp;lt; 20, } go func() { err := s.ListenAndServe() if err != nil { logtool.Zap.Panic(&amp;#34;bat_file err&amp;#34;, zap.</description>
    </item>
    
    <item>
      <title>构建一个go程序的docker小镜像</title>
      <link>http://hwholiday.github.io/2018/golang_for_docker/</link>
      <pubDate>Wed, 07 Nov 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/golang_for_docker/</guid>
      <description>scratch镜像是一个空的镜像文件，特别适合创建超级小的镜像。 生成go可执行程序的方法 go可执行程序生成的时候依赖的一些库如libc还是动态链接的，但是scratch 镜像完全是空的，什么东西也不包含，所以生成go可执行程序时候要按照下面的方式生成，使生成的go可执行程序静态链接所有的库：
CGO_ENABLED=0 GOOS=linux go build -a -ldflags &amp;#39;-extldflags &amp;#34;-static&amp;#34;&amp;#39; -o howie_tcp . 创建dockerfile FROM scratch ADD howie_tcp /var/howie_tcp WORKDIR /var ENTRYPOINT [&amp;#34;/var/howie_tcp&amp;#34;] build 镜像 docker build -t tcp:v1 . 创建一个带配置文件的dockerfile FROM scratch ADD main /var/main ADD conf /var/conf/ WORKDIR /var ENTRYPOINT [&amp;#34;/var/main&amp;#34;] //项目目录 . ├── conf │ └── app.ini ├── Dockerfile ├── main └── main.go //main.go 代码 package main import ( &amp;#34;os&amp;#34; &amp;#34;path/filepath&amp;#34; &amp;#34;github.com/go-ini/ini&amp;#34; &amp;#34;fmt&amp;#34; ) func main() { checkErr := func(err error) { if err !</description>
    </item>
    
    <item>
      <title>使用TCP并解决TCP粘包的问题</title>
      <link>http://hwholiday.github.io/2018/goang_tcp_use/</link>
      <pubDate>Thu, 01 Nov 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/goang_tcp_use/</guid>
      <description>最新代码地址(添加head+type+data 解包 并添加心跳) 点击这里 此项目有对应的Android端demo有需求请联系下方QQ TCP粘包和拆包产生的原因 应用程序写入数据的字节大小大于套接字发送缓冲区的大小 进行MSS大小的TCP分段。MSS是最大报文段长度的缩写。MSS是TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是TCP报文段的最大长度，而是：MSS=TCP报文段长度-TCP首部长度 以太网的payload大于MTU进行IP分片。MTU指：一种通信协议的某一层上面所能通过的最大数据包大小。如果IP层有一个数据包要传，而且数据的长度比链路层的MTU大，那么IP层就会进行分片，把数据包分成托干片，让每一片都不超过MTU。注意，IP分片可以发生在原始发送端主机上，也可以发生在中间路由器上。 TCP粘包和拆包的解决策略 消息定长。例如100字节。 在包尾部增加回车或者空格符等特殊字符进行分割，典型的如FTP协议 将消息分为消息头和消息尾。(len+data模式) 其它复杂的协议，如RTMP协议等。 将消息分为消息头+消息类型+消息体。(len+type+data 模式) 废话不多说直接上代码 服务端 package network import ( &amp;#34;net&amp;#34; &amp;#34;github.com/hwholiday/libs/logtool&amp;#34; &amp;#34;go.uber.org/zap&amp;#34; &amp;#34;os&amp;#34; &amp;#34;time&amp;#34; &amp;#34;io&amp;#34; &amp;#34;fmt&amp;#34; ) func InitTcp() { addr, err := net.ResolveTCPAddr(&amp;#34;tcp&amp;#34;, &amp;#34;192.168.2.28:8111&amp;#34;) if err != nil { logtool.Zap.Error(&amp;#34;create addr&amp;#34;, zap.Error(err)) os.Exit(0) } listener, err := net.ListenTCP(&amp;#34;tcp&amp;#34;, addr) if err != nil { logtool.Zap.Error(&amp;#34;listen tcp&amp;#34;, zap.Error(err)) os.Exit(0) } logtool.Zap.Info(&amp;#34;listen tcp&amp;#34;, zap.String(&amp;#34;地址&amp;#34;, addr.String())) go acceptTcp(listener) } func acceptTcp(listener *net.</description>
    </item>
    
    <item>
      <title>随机生成中国人姓名</title>
      <link>http://hwholiday.github.io/2018/go_cn_fullname/</link>
      <pubDate>Mon, 29 Oct 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/go_cn_fullname/</guid>
      <description>package utils import ( &amp;#34;math/rand&amp;#34; &amp;#34;time&amp;#34; &amp;#34;fmt&amp;#34; ) var lastName = []string{ &amp;#34;赵&amp;#34;, &amp;#34;钱&amp;#34;, &amp;#34;孙&amp;#34;, &amp;#34;李&amp;#34;, &amp;#34;周&amp;#34;, &amp;#34;吴&amp;#34;, &amp;#34;郑&amp;#34;, &amp;#34;王&amp;#34;, &amp;#34;冯&amp;#34;, &amp;#34;陈&amp;#34;, &amp;#34;褚&amp;#34;, &amp;#34;卫&amp;#34;, &amp;#34;蒋&amp;#34;, &amp;#34;沈&amp;#34;, &amp;#34;韩&amp;#34;, &amp;#34;杨&amp;#34;, &amp;#34;朱&amp;#34;, &amp;#34;秦&amp;#34;, &amp;#34;尤&amp;#34;, &amp;#34;许&amp;#34;, &amp;#34;何&amp;#34;, &amp;#34;吕&amp;#34;, &amp;#34;施&amp;#34;, &amp;#34;张&amp;#34;, &amp;#34;孔&amp;#34;, &amp;#34;曹&amp;#34;, &amp;#34;严&amp;#34;, &amp;#34;华&amp;#34;, &amp;#34;金&amp;#34;, &amp;#34;魏&amp;#34;, &amp;#34;陶&amp;#34;, &amp;#34;姜&amp;#34;, &amp;#34;戚&amp;#34;, &amp;#34;谢&amp;#34;, &amp;#34;邹&amp;#34;, &amp;#34;喻&amp;#34;, &amp;#34;柏&amp;#34;, &amp;#34;水&amp;#34;, &amp;#34;窦&amp;#34;, &amp;#34;章&amp;#34;, &amp;#34;云&amp;#34;, &amp;#34;苏&amp;#34;, &amp;#34;潘&amp;#34;, &amp;#34;葛&amp;#34;, &amp;#34;奚&amp;#34;, &amp;#34;范&amp;#34;, &amp;#34;彭&amp;#34;, &amp;#34;郎&amp;#34;, &amp;#34;鲁&amp;#34;, &amp;#34;韦&amp;#34;, &amp;#34;昌&amp;#34;, &amp;#34;马&amp;#34;, &amp;#34;苗&amp;#34;, &amp;#34;凤&amp;#34;, &amp;#34;花&amp;#34;, &amp;#34;方&amp;#34;, &amp;#34;任&amp;#34;, &amp;#34;袁&amp;#34;, &amp;#34;柳&amp;#34;, &amp;#34;鲍&amp;#34;, &amp;#34;史&amp;#34;, &amp;#34;唐&amp;#34;, &amp;#34;费&amp;#34;, &amp;#34;薛&amp;#34;, &amp;#34;雷&amp;#34;, &amp;#34;贺&amp;#34;, &amp;#34;倪&amp;#34;, &amp;#34;汤&amp;#34;, &amp;#34;滕&amp;#34;, &amp;#34;殷&amp;#34;, &amp;#34;罗&amp;#34;, &amp;#34;毕&amp;#34;, &amp;#34;郝&amp;#34;, &amp;#34;安&amp;#34;, &amp;#34;常&amp;#34;, &amp;#34;傅&amp;#34;, &amp;#34;卞&amp;#34;, &amp;#34;齐&amp;#34;, &amp;#34;元&amp;#34;, &amp;#34;顾&amp;#34;, &amp;#34;孟&amp;#34;, &amp;#34;平&amp;#34;, &amp;#34;黄&amp;#34;, &amp;#34;穆&amp;#34;, &amp;#34;萧&amp;#34;, &amp;#34;尹&amp;#34;, &amp;#34;姚&amp;#34;, &amp;#34;邵&amp;#34;, &amp;#34;湛&amp;#34;, &amp;#34;汪&amp;#34;, &amp;#34;祁&amp;#34;, &amp;#34;毛&amp;#34;, &amp;#34;狄&amp;#34;, &amp;#34;米&amp;#34;, &amp;#34;伏&amp;#34;, &amp;#34;成&amp;#34;, &amp;#34;戴&amp;#34;, &amp;#34;谈&amp;#34;, &amp;#34;宋&amp;#34;, &amp;#34;茅&amp;#34;, &amp;#34;庞&amp;#34;, &amp;#34;熊&amp;#34;, &amp;#34;纪&amp;#34;, &amp;#34;舒&amp;#34;, &amp;#34;屈&amp;#34;, &amp;#34;项&amp;#34;, &amp;#34;祝&amp;#34;, &amp;#34;董&amp;#34;, &amp;#34;梁&amp;#34;, &amp;#34;杜&amp;#34;, &amp;#34;阮&amp;#34;, &amp;#34;蓝&amp;#34;, &amp;#34;闵&amp;#34;, &amp;#34;季&amp;#34;, &amp;#34;贾&amp;#34;, &amp;#34;路&amp;#34;, &amp;#34;娄&amp;#34;, &amp;#34;江&amp;#34;, &amp;#34;童&amp;#34;, &amp;#34;颜&amp;#34;, &amp;#34;郭&amp;#34;, &amp;#34;梅&amp;#34;, &amp;#34;盛&amp;#34;, &amp;#34;林&amp;#34;, &amp;#34;钟&amp;#34;, &amp;#34;徐&amp;#34;, &amp;#34;邱&amp;#34;, &amp;#34;骆&amp;#34;, &amp;#34;高&amp;#34;, &amp;#34;夏&amp;#34;, &amp;#34;蔡&amp;#34;, &amp;#34;田&amp;#34;, &amp;#34;樊&amp;#34;, &amp;#34;胡&amp;#34;, &amp;#34;凌&amp;#34;, &amp;#34;霍&amp;#34;, &amp;#34;虞&amp;#34;, &amp;#34;万&amp;#34;, &amp;#34;支&amp;#34;, &amp;#34;柯&amp;#34;, &amp;#34;管&amp;#34;, &amp;#34;卢&amp;#34;, &amp;#34;莫&amp;#34;, &amp;#34;柯&amp;#34;, &amp;#34;房&amp;#34;, &amp;#34;裘&amp;#34;, &amp;#34;缪&amp;#34;, &amp;#34;解&amp;#34;, &amp;#34;应&amp;#34;, &amp;#34;宗&amp;#34;, &amp;#34;丁&amp;#34;, &amp;#34;宣&amp;#34;, &amp;#34;邓&amp;#34;, &amp;#34;单&amp;#34;, &amp;#34;杭&amp;#34;, &amp;#34;洪&amp;#34;, &amp;#34;包&amp;#34;, &amp;#34;诸&amp;#34;, &amp;#34;左&amp;#34;, &amp;#34;石&amp;#34;, &amp;#34;崔&amp;#34;, &amp;#34;吉&amp;#34;, &amp;#34;龚&amp;#34;, &amp;#34;程&amp;#34;, &amp;#34;嵇&amp;#34;, &amp;#34;邢&amp;#34;, &amp;#34;裴&amp;#34;, &amp;#34;陆&amp;#34;, &amp;#34;荣&amp;#34;, &amp;#34;翁&amp;#34;, &amp;#34;荀&amp;#34;, &amp;#34;于&amp;#34;, &amp;#34;惠&amp;#34;, &amp;#34;甄&amp;#34;, &amp;#34;曲&amp;#34;, &amp;#34;封&amp;#34;, &amp;#34;储&amp;#34;, &amp;#34;仲&amp;#34;, &amp;#34;伊&amp;#34;, &amp;#34;宁&amp;#34;, &amp;#34;仇&amp;#34;, &amp;#34;甘&amp;#34;, &amp;#34;武&amp;#34;, &amp;#34;符&amp;#34;, &amp;#34;刘&amp;#34;, &amp;#34;景&amp;#34;, &amp;#34;詹&amp;#34;, &amp;#34;龙&amp;#34;, &amp;#34;叶&amp;#34;, &amp;#34;幸&amp;#34;, &amp;#34;司&amp;#34;, &amp;#34;黎&amp;#34;, &amp;#34;溥&amp;#34;, &amp;#34;印&amp;#34;, &amp;#34;怀&amp;#34;, &amp;#34;蒲&amp;#34;, &amp;#34;邰&amp;#34;, &amp;#34;从&amp;#34;, &amp;#34;索&amp;#34;, &amp;#34;赖&amp;#34;, &amp;#34;卓&amp;#34;, &amp;#34;屠&amp;#34;, &amp;#34;池&amp;#34;, &amp;#34;乔&amp;#34;, &amp;#34;胥&amp;#34;, &amp;#34;闻&amp;#34;, &amp;#34;莘&amp;#34;, &amp;#34;党&amp;#34;, &amp;#34;翟&amp;#34;, &amp;#34;谭&amp;#34;, &amp;#34;贡&amp;#34;, &amp;#34;劳&amp;#34;, &amp;#34;逄&amp;#34;, &amp;#34;姬&amp;#34;, &amp;#34;申&amp;#34;, &amp;#34;扶&amp;#34;, &amp;#34;堵&amp;#34;, &amp;#34;冉&amp;#34;, &amp;#34;宰&amp;#34;, &amp;#34;雍&amp;#34;, &amp;#34;桑&amp;#34;, &amp;#34;寿&amp;#34;, &amp;#34;通&amp;#34;, &amp;#34;燕&amp;#34;, &amp;#34;浦&amp;#34;, &amp;#34;尚&amp;#34;, &amp;#34;农&amp;#34;, &amp;#34;温&amp;#34;, &amp;#34;别&amp;#34;, &amp;#34;庄&amp;#34;, &amp;#34;晏&amp;#34;, &amp;#34;柴&amp;#34;, &amp;#34;瞿&amp;#34;, &amp;#34;阎&amp;#34;, &amp;#34;连&amp;#34;, &amp;#34;习&amp;#34;, &amp;#34;容&amp;#34;, &amp;#34;向&amp;#34;, &amp;#34;古&amp;#34;, &amp;#34;易&amp;#34;, &amp;#34;廖&amp;#34;, &amp;#34;庾&amp;#34;, &amp;#34;终&amp;#34;, &amp;#34;步&amp;#34;, &amp;#34;都&amp;#34;, &amp;#34;耿&amp;#34;, &amp;#34;满&amp;#34;, &amp;#34;弘&amp;#34;, &amp;#34;匡&amp;#34;, &amp;#34;国&amp;#34;, &amp;#34;文&amp;#34;, &amp;#34;寇&amp;#34;, &amp;#34;广&amp;#34;, &amp;#34;禄&amp;#34;, &amp;#34;阙&amp;#34;, &amp;#34;东&amp;#34;, &amp;#34;欧&amp;#34;, &amp;#34;利&amp;#34;, &amp;#34;师&amp;#34;, &amp;#34;巩&amp;#34;, &amp;#34;聂&amp;#34;, &amp;#34;关&amp;#34;, &amp;#34;荆&amp;#34;, &amp;#34;司马&amp;#34;, &amp;#34;上官&amp;#34;, &amp;#34;欧阳&amp;#34;, &amp;#34;夏侯&amp;#34;, &amp;#34;诸葛&amp;#34;, &amp;#34;闻人&amp;#34;, &amp;#34;东方&amp;#34;, &amp;#34;赫连&amp;#34;, &amp;#34;皇甫&amp;#34;, &amp;#34;尉迟&amp;#34;, &amp;#34;公羊&amp;#34;, &amp;#34;澹台&amp;#34;, &amp;#34;公冶&amp;#34;, &amp;#34;宗政&amp;#34;, &amp;#34;濮阳&amp;#34;, &amp;#34;淳于&amp;#34;, &amp;#34;单于&amp;#34;, &amp;#34;太叔&amp;#34;, &amp;#34;申屠&amp;#34;, &amp;#34;公孙&amp;#34;, &amp;#34;仲孙&amp;#34;, &amp;#34;轩辕&amp;#34;, &amp;#34;令狐&amp;#34;, &amp;#34;徐离&amp;#34;, &amp;#34;宇文&amp;#34;, &amp;#34;长孙&amp;#34;, &amp;#34;慕容&amp;#34;, &amp;#34;司徒&amp;#34;, &amp;#34;司空&amp;#34;} var firstName = []string{ &amp;#34;伟&amp;#34;, &amp;#34;刚&amp;#34;, &amp;#34;勇&amp;#34;, &amp;#34;毅&amp;#34;, &amp;#34;俊&amp;#34;, &amp;#34;峰&amp;#34;, &amp;#34;强&amp;#34;, &amp;#34;军&amp;#34;, &amp;#34;平&amp;#34;, &amp;#34;保&amp;#34;, &amp;#34;东&amp;#34;, &amp;#34;文&amp;#34;, &amp;#34;辉&amp;#34;, &amp;#34;力&amp;#34;, &amp;#34;明&amp;#34;, &amp;#34;永&amp;#34;, &amp;#34;健&amp;#34;, &amp;#34;世&amp;#34;, &amp;#34;广&amp;#34;, &amp;#34;志&amp;#34;, &amp;#34;义&amp;#34;, &amp;#34;兴&amp;#34;, &amp;#34;良&amp;#34;, &amp;#34;海&amp;#34;, &amp;#34;山&amp;#34;, &amp;#34;仁&amp;#34;, &amp;#34;波&amp;#34;, &amp;#34;宁&amp;#34;, &amp;#34;贵&amp;#34;, &amp;#34;福&amp;#34;, &amp;#34;生&amp;#34;, &amp;#34;龙&amp;#34;, &amp;#34;元&amp;#34;, &amp;#34;全&amp;#34;, &amp;#34;国&amp;#34;, &amp;#34;胜&amp;#34;, &amp;#34;学&amp;#34;, &amp;#34;祥&amp;#34;, &amp;#34;才&amp;#34;, &amp;#34;发&amp;#34;, &amp;#34;武&amp;#34;, &amp;#34;新&amp;#34;, &amp;#34;利&amp;#34;, &amp;#34;清&amp;#34;, &amp;#34;飞&amp;#34;, &amp;#34;彬&amp;#34;, &amp;#34;富&amp;#34;, &amp;#34;顺&amp;#34;, &amp;#34;信&amp;#34;, &amp;#34;子&amp;#34;, &amp;#34;杰&amp;#34;, &amp;#34;涛&amp;#34;, &amp;#34;昌&amp;#34;, &amp;#34;成&amp;#34;, &amp;#34;康&amp;#34;, &amp;#34;星&amp;#34;, &amp;#34;光&amp;#34;, &amp;#34;天&amp;#34;, &amp;#34;达&amp;#34;, &amp;#34;安&amp;#34;, &amp;#34;岩&amp;#34;, &amp;#34;中&amp;#34;, &amp;#34;茂&amp;#34;, &amp;#34;进&amp;#34;, &amp;#34;林&amp;#34;, &amp;#34;有&amp;#34;, &amp;#34;坚&amp;#34;, &amp;#34;和&amp;#34;, &amp;#34;彪&amp;#34;, &amp;#34;博&amp;#34;, &amp;#34;诚&amp;#34;, &amp;#34;先&amp;#34;, &amp;#34;敬&amp;#34;, &amp;#34;震&amp;#34;, &amp;#34;振&amp;#34;, &amp;#34;壮&amp;#34;, &amp;#34;会&amp;#34;, &amp;#34;思&amp;#34;, &amp;#34;群&amp;#34;, &amp;#34;豪&amp;#34;, &amp;#34;心&amp;#34;, &amp;#34;邦&amp;#34;, &amp;#34;承&amp;#34;, &amp;#34;乐&amp;#34;, &amp;#34;绍&amp;#34;, &amp;#34;功&amp;#34;, &amp;#34;松&amp;#34;, &amp;#34;善&amp;#34;, &amp;#34;厚&amp;#34;, &amp;#34;庆&amp;#34;, &amp;#34;磊&amp;#34;, &amp;#34;民&amp;#34;, &amp;#34;友&amp;#34;, &amp;#34;裕&amp;#34;, &amp;#34;河&amp;#34;, &amp;#34;哲&amp;#34;, &amp;#34;江&amp;#34;, &amp;#34;超&amp;#34;, &amp;#34;浩&amp;#34;, &amp;#34;亮&amp;#34;, &amp;#34;政&amp;#34;, &amp;#34;谦&amp;#34;, &amp;#34;亨&amp;#34;, &amp;#34;奇&amp;#34;, &amp;#34;固&amp;#34;, &amp;#34;之&amp;#34;, &amp;#34;轮&amp;#34;, &amp;#34;翰&amp;#34;, &amp;#34;朗&amp;#34;, &amp;#34;伯&amp;#34;, &amp;#34;宏&amp;#34;, &amp;#34;言&amp;#34;, &amp;#34;若&amp;#34;, &amp;#34;鸣&amp;#34;, &amp;#34;朋&amp;#34;, &amp;#34;斌&amp;#34;, &amp;#34;梁&amp;#34;, &amp;#34;栋&amp;#34;, &amp;#34;维&amp;#34;, &amp;#34;启&amp;#34;, &amp;#34;克&amp;#34;, &amp;#34;伦&amp;#34;, &amp;#34;翔&amp;#34;, &amp;#34;旭&amp;#34;, &amp;#34;鹏&amp;#34;, &amp;#34;泽&amp;#34;, &amp;#34;晨&amp;#34;, &amp;#34;辰&amp;#34;, &amp;#34;士&amp;#34;, &amp;#34;以&amp;#34;, &amp;#34;建&amp;#34;, &amp;#34;家&amp;#34;, &amp;#34;致&amp;#34;, &amp;#34;树&amp;#34;, &amp;#34;炎&amp;#34;, &amp;#34;德&amp;#34;, &amp;#34;行&amp;#34;, &amp;#34;时&amp;#34;, &amp;#34;泰&amp;#34;, &amp;#34;盛&amp;#34;, &amp;#34;雄&amp;#34;, &amp;#34;琛&amp;#34;, &amp;#34;钧&amp;#34;, &amp;#34;冠&amp;#34;, &amp;#34;策&amp;#34;, &amp;#34;腾&amp;#34;, &amp;#34;楠&amp;#34;, &amp;#34;榕&amp;#34;, &amp;#34;风&amp;#34;, &amp;#34;航&amp;#34;, &amp;#34;弘&amp;#34;, &amp;#34;秀&amp;#34;, &amp;#34;娟&amp;#34;, &amp;#34;英&amp;#34;, &amp;#34;华&amp;#34;, &amp;#34;慧&amp;#34;, &amp;#34;巧&amp;#34;, &amp;#34;美&amp;#34;, &amp;#34;娜&amp;#34;, &amp;#34;静&amp;#34;, &amp;#34;淑&amp;#34;, &amp;#34;惠&amp;#34;, &amp;#34;珠&amp;#34;, &amp;#34;翠&amp;#34;, &amp;#34;雅&amp;#34;, &amp;#34;芝&amp;#34;, &amp;#34;玉&amp;#34;, &amp;#34;萍&amp;#34;, &amp;#34;红&amp;#34;, &amp;#34;娥&amp;#34;, &amp;#34;玲&amp;#34;, &amp;#34;芬&amp;#34;, &amp;#34;芳&amp;#34;, &amp;#34;燕&amp;#34;, &amp;#34;彩&amp;#34;, &amp;#34;春&amp;#34;, &amp;#34;菊&amp;#34;, &amp;#34;兰&amp;#34;, &amp;#34;凤&amp;#34;, &amp;#34;洁&amp;#34;, &amp;#34;梅&amp;#34;, &amp;#34;琳&amp;#34;, &amp;#34;素&amp;#34;, &amp;#34;云&amp;#34;, &amp;#34;莲&amp;#34;, &amp;#34;真&amp;#34;, &amp;#34;环&amp;#34;, &amp;#34;雪&amp;#34;, &amp;#34;荣&amp;#34;, &amp;#34;爱&amp;#34;, &amp;#34;妹&amp;#34;, &amp;#34;霞&amp;#34;, &amp;#34;香&amp;#34;, &amp;#34;月&amp;#34;, &amp;#34;莺&amp;#34;, &amp;#34;媛&amp;#34;, &amp;#34;艳&amp;#34;, &amp;#34;瑞&amp;#34;, &amp;#34;凡&amp;#34;, &amp;#34;佳&amp;#34;, &amp;#34;嘉&amp;#34;, &amp;#34;琼&amp;#34;, &amp;#34;勤&amp;#34;, &amp;#34;珍&amp;#34;, &amp;#34;贞&amp;#34;, &amp;#34;莉&amp;#34;, &amp;#34;桂&amp;#34;, &amp;#34;娣&amp;#34;, &amp;#34;叶&amp;#34;, &amp;#34;璧&amp;#34;, &amp;#34;璐&amp;#34;, &amp;#34;娅&amp;#34;, &amp;#34;琦&amp;#34;, &amp;#34;晶&amp;#34;, &amp;#34;妍&amp;#34;, &amp;#34;茜&amp;#34;, &amp;#34;秋&amp;#34;, &amp;#34;珊&amp;#34;, &amp;#34;莎&amp;#34;, &amp;#34;锦&amp;#34;, &amp;#34;黛&amp;#34;, &amp;#34;青&amp;#34;, &amp;#34;倩&amp;#34;, &amp;#34;婷&amp;#34;, &amp;#34;姣&amp;#34;, &amp;#34;婉&amp;#34;, &amp;#34;娴&amp;#34;, &amp;#34;瑾&amp;#34;, &amp;#34;颖&amp;#34;, &amp;#34;露&amp;#34;, &amp;#34;瑶&amp;#34;, &amp;#34;怡&amp;#34;, &amp;#34;婵&amp;#34;, &amp;#34;雁&amp;#34;, &amp;#34;蓓&amp;#34;, &amp;#34;纨&amp;#34;, &amp;#34;仪&amp;#34;, &amp;#34;荷&amp;#34;, &amp;#34;丹&amp;#34;, &amp;#34;蓉&amp;#34;, &amp;#34;眉&amp;#34;, &amp;#34;君&amp;#34;, &amp;#34;琴&amp;#34;, &amp;#34;蕊&amp;#34;, &amp;#34;薇&amp;#34;, &amp;#34;菁&amp;#34;, &amp;#34;梦&amp;#34;, &amp;#34;岚&amp;#34;, &amp;#34;苑&amp;#34;, &amp;#34;婕&amp;#34;, &amp;#34;馨&amp;#34;, &amp;#34;瑗&amp;#34;, &amp;#34;琰&amp;#34;, &amp;#34;韵&amp;#34;, &amp;#34;融&amp;#34;, &amp;#34;园&amp;#34;, &amp;#34;艺&amp;#34;, &amp;#34;咏&amp;#34;, &amp;#34;卿&amp;#34;, &amp;#34;聪&amp;#34;, &amp;#34;澜&amp;#34;, &amp;#34;纯&amp;#34;, &amp;#34;毓&amp;#34;, &amp;#34;悦&amp;#34;, &amp;#34;昭&amp;#34;, &amp;#34;冰&amp;#34;, &amp;#34;爽&amp;#34;, &amp;#34;琬&amp;#34;, &amp;#34;茗&amp;#34;, &amp;#34;羽&amp;#34;, &amp;#34;希&amp;#34;, &amp;#34;欣&amp;#34;, &amp;#34;飘&amp;#34;, &amp;#34;育&amp;#34;, &amp;#34;滢&amp;#34;, &amp;#34;馥&amp;#34;, &amp;#34;筠&amp;#34;, &amp;#34;柔&amp;#34;, &amp;#34;竹&amp;#34;, &amp;#34;霭&amp;#34;, &amp;#34;凝&amp;#34;, &amp;#34;晓&amp;#34;, &amp;#34;欢&amp;#34;, &amp;#34;霄&amp;#34;, &amp;#34;枫&amp;#34;, &amp;#34;芸&amp;#34;, &amp;#34;菲&amp;#34;, &amp;#34;寒&amp;#34;, &amp;#34;伊&amp;#34;, &amp;#34;亚&amp;#34;, &amp;#34;宜&amp;#34;, &amp;#34;可&amp;#34;, &amp;#34;姬&amp;#34;, &amp;#34;舒&amp;#34;, &amp;#34;影&amp;#34;, &amp;#34;荔&amp;#34;, &amp;#34;枝&amp;#34;, &amp;#34;丽&amp;#34;, &amp;#34;阳&amp;#34;, &amp;#34;妮&amp;#34;, &amp;#34;宝&amp;#34;, &amp;#34;贝&amp;#34;, &amp;#34;初&amp;#34;, &amp;#34;程&amp;#34;, &amp;#34;梵&amp;#34;, &amp;#34;罡&amp;#34;, &amp;#34;恒&amp;#34;, &amp;#34;鸿&amp;#34;, &amp;#34;桦&amp;#34;, &amp;#34;骅&amp;#34;, &amp;#34;剑&amp;#34;, &amp;#34;娇&amp;#34;, &amp;#34;纪&amp;#34;, &amp;#34;宽&amp;#34;, &amp;#34;苛&amp;#34;, &amp;#34;灵&amp;#34;, &amp;#34;玛&amp;#34;, &amp;#34;媚&amp;#34;, &amp;#34;琪&amp;#34;, &amp;#34;晴&amp;#34;, &amp;#34;容&amp;#34;, &amp;#34;睿&amp;#34;, &amp;#34;烁&amp;#34;, &amp;#34;堂&amp;#34;, &amp;#34;唯&amp;#34;, &amp;#34;威&amp;#34;, &amp;#34;韦&amp;#34;, &amp;#34;雯&amp;#34;, &amp;#34;苇&amp;#34;, &amp;#34;萱&amp;#34;, &amp;#34;阅&amp;#34;, &amp;#34;彦&amp;#34;, &amp;#34;宇&amp;#34;, &amp;#34;雨&amp;#34;, &amp;#34;洋&amp;#34;, &amp;#34;忠&amp;#34;, &amp;#34;宗&amp;#34;, &amp;#34;曼&amp;#34;, &amp;#34;紫&amp;#34;, &amp;#34;逸&amp;#34;, &amp;#34;贤&amp;#34;, &amp;#34;蝶&amp;#34;, &amp;#34;菡&amp;#34;, &amp;#34;绿&amp;#34;, &amp;#34;蓝&amp;#34;, &amp;#34;儿&amp;#34;, &amp;#34;翠&amp;#34;, &amp;#34;烟&amp;#34;, &amp;#34;小&amp;#34;, &amp;#34;轩&amp;#34;} var lastNameLen = len(lastName) var firstNameLen = len(firstName) func GetFullName() string { rand.</description>
    </item>
    
    <item>
      <title>docker和二进制安装minio单机和集群</title>
      <link>http://hwholiday.github.io/2018/docker_install_minio/</link>
      <pubDate>Wed, 24 Oct 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/docker_install_minio/</guid>
      <description>Minio简介 Minio是一款高性能的分布式对象存储服务器，专为大规模私有云基础架构而设计 Minio是一个分布式对象存储服务器，Amazon S3兼容,用Go编写，在Apache License Version 2.0下开源 Minio为加密数据提供机密性，完整性和真实性保证，而性能开销可忽略不计。使用AES-256-GCM，ChaCha20-Poly1305和AES-CBC支持服务器端和客户端加密。加密对象使用AEAD服务器端加密进行防篡改。 详细简介请 点击这里 以下命令都需要管理员权限 sudo 搜索 gitlab Docker镜像 docker search minio //输出结果部分截图 NAME DESCRIPTION STARS OFFICIAL AUTOMATED minio/minio Minio is an Amazon S3 compatible object stor… 175 [OK] minio/mc Minio Client (mc) provides a modern alternat… 8 [OK] webhippie/minio Docker images for minio 3 [OK] pixelchrome/minio-arm This Dockerfile installs Minio on your ARM-P… 3 bbinet/salt-minion 2 [OK] zenithar/minio-server Minio.io Server in Alpine Linux docker 1 [OK] opennms/minion Application container runs Minion by OpenNMS… 1 [OK] jarfil/salt-minion Salt minion only 1 [OK] icereed/openshift-minio Minio packaged and compatible to Openshift a… 1 [OK] webcenter/alpine-minio The Minio Cloud Storage that work on Rancher.</description>
    </item>
    
    <item>
      <title>ubuntu 删除,修改,忘记passwd导致无法开机解决</title>
      <link>http://hwholiday.github.io/2018/del_or_update_passwd/</link>
      <pubDate>Mon, 22 Oct 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/del_or_update_passwd/</guid>
      <description>重启ubuntu，随即长按shirft进入grub菜单 选择ubuntu高级模式,选择一个带recovery mode的选项,有的人显示不太一样，选择最新内核回车即可 选择 root Drop to root shell prompt 依次执行如下命令 //修改权限 mount -o rw,remount / // 系统中的用户 ls /home //修改密码 passwd 用户名 //重启 reboot 如果修改文件过程中提示权限不够 lsattr /etc/passwd ----i---------e--- /etc/passwd chattr -i /etc/passwd //去掉不得任意更动文件或目录该效果 chattr +i /etc/passwd //添加不得任意更动文件或目录该效果 a：让文件或目录仅供附加用途。 b：不更新文件或目录的最后存取时间。 c：将文件或目录压缩后存放。 d：将文件或目录排除在倾倒操作之外。 i：不得任意更动文件或目录。包括root账户 s：保密性删除文件或目录。 S：即时更新文件或目录。 u：预防意外删除。 联系 QQ: 3355168235 </description>
    </item>
    
    <item>
      <title>从零开始微服务构建</title>
      <link>http://hwholiday.github.io/2018/micro_server/</link>
      <pubDate>Mon, 22 Oct 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/micro_server/</guid>
      <description>代码演示地址 点击这里 是使用Micro,etcd,nsq,grpc,gin等相关技术的一个微服务实例
只有一个gateway服务器，api节点,db节点,log节点都可以自由添加 log节点采用nsq,其他节点采用grpc,网关服务对外默认http #TODO 添加令牌服务器,链路追踪等功能,prometheus 架构图 启动命令 etcd nsqlookupd nsqd --lookupd-tcp-address=127.0.0.1:4160 nsqadmin --lookupd-http-address=127.0.0.1:4161 micro --registry=etcdv3 --broker=nsq api --handler=http 执行conf中的文件将配置信息读取到etcd中 启动api_agent,log_agent,db_agent curl http://127.0.0.1:8080/api/v1/test 查看整个程序的运行情况 log_agent db_agent api_agent 关于 Micro Micro 是一个微服务工具集。它被用来实现它的特性和接口，同时提供强大的可插拔的架构来保证基础组件可以被替换掉。 Micro 专注于解决构建微服务系统的基础需求。它采用了深思熟虑地富有预见性的方式来实现它的设计。 如果你想深入研究 Micro 工具集请点击这里 联系 QQ: 3355168235 </description>
    </item>
    
    <item>
      <title>我是如何把聊天数据迁移到mongodb</title>
      <link>http://hwholiday.github.io/2018/chat_mongodb/</link>
      <pubDate>Wed, 17 Oct 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/chat_mongodb/</guid>
      <description>背景 目前我在一家IM相关的公司上班，老的项目聊天数据没做相关的数据缓存直接存在的mysql数据库，经常链接数过多服务假死,所以现在我们在重构整个聊天项目 业务场景数据 由于要持久化redis中的用户消息数据，数据量比较大，写频繁。因为MongoDB的底层实现采用内存映射机制，因此非常适合大并发量的写。 由于用户的消息量非常大，因此要很方便的支持水平扩展。MongoDB的对水平扩展的支持非常好，并且支持自动分片　因为redis和Mongodb都是Nosql其他方面的属性差不多,所以我选择了用Mongodb来储存聊天数据 业务分析 单聊只会缓存离线数据，拉去一条离线就会删除一条，整体数据量不大 群聊会缓存全部的聊天数据，对与聊天信息比较多的群会７天新建一个collection同样存３０天的数据，聊天少的３０天为一个collection，超过的数据会导出为文本放在minio搭建的对象存储服务器上面(eg:可以看看我其他文章,了解minio搭建已经介绍) 其他 mongodb 最大可以创建多少 collection ？ 默认的情况下，MongoDB的每个数据库有24000左右命名空间的限制。 每个命名空间有628字节。.nsfile默认为16MB。 每个collection以及索引都算作namespace。因此如果每个collection有一个索引， 我们能创建12000个collection。 --nssize允许提升这个限制。 小心的是每个collection都会占用一些存储-很少的KB。更近一步说，任何的索引都需要至少8KB的数据空间， 也就意味着每个b-tree page大小为8KB. 如果有很多collection以及元数据经常要页输出，会导致核心的操作速度变慢。 --nssize 如果需要更多的collection，运行mongod --nssize参数。这个参数会让.ns文件更大， 支持更多的collection。注意的是 --nssize 用于最新创建数据库。如果你运行在一个存在的数据库， 希望重新定义大小，那么在运行--nssize之后，要运行db.repairDatabase()命令来调整大小。 .ns 文件最大为 2GB. 应用 collection单聊　名字我设置为single_用户id collection群聊　名字我设置为group_群id_年月日　通过年月日就可以判断是否需要新建或者存档数据 MongoDb 集群(副本集) mongod --nssize 500 --bind_ip 192.168.2.28 --port 27019 --dbpath /data/db_c --replSet howie/192.168.2.28:27017 mongod --nssize 500 --bind_ip 192.168.2.28 --port 27018 --dbpath /data/db_b --replSet howie/192.168.2.28:27019 mongod --nssize 500 --bind_ip 192.168.2.28 --port 27017 --dbpath /data/db_a --replSet howie/192.</description>
    </item>
    
    <item>
      <title>如何使用mongodb</title>
      <link>http://hwholiday.github.io/2018/how_use_mongodb/</link>
      <pubDate>Wed, 10 Oct 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/how_use_mongodb/</guid>
      <description>查找 Find m := bson.M{ &amp;#34;create_time&amp;#34;: bson.M{ &amp;#34;$gte&amp;#34;: start, &amp;#34;$lte&amp;#34;: end, }, &amp;#34;account&amp;#34;: account, &amp;#34;tag&amp;#34;: &amp;#34;tag&amp;#34;, } session.DB(&amp;#34;db&amp;#34;).C(&amp;#34;collect&amp;#34;).Find(m).Count() 这里查找时间戳内，账号为account，标签为tag的数据并统计个数。
聚合管道在mgo中为Pipe(pipeline interface{}) 这个和bash中使用的管道很像，数据可以被层层处理。一般传入的参数为[]bson.M。这个[]bson.M里如果还有嵌套则还要使用[]bson.M
比如这里首先匹配标签和账号 时间戳在一段时间内 然后根据名字分组统计数量 最后排序取最前面的三个。 //这个就可以传入Pipe m := []bson.M{ {&amp;#34;$match&amp;#34;: bson.M{&amp;#34;tag&amp;#34;: &amp;#34;tag&amp;#34;, &amp;#34;account&amp;#34;: account, &amp;#34;create_time&amp;#34;: bson.M{&amp;#34;$gte&amp;#34;: start, &amp;#34;$lte&amp;#34;: end}}}, {&amp;#34;$group&amp;#34;: bson.M{&amp;#34;_id&amp;#34;: &amp;#34;$TagName&amp;#34;, &amp;#34;count&amp;#34;: bson.M{&amp;#34;$sum&amp;#34;: 1}}}, {&amp;#34;$sort&amp;#34;: bson.M{&amp;#34;count&amp;#34;: -1}}, {&amp;#34;$limit&amp;#34;: 3}, } //这里就可以取到输出的数据 var values []result session.DB(&amp;#34;db&amp;#34;).C(&amp;#34;collect&amp;#34;).Pipe(m).All(&amp;amp;values) 简单介绍 package main import ( &amp;#34;gopkg.in/mgo.v2&amp;#34; &amp;#34;log&amp;#34; &amp;#34;gopkg.in/mgo.v2/bson&amp;#34; ) type User struct { Id bson.</description>
    </item>
    
    <item>
      <title>进程管理supervisor使用详解</title>
      <link>http://hwholiday.github.io/2018/supervisor/</link>
      <pubDate>Mon, 02 Apr 2018 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2018/supervisor/</guid>
      <description>安装 apt-get install supervisor
配置文件地址 /etc/supervisor/supervisord.conf 开始给自己需要的脚本程序编写一个子进程配置文件，让supervisor来管理它 放在/etc/supervisor/conf.d/目录下，以.conf作为扩展名（每个进程的配置文件都可以单独分拆也可以把相关的脚本放一起） 如任意定义一个和脚本相关的项目名称的选项组（/etc/supervisor/conf.d/etcd.conf） #项目名 [program:etcd] #脚本目录 directory=/home/howie/go/bin #脚本执行命令 command=/home/howie/go/bin/etcd -listen-client-urls http://192.168.2.28:2379 --advertise-client-urls http://192.168.2.28:2380 #supervisor启动的时候是否随着同时启动，默认True autostart=true #当程序exit的时候，这个program不会自动重启,默认unexpected #设置子进程挂掉后自动重启的情况，有三个选项，false,unexpected和true。如果为false的时候，无论什么情况下，都不会被重新启动，如果为unexpected，只有当进程的退出码不在下面的exitcodes里面定义的 autorestart=false #这个选项是子进程启动多少秒之后，此时状态如果是running，则我们认为启动成功了。默认值为1 startsecs=1 #日志输出 stderr_logfile=/tmp/etcd_stderr.log stdout_logfile=/tmp/etcd_stdout.log #脚本运行的用户身份 user = howie #把 stderr 重定向到 stdout，默认 false redirect_stderr = true #stdout 日志文件大小，默认 50MB stdout_logfile_maxbytes = 20M #stdout 日志文件备份数 stdout_logfile_backups = 20 运行 sudo /etc/init.d/supervisor start //启动 sudo /etc/init.d/supervisor stop //停止 sudo supervisorctl status //查看所有子进程的状态 sudo supervisorctl start etcd //开启指定的子进程： sudo supervisorctl stop etcd //关闭指定的子进程： sudo supervisorctl stop all //关闭所有的子进程： sudo supervisorctl start all //开启所有的子进程： web界面操作 需要在supervisor的配置文件里添加[inet_http_server]选项组</description>
    </item>
    
    <item>
      <title>docker安装gitlab</title>
      <link>http://hwholiday.github.io/2017/docker_install_gitlab/</link>
      <pubDate>Sat, 02 Dec 2017 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2017/docker_install_gitlab/</guid>
      <description>Gitlab简介 GitLab是由GitLab Inc.开发，使用MIT许可证的基于网络的Git仓库管理工具，且具有wiki和issue跟踪功能。 GitLab是一个Git的代码托管工具，有免费的社区版允许我们在本地搭建代码托管网站，也有付费的企业版网站，能够在线托管代码。 搜索 gitlab Docker镜像 sudo docker search gitlab //输出结果部分截图 NAME DESCRIPTION STARS OFFICIAL AUTOMATED gitlab/gitlab-ce GitLab Community Edition docker image based … 2165 [OK] sameersbn/gitlab Dockerized gitlab web server 1067 [OK] gitlab/gitlab-runner GitLab CI Multi Runner used to fetch and run… 409 [OK] twang2218/gitlab-ce-zh 汉化的 GitLab 社区版 Docker Image 149 [OK] gitlab/gitlab-ee GitLab Enterprise Edition docker image based… 115 jangrewe/gitlab-ci-android GitLab CI image for building Android apps 46 [OK] centurylink/gitlab This image uses the image from sameersbn / g… 26 [OK] gitlab/dind 24 [OK] 拉取 gitlab Docker镜像 sudo docker pull gitlab/gitlab-ce 启动Gitlab 启动一个默认配置的Gitlab。在本机测试使用的话，将-h替换为127.</description>
    </item>
    
    <item>
      <title>使用dockerfile部署你的第一个服务</title>
      <link>http://hwholiday.github.io/2017/docker_deploy/</link>
      <pubDate>Sat, 11 Nov 2017 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2017/docker_deploy/</guid>
      <description>VMware 安装Ubuntu 虚拟机不能联网 首先完全关闭ubuntu 还是找到unbutu，右键“设置”找到“网络适配器” 然后勾选“桥接模式”确定即可 下载openssh-server 使用远程服务 sudo apt-get install openssh-server 如果出现ifconfig命令没有反应的情况使用 sudo apt-get install net-tools 使用xsell登录到服务器 新建连接：输入(luinx)IP 端口为：22 输入用户名，密码 登录成功 安装docker准备(Docker 要求 Ubuntu 系统的内核版本高于 3.10 ) uname -r 查看Ubuntu 系统的内核版本 Dockerfile howie_api 与 Dockerfile同目录 FROM ubuntu ADD howie_api /var/howie_api //可执行程序 ADD conf /var/conf //配置文件 WORKDIR /var ENTRYPOINT [ &amp;#34;/var/howie_api&amp;#34;] build Docker docker build -t howie/api:v1 . 启动images sudo docker run -d -p 8070:8070 howie_api -d 后台运行 -p 输出端口 拷贝文件到docker sudo docker cp howie_api a62d89c48588:/var/howie_api 打开docker到文件 sudo docker exec -it a62d89c48588 &amp;#34;/bin/bash&amp;#34;; 挂载本地目录到容器和其他一些操作 docker run -d -p 8070:8070 -i -t -v /usr/local/howie:/var/howie ubuntu:16.</description>
    </item>
    
    <item>
      <title>第一次使用docker并安装mysql,redis（使用xshell操作）</title>
      <link>http://hwholiday.github.io/2017/ubuntu_docker_mysql_redis/</link>
      <pubDate>Fri, 10 Nov 2017 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2017/ubuntu_docker_mysql_redis/</guid>
      <description>1:下载openssh-server 使用远程服务
sudo apt-get install openssh-server 2:如果出现ifconfig命令没有反应的情况使用
sudo apt-get install net-tools 3:使用xsell登录到服务器
新建连接：输入(luinx)IP 端口为：22 输入用户名，密码 登录成功
4:安装docker准备(Docker 要求 Ubuntu 系统的内核版本高于 3.10 )
uname -r 查看ubuntu 系统的内核版本 5:安装docker
sudo apt install docker.io （PS:过程比较漫长~~~） sudo su service docker start docker version 6:安装mysql
1:查找mysql镜像
docker search mysql
2:下载镜像
docker pull mysql:5.6 （PS:过程比较漫长~~~）
3:启动mysql
docker run --name mymysql -p 3306:3306 -v /home/howie/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6 //注意，这里的容器名字叫：mymysql ，mysql的root用户密码是：123456 ，映射宿主机子的端口3306到容器的端口3306，本地持久化文件地址/home/howie/mysql/data,仓库名mysql和标签(tag）唯一确定了要指定的镜像，其实如果这里只有一个mysql也有必要要tag，执行该命令返回的结果 4:设置mysql让其可以外部链接
执行 mysql -uroot -p</description>
    </item>
    
    <item>
      <title>程序火焰图</title>
      <link>http://hwholiday.github.io/2017/flame_map_analysis/</link>
      <pubDate>Mon, 23 Oct 2017 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2017/flame_map_analysis/</guid>
      <description>程序火焰图 - git clone https://github.com/brendangregg/FlameGraph.git - 以下命令在FlameGraph里面执行 - yum install perf -y - perf record -F 99 -p 进程pid -g -- sleep 30 - perf report -n --stdio - perf script -i perf.data &amp;amp;&amp;gt; perf.unfold - ./stackcollapse-perf.pl perf.unfold &amp;amp;&amp;gt; perf.folded - ./flamegraph.pl perf.folded &amp;gt; perf.svg 联系 QQ: 3355168235 </description>
    </item>
    
    <item>
      <title>pprof使用</title>
      <link>http://hwholiday.github.io/2017/use_pprof/</link>
      <pubDate>Mon, 11 Sep 2017 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2017/use_pprof/</guid>
      <description>来查看正在使用的对象较多的个函数入口 top查看 go tool pprof --inuse_space http://127.0.0.1:8182/debug/pprof/heap 来查看累积分配内存较多的一些函数调用 top查看 go tool pprof --alloc_objects http://127.0.0.1:8182/debug/pprof/heap 查看25S内CPU的使用情况,分析函数耗时 top查看 go tool pprof --seconds 25 http://localhost:9090/debug/pprof/profile 查看svg数据（先安装graphviz） sudo apt-get install graphviz go tool pprof --seconds 25 http://localhost:9090/debug/pprof/profile //输出 Fetching profile over HTTP from http://localhost:9090/debug/pprof/profile profile?seconds=25 Please wait... (25s) Saved profile in /home/howie/pprof/pprof.test.samples.cpu.004.pb.gz File: test Type: cpu Time: Apr 26, 2019 at 3:32pm (CST) Duration: 25.08s, Total samples = 20.88s (83.24%) Entering interactive mode (type &amp;#34;help&amp;#34; for commands, &amp;#34;o&amp;#34; for options) (pprof) web //输入web　就可以在浏览器中看svg图了 当我们不明确这些调用时是被哪些函数引起的时，我们可以输入top -cum来查找，-cum的意思就是，将函数调用关系 中的数据进行累积，比如A函数调用的B函数，则B函数中的内存分配量也会累积到A上面，这样就可以很容易的找出调用链。</description>
    </item>
    
    <item>
      <title>ubuntu使用shadowsocks</title>
      <link>http://hwholiday.github.io/2017/ubuntu_use_shadowsocks/</link>
      <pubDate>Fri, 07 Apr 2017 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2017/ubuntu_use_shadowsocks/</guid>
      <description>安装shadowsocks 用PIP安装 sudo apt-get update sudo apt-get install python-pip sudo apt-get install python-setuptools m2crypto pip install shadowsocks 如果是ubuntu16.04 直接 (16.04 里可以直接用apt 而不用 apt-get 这是一项改进） sudo apt install shadowsocks shadowsock使用 推荐在/etc/shadowsocks下 新建config.json { &amp;#34;server&amp;#34;:&amp;#34;118.193.178.111&amp;#34;,//你的服务器IP &amp;#34;server_port&amp;#34;:60010,//服务器端口 &amp;#34;local_address&amp;#34;: &amp;#34;127.0.0.1&amp;#34;,//本地代理IP &amp;#34;local_port&amp;#34;:1080,//本地代理端口 &amp;#34;password&amp;#34;:&amp;#34;123qeq&amp;#34;,//密码 &amp;#34;timeout&amp;#34;:300,//过期时间 &amp;#34;method&amp;#34;:&amp;#34;aes-256-cfb&amp;#34;,//加密方式 &amp;#34;fast_open&amp;#34;: false, //默认 &amp;#34;workers&amp;#34;: 1//默认 } 使用命令:nohup sslocal -c /etc/shadowsocks/config.json &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp; 启动代理 如果使用supervosor控制程序可参考如下配置
[program:shadowsocks] command=sslocal -c /etc/shadowsocks.json autorestart=true user=nobody google浏览器配置 下载 https://github.com/FelisCatus/SwitchyOmega/releases 后缀为crx 打开chrome的设置&amp;gt;扩展程序，然后把插件拖进来安装 切换到switchyOmega主界面 &amp;gt; 新建情景模式 &amp;gt; 选择代理服务器 &amp;gt; 名称自己定义(shadowcocks) &amp;gt; 创建 &amp;gt; 应用选项 选择新建的情景模式 &amp;gt; 代理协议选择为SOCKS5 &amp;gt; 代理服务器输入127.</description>
    </item>
    
    <item>
      <title>我的博客是如何构建的</title>
      <link>http://hwholiday.github.io/2016/first/</link>
      <pubDate>Sun, 11 Sep 2016 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2016/first/</guid>
      <description>安装hugo（需要先安装go,git环境） 下载 https://github.com/gohugoio/hugo/releases 二进制文件或者hugo.exe Mac下直接使用 Homebrew 安装： brew install hugo 创建项目 hugo new howie /path/howie //创建项目howie,/path/howie为路径 进入 /path/howie 目录 结构为 ▸ archetypes/ ▸ content/ ▸ layouts/ ▸ static/ config.toml 创建第一篇文章，放到 post 目录，方便之后生成聚合页面。
hugo new post/first.md 打开编辑 post/first.md ：
--- date: &amp;#34;2018-10-12&amp;#34; title: &amp;#34;first&amp;#34; --- testtesttesttesttesttest 安装皮肤这里以（Leaveit）为例子 cd themes git clone https://github.com/liuzc/LeaveIt.git 为了更好的使用该主题我们将post/first.md的头部改为
--- date: 2018-10-11 title: &amp;#34;我的博客是如何构建的&amp;#34; description: &amp;#34;我的博客是如何构建的&amp;#34; tags: [&amp;#34;其他&amp;#34;, &amp;#34;golang&amp;#34;] categories: [&amp;#34;其他&amp;#34;] --- 启动 hugo server --theme=LeaveIt --buildDrafts 浏览器里打开： http://localhost:1313 配置 根据主题配置分享下我的配置 baseurl = &amp;#34;http://hwholiday.</description>
    </item>
    
    <item>
      <title>常用开源协议</title>
      <link>http://hwholiday.github.io/2016/open_source_agreement/</link>
      <pubDate>Sat, 03 Sep 2016 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2016/open_source_agreement/</guid>
      <description>常用协议： Apache License 2.0
要点：Apache Licence是对商业应用友好的许可。使用者也可以在需要的时候修改代码来满足需要并作为开源或商业产品发布/销售。
BSD开源协议（Berkerley Software Distribution）
要点：商业软件可以使用，也可以修改使用BSD协议的代码。
GPL ( GNU General Public License )
要点：商业软件不能使用GPL协议的代码。
LGPL ( GNU Library or &amp;ldquo;Lesser&amp;rdquo; General Public License )
要点：商业软件可以使用，但不能修改LGPL协议的代码。
MIT ( MIT license )
要点：商业软件可以使用，也可以修改MIT协议的代码，甚至可以出售MIT协议的代码。
MPL ( Mozilla Public License 1.1 )
要点：商业软件可以使用，也可以修改MPL协议的代码，但修改后的代码版权归软件的发起者。
CDDL (Common Development and Distribution License )
要点：商业软件可以使用，也可以修改CDDL协议的代码。
EPL (Eclipse Public License 1.0 )
要点：商业软件可以使用，也可以修改EPL协议的代码，但要承担代码产生的侵权责任。
联系 QQ: 3355168235 </description>
    </item>
    
    <item>
      <title>Android实用插件</title>
      <link>http://hwholiday.github.io/2016/android_idea_plugin/</link>
      <pubDate>Sun, 10 Apr 2016 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2016/android_idea_plugin/</guid>
      <description>top：1 Android ButterKnife Zelezny ButterKnife是一个专注于Android系统的View注入框架,可以减少大量的findViewById以及 setOnClickListener代码，可视化一键生成。
top:2 GsonFormat GsonFormat是一个快速格式化json数据,自动生成实体类参数的插件。(对于返回的数据格式是json，简直不能再好用)
top:3 Android Postfix Completion 可根据后缀快速完成代码。(log,toast，神技能)
top:4 Codota 基于安卓代码搜索引擎是有以色列理工大学毕业生制造的一个可以在网上发现的代码案例，帮助开发人员可以节省开发者大量的工作时间，通过专业的代码搜索引擎可以更方便的查询想要的代码。
top:5 Lifecycle Sorter 可以根据Activity或者fragment的生命周期对其生命周期方法位置进行先后排序。
top：6 Android Drawable Importer 为了适应所有Android屏幕的大小和密度，每个Android项目都会包含drawable文件夹。任何具备Android开发经验的开发人员都知道，为了支持所有的屏幕尺寸，你必须给每个屏幕类型导入不同的画板。Android Drawable Importer插件能让这项工作变得更容易。它可以减少导入缩放图像到Android项目所需的工作量。Android Drawable Importer添加了一个在不同分辨率导入画板或缩放指定图像到定义分辨率的选项
top:7 Material Theme UI 如果你使用的是android studio 那么这个无疑会让你的编辑器，b格上升一个档次（个人喜爱。。。）
top：8 ECTranslation 翻译插件，可以再IDE里直接翻译单词，对于我们这些英语小菜鸡简直是神器。
top：9 Sexy Editor 设置Android Stuido 代码编辑区的背景图
top:10 JsonOnlineViewer 可实现直接在android studio中调试接口数据，可以选择请求类型，自定义请求头及请求体，json数据格式化后展示
top:11 CodeGlance 在右边可以预览代码，实现快速定位
top：12 SelectorChapek for Android 通过资源文件命名自动生成Selector文件
top:13 .ignore .gitignore 配置文件用于配置不需要加入版本管理的文件，配置好该文件可以为我们的版本管理带来很大的便利 1、配置语法： 以斜杠“/”开头表示目录； 以星号“*”通配多个字符； 以问号“?”通配单个字符 以方括号“[]”包含单个字符的匹配列表； 以叹号“!”表示不忽略(跟踪)匹配到的文件或目录； top:14 Material Design Icon Generator 第三方的图标库，很多实用好看的icon提供使用</description>
    </item>
    
    <item>
      <title>Android开发 你应该知道的adb 命令</title>
      <link>http://hwholiday.github.io/2016/android_adb/</link>
      <pubDate>Thu, 03 Mar 2016 00:00:00 +0000</pubDate>
      
      <guid>http://hwholiday.github.io/2016/android_adb/</guid>
      <description>个人建议配置环境变量时在Path类加入 你sdk的存放目录\platform-tools
启动cmd
1：启动adb
adb start-service 2：停止 adb server
adb kill-server 3：显示当前运行的全部模拟器
adb devices 4：列出手机装的所有app的包名
adb shell pm list packages 5：列出系统应用的所有包名
adb shell pm list packages -s 6：列出除了系统应用的第三方应用包名
adb shell pm list packages -3 7：安装应用程序
adb install -r 应用程序.apk 如果不是当前目录，则后面要跟路径名 8： 卸载软件
adb uninstall 应用程序.apk adb uninstall -k 应用程序.apk如果加 -k 参数,为卸载软件但是保留配置和缓存文件.如果不是当前目录，则后面要跟路径名 9：获取序列号
adb get-serialno 10： 获取管理员权限：
adb root 11：查看adb命令帮助信息：
adb help 12： 进入模拟器的shell模式：
adb shell 13：查看最上层成activity名字
adb shell dumpsys activity | findstr &amp;#34;mFocusedActivity&amp;#34; 14：获取 MAC 地址</description>
    </item>
    
  </channel>
</rss>
