<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>文章 on 华说记录我的生活</title>
    <link>http://www.huasay.com/posts/</link>
    <description>Recent content in 文章 on 华说记录我的生活</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh</language>
    <lastBuildDate>Tue, 07 Nov 2023 16:29:12 +0800</lastBuildDate>
    <atom:link href="http://www.huasay.com/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>我与工作那些事</title>
      <link>http://www.huasay.com/2023/11/07/things_related_to_work/</link>
      <pubDate>Tue, 07 Nov 2023 16:29:12 +0800</pubDate>
      <guid>http://www.huasay.com/2023/11/07/things_related_to_work/</guid>
      <description>入职这家公司已有半年，想想半年前，还在上海，待业半年之久，那段有点失意的日子，让我的心态，变得很佛系。人的一生，不需要一直工作，那样疲于奔命，最终的结果也不一定是自己期待的。半年从眼前瞬然流逝，在这公司的半年融合下，也认识一些朋友，但始终不觉得这家公司是我的归宿，满满的不安全感。
论职场，虽然以我的工龄，像是个职场老手，但实际上，却很单纯。因为自己的性格，从不喜欢向上管理，也从不喜欢去管理别人，所以，最终到头来，我还是个兵。在职场上，老兵也是个兵，却比不上新兵蛋子了，那股冲劲，显然都是一股要把前浪拍死在沙滩上的，所以，这一行，老兵很难，一旦所谓的降本增效来临，那老兵大概率会被拍出去。
有的人不甘于做老兵，当然，有那能力谁去做老兵呢，做个管理兵的管理层干部，不是也挺好的么。只是，这种场面，更多的需要口才，需要PPT，显然，很多老兵不适合，那怎么办呢？只能继续做个兵。然而以兵作为自己的归宿，大概率会以悲剧收场。在人才爆棚的今天，老兵又该以什么样的方式自处，又该以怎么样的试去生存，是个难题，也是大多数老兵在失去工作后，短期内无法找到工作的原因。
说回正题，我与工作的那些事，嗯，工作上的事情让我有点不知所措。首先，公司开始人事上的变动，这种变动最直接的就是上层领导的改变，原先的架构师在新的总监过来之后，不适应准备撤离。而由架构师主导的项目，尤其是我这边的工作内容，就变得非常多余。这种多余体现在人力资源的投入上，公司今后的发展方向上，这些都不匹配，导致我现在的处境是做也不是，不做也不是，没人发话说这不做，可以停下手上的工作，也没人发话说这要做，继续做，没个明确的目标，这确实让我有点混乱。当然，以我的佛性心态来讲，我并不在乎有没有事情做，我更在乎的是有没有钱拿。
关于工作，也谈谈与这家公司的磨合，半年的磨合，其实同事关系处得还可以，但和架构师的相处方式，让我一直很被动，我有时候甚至不理解架构师的思想与思路，或许是对更多的理论缺少概念导致的吧。面对一大堆理论，有的甚至都没听说过，所以理解起来困难，节奏一直把握不对。但我觉得架构师人还是不错的，除了脾气差点外。</description>
    </item>
    <item>
      <title>for 循环中使用defer的方案</title>
      <link>http://www.huasay.com/2023/11/07/for_defer_usage/</link>
      <pubDate>Tue, 07 Nov 2023 10:47:43 +0800</pubDate>
      <guid>http://www.huasay.com/2023/11/07/for_defer_usage/</guid>
      <description>defer 的作用用于延迟处理，在golang中，它一般在方法即将结束返回时调用, 因此，我们使用defer最多的场景就是对资源的释放，这种资源包括连接资源(http连接，数据库连接等)，文件资源(file相关)，锁资源(sync.mutex), 对资源的释放处理不受panic的影响，意思就是方法体内即使有panic，也阻止不了defer的执行。除了对资源的释放外，defer的第二大用处就是用于捕获异常。当然，常规的使用这些，都不是我们这篇文章的重点。
在引言中, 提到了两个defer最常用的使用场景, 虽然不是这篇文章的重点，但可以简单的回顾一下。
defer的常用使用场景 释放资源 - 释放锁资源 func DoSomething(mu *sync.Mutex, s []string) {mu.Lock()defer mu.Unlock()s = append(s, &amp;quot;test&amp;quot;)}释放资源 - 释放数据库连接资源 func fetchDataFromDB() error {db, err := sql.Open(&amp;quot;mysql&amp;quot;, &amp;quot;user:password@/dbname&amp;quot;)if err != nil {return err}defer db.Close() // 确保数据库连接在函数结束时被关闭// 执行数据库查询操作// ...return nil}资源释放 - http资源释放 // 最容易遗忘导致内存泄露的场景resp, err := http.Get(&amp;quot;https://example.com&amp;quot;)if err != nil {// 错误处理return}defer resp.</description>
    </item>
    <item>
      <title>父亲</title>
      <link>http://www.huasay.com/2023/11/06/father-2023/</link>
      <pubDate>Mon, 06 Nov 2023 16:51:36 +0800</pubDate>
      <guid>http://www.huasay.com/2023/11/06/father-2023/</guid>
      <description>近些年，与父亲极少交流，究其原因，我个人觉得我们都是有点小脾气的人，而有些事情，却无法释怀，或者没有通过言语心平气和的聊一聊，从而导致我们之间的隔阂越来越大。我承认我的不作为，不受控的情绪，这些让他从心底里对我失望，我们之间的气氛总是冷冷的。
父亲，一个20岁左右就一直在外漂泊近半生的泥水工人。在我印象里，对父亲的记忆很模糊。从记事起，他就在外面打工，一年回来个一两次，见面机会甚少，当然，现在的我也很能理解那种在外奔波养活一家人的不易。只是打小的记忆里，我一直渴望有父爱在身边。但又不得不必须接受事实，珍惜每年一两次的相聚。
父亲是个乐天派，喜欢和别人开玩笑，也喜欢开自己玩笑，而我与母亲却都是寡言的。我羡慕父亲的那种大大咧咧的性格，一直在想，为何我没有继承父亲这点，而是个沉闷的葫芦, 也许这点也是他与我共同的遗憾吧，我确实没能像他一样，能够处理好各种人际关系。而我在职场或者在社会上，缺得正是这点，也因为自己的内向懦弱，失去了很多机会。
父亲也慢慢的老了，我能清晰的看见头发花白的他，有点憔悴，少了年轻时的意气风发。而在花甲之年，还在为生活奔波，在工地上奔波，也许，在他这年纪，他是希望看到儿子能够成家立业，能够结婚生子，是该享受儿孙满堂带来的幸福的时光。而我一直以来给他灌输的思想是我不想结婚，我只想做自己，不想被束缚。这点，显然是他的雷区，每次交谈中，我能看出他眼中的光灭了，这种场景通常以我的沉默而结束，以他的失望而告终。我们慢慢疏远，这种疏远，我觉得是一种愧疚，一种无颜以对，也是一种无可奈何。
这一年，2023，我迎来了我事业上面的最低谷期，而我极力想去改变，却改变不了，这让我有点心灰意冷。挫败感让我更加的不想面对家里的压力。而这漫长的时期，也与父亲竟然有长达8月之久未联系。这点毋庸置疑是我的问题。在很长的日子里，我是害怕让他们看到我的颓废的。10.1过后，父亲借着母亲来看我的机会，母亲说父亲带了点家乡的菜，她到时候给我带点过来，事实上，我一直以为就母亲一人过来，我有点诧异，也有点愧疚，就在附近的一家衢州菜馆里，聚上我们年后的第一顿饭。我们都收起了锋芒，父亲也知道我的处境，也没提任何关于婚姻或者结婚上的见解。那一顿饭，我吃得很满足。饭后，他们顺便到我住处看看，我住的还行，比我在上海时期住的好很多，看我买的锅不行，父亲说他给我整口锅过来，事实上，我不太会做饭，有时候根本也不想做饭，但也不想辜负父亲的一片好意。
希望父亲这一辈子都能身体健康，也希望我们能互相理解与成全。也许人生就这样，没有完美，只能尽可能的互相包容。当历史碾过百年，我们依旧是父子，只是所有的不愉快都会被尘埃拂过。而下辈子，希望你能拥有如你所期的那样的孩子，带给你幸福。</description>
    </item>
    <item>
      <title>权限控制 - Casbin</title>
      <link>http://www.huasay.com/2023/09/14/casbin/</link>
      <pubDate>Thu, 14 Sep 2023 16:58:10 +0800</pubDate>
      <guid>http://www.huasay.com/2023/09/14/casbin/</guid>
      <description>最近在研究 iam 相关的内容，iam 即身份访问管理(identify access management) 身份: 用户在整个系统体系中扮演什么样的角色 访问管理：对身份的权限控制。 那既然谈到权限控制，不得不谈谈 casbin, casbin 目前是 github 上在权限控制处理方面 star 数是最多的，虽然之前没接触过 casbin,但也调研了一段时间，从易用性，扩展性，实现上来谈谈 casbin。
核心概念 权限模型目前主流的主要包括acl, rbac, abac。 简单先从这几个模型说起。而了解这几个模型之前，我们先约定一下一些术语。
subject 主体，在一般的权限体系中，主体一般是指操作者，比如某个用户，某个角色(其实角色最下面也是个用户)，当然更广义的讲，可能主体也可以代表其他需要约束的对象，比如在物联网中，他也可以代表一个iot设备。 resouce 资源，一切可操作的实体都可以当做是一种资源，比如aliyun上的我们购买的ecs实例，后台系统的一个user action 操作，主体对资源的操作，比如我们可以对ecs实例进行开机，关机，重启等操作，可以新增，删除，编辑一个user。 condition 操作的条件，一般基于主体与资源的约事条件，比如 user 的ip必须在172.168.0.1/24的段内 effect 影响效力，一般只有allow(允许)/deny(不允许) 有了这些术语，我们去解释对应的权限模型，可能更知道不同模型的区别 ACL acl(访问控制列表)，他代表的是，哪些用户（subject）或系统进程可以访问(action)资源(resource) 如果某个文件 apple.jpg（resource） 的 ACL 包含（Alice(subject): read(action),write(action)；Bob(subject): read(action)），这将赋予 Alice 读写文件的权限，而只赋予 Bob 读取文件的权限。
RBAC ABAC casbin 中的概念 理解casbin，最主要理解其核心思路，casbin中的核心思路是使用policy(策略)中的规则去应用到model(模型)中，model 是一个规则引擎，帮我们处理一个主体(subject)是否有操作(action)某个资源(subject)的权限。
policy策略：一组规则的集合, 规则 model模型：对每行规则进行解析
因此，对于我们使用者来说，大多时候仅仅只需要关注policy和model就行。
model 初览 在model层面，casbin又基于 PERM (Policy, Effect, Request, Matcher). 一个完整的model(perm)文件格式如下：</description>
    </item>
    <item>
      <title>swagger的使用</title>
      <link>http://www.huasay.com/2023/08/27/swagger_usage/</link>
      <pubDate>Sun, 27 Aug 2023 21:20:10 +0800</pubDate>
      <guid>http://www.huasay.com/2023/08/27/swagger_usage/</guid>
      <description>随着RESTful API的流行，Swagger已经成为了一种通用的API描述和文档格式。它可以帮助开发者描述、测试和文档化RESTful API。在本文中，我们将介绍在go中如何使用相应的库生成swagger文档。在golang中, 有两款可以生成swagger的库，一般我们选择https://github.com/swaggo/swag,还有另一款https://github.com/go-swagger/go-swagger,相对来说，使用起来swag更易用一点
安装 1 go install github.com/swaggo/swag/cmd/swag@latest 默认情况下，会安装在go path相关的目录下，该目录一般已经加入环境变量，若没有加入环境变量，我们可根据每种系统的不同，手动加入至环境变量中
检测是否安装成功：
1 swag -v 返回具体的版本号即成功:
1 swag.exe version v1.8.12 使用 路由绑定 我们使用的是gin框架，swag对gin也有集成封装, 我们可以在gin的路由绑定至对应的swagger文档
1 2 3 // swagger文档查看路径 url := ginSwagger.URL(&amp;#34;/swagger/doc.json&amp;#34;) // The url pointing to API definition r.GET(&amp;#34;swagger/*any&amp;#34;, ginSwagger.WrapHandler(swaggerFiles.Handler, url)) 依赖库：
1 2 swaggerFiles &amp;#34;github.com/swaggo/files&amp;#34; &amp;#34;github.com/swaggo/gin-swagger&amp;#34; 路由注释 1 2 3 4 5 6 7 8 9 10 // ListUser // @Summary 查询用户信息 // @Tags 用户 // @Description	查询用户信息 // @Produce	json // @Param UserId header string true &amp;#34;当前用户id&amp;#34; // @Param query query dto.</description>
    </item>
    <item>
      <title>go分享</title>
      <link>http://www.huasay.com/2023/05/24/share-go-routine/</link>
      <pubDate>Wed, 24 May 2023 22:49:21 +0800</pubDate>
      <guid>http://www.huasay.com/2023/05/24/share-go-routine/</guid>
      <description>go的goroutine go中最重要的概念之一就是协程，协程的创建方式也很简单，go func()就简单的创建了一个协程，虽然go语言中并没有规定协程的 创建数据限制，每个协程相对于线程的成本也很低，协程最小占用只有2Kb， 1000个协程才2M，所以成本极低。
但创建容易的同时也应该注意以下几点：
对于panic捕获的安全性 我们一般使用go func()直接创建协程了，但一般在代码中，很少直接这么使用，一般会在外面再封装一层。具体的封装方式类似这样：
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package thread import ( &amp;#34;fmt&amp;#34; &amp;#34;runtime/debug&amp;#34; ) func GoSafe(fn func()) { go RunSafe(fn) } func RunSafe(fn func()) { // 可以將panic上报给sentry等报警平台，或者钉钉，飞书机器人的钩子等 defer func() { if p := recover(); p != nil { fmt.Printf(&amp;#34;RunSafe capture crash,msg: %s \n %s &amp;#34;, fmt.Sprint(p), string(debug.Stack())) } }() fn() } 原因很简单，go语言外层的defer是捕获不了内部goroutine的异常的，所以如果内部的goroutine发生panic，那会导致整个程序直接crash。 因此，使用goroutine的话最好再加一层安全封装，以防止潜在的panic导致的crash。</description>
    </item>
    <item>
      <title>Yaml 语法</title>
      <link>http://www.huasay.com/2023/05/18/yaml-synax/</link>
      <pubDate>Thu, 18 May 2023 23:30:48 +0800</pubDate>
      <guid>http://www.huasay.com/2023/05/18/yaml-synax/</guid>
      <description> yaml是工作中遇到比较多的标记语言，特别在k8s横行其道的年代， yaml简直就是标配， 到处都是yaml。yaml的语法还是简单的，在此只 是做点小记录
yaml的基本使用 简单的对象关系 1 name: &amp;#34;hua&amp;#34; ## 在同一行，:后一定要加空格 行内对象嵌套关系 1 info: {name: &amp;#34;hua&amp;#34;, age: 32} 数组关系 1 2 3 - Bird - Cat - Dog 行内数组 1 animals: [Bird, Cat, Dog] 子数组 1 2 3 4 - - Bird - Cat - Dog </description>
    </item>
    <item>
      <title>网关traefik入门级使用</title>
      <link>http://www.huasay.com/2023/05/12/gateway-traefik-usage/</link>
      <pubDate>Fri, 12 May 2023 20:42:55 +0800</pubDate>
      <guid>http://www.huasay.com/2023/05/12/gateway-traefik-usage/</guid>
      <description>基本概念 EntryPoints EntryPoints 是进入traefik的入口点，定义端口接收数据包，可以是tcp也可以udp的包。 Routers Middlewares 附加在路由之上，中间件可以在发送至后端服务器之前处理请求或响应。 Services 简单部署 可以写一个docker-compose.yaml文件编排traefik与后端服务whoami
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 version: &amp;#39;3&amp;#39; services: reverse-proxy: # The official v2 Traefik docker image image: traefik:v2.10 # Enables the web UI and tells Traefik to listen to docker command: --api.insecure=true --providers.docker --accesslog=true ports: # The HTTP port - &amp;#34;80:80&amp;#34; # The Web UI (enabled by --api.</description>
    </item>
    <item>
      <title>网关traefik调研</title>
      <link>http://www.huasay.com/2023/05/11/gateway-traefik/</link>
      <pubDate>Thu, 11 May 2023 21:30:20 +0800</pubDate>
      <guid>http://www.huasay.com/2023/05/11/gateway-traefik/</guid>
      <description></description>
    </item>
    <item>
      <title>网关gloo调研</title>
      <link>http://www.huasay.com/2023/05/08/gateway-gloo/</link>
      <pubDate>Mon, 08 May 2023 22:12:37 +0800</pubDate>
      <guid>http://www.huasay.com/2023/05/08/gateway-gloo/</guid>
      <description></description>
    </item>
    <item>
      <title>跨城搬家</title>
      <link>http://www.huasay.com/2023/04/27/move-house-over-city/</link>
      <pubDate>Thu, 27 Apr 2023 23:22:11 +0800</pubDate>
      <guid>http://www.huasay.com/2023/04/27/move-house-over-city/</guid>
      <description>上海，我终究没有留下来，在失业长达半年之久，期间拿到惟一还算可以的offer竟然是在杭州。怀着复杂的心情，没有任何选择的情况下， 准备离开上海。
选择方案 以往的搬家，基本上都是同城叫个货拉拉，东西少的话自己搬，东西多的话请师傅搬，不得不说，搬家是个累活。这次是个跨城搬家，东西还有点多， 在出发之前，我在想，我该以怎样的方式从上海搬到杭州，我自己给自己想了几种方案。
方案一： 不贵重的东西走物流，我称了称我那至少8大箱的东西，大概的重量已经超过100kg了，价钱也至少得150以上了，还是在没任何保价的情况下。 贵重的东西走顺丰，我一个台式电脑，走顺丰，发现如果要保价就要80了。就单单一个台式电脑而已 人和猫走顺风车，看了下顺丰车的价格，大概也是不到150. 那整体的总价大概是要400出头了。缺点也是费时费力不省心。
方案二： 走朋友的车，杭州的一位朋友说帮我搬家，但着实东西有点多，其实他来回成本还是蛮大的，而且小车也放不下，我放弃了。
方案三： 货拉拉等跨省搬家方案，货拉拉是最便宜的，大概是在450，如果不算高速费的话，加上高速费80的话，那就是总价要530了。 但整体是省时省力的，没有过多的折腾。货拉拉相比其他的，比如快狗，滴滴都便宜不少，比滴滴便宜30左右，比快狗便宜300. 还问了一些蚂蚁搬家之类的，搬过来一口价都是800-900的样子，着实搬不起。看来货拉拉对于跨省搬家还是首选。
最终我是选择了方案三。
意外 对于货拉拉，之前同城搬家也搬过，但都是走平台的。但出发前5小时，司机突然告诉我他有事不能跑，问我能不能让他朋友来接。 但我的建议是，如果有事，那么我重新下单，我还是希望走平台的，我怕不走平台之后会有各种扯皮。小哥有点不高兴，觉得不走平台还 可以给我便宜点，但信任始终是个问题，最后他还是决定接下单自己亲自来跑。其实我不关心是否他亲自跑，我只想走平台而已，他 可以让他朋友代跑，但不能不走平台，仅此而已。最终小哥的选择是他亲自跑，他的其他事(说的是送朋友回苏州)让他朋友代劳，这整 得我多少有点不近人情。但我也想给自己的麻烦创造的少点。
迟到 不知道小哥是否因为早上的事生气，本来原定14:30的车，在14:10分左右我问他能不能准时到，他说能准时到。事实上我已经都准备得差不多了， 就等着小哥来装车了。小哥硬是让我等了30分钟左右，到15点才走。这多少让我心里有点郁闷，但也不想多说了，毕竟时间不早，我也没 有能力再去换车了。这迟到的车过来，我很心急的一通搬，果然忘记掉东西了，把我的自行车忘记在了上海。虽然也1年没骑过了，但 还是我的爱车啊，不过在上海那边也没人，而且寄自己车也贵，也只能让他在那边呆着了
路途 路途遥远，全程大概有180多公里，导航上都要快3个小时才能到。在五一的前夕，还是避免不了堵车，在上海上高架前的路堵了10多分钟。 好在还有一天才到五一放假，因此高速上还是能一路畅通。在行至一段高速后，小哥说他的电车电池需要充下电，大概要30分钟，嗯，又在 路上的服务区充了30分钟电，本来预估3小时能到的，到那边整整到19点了简直是超预期。
酒店 终于到了，酒店的小姐姐给拉了推车，还有司机的推车借着用了一下。顺利到家的感觉真好，只是，真得很累。同时也在为5.1之后的放职而 担忧，长时间的不工作真得没有任何工作状态了吧。希望接下来职场能顺利些。
关于价钱 货拉拉450 + 高速费 80，花了530. 为什么货拉拉比传统的搬家便宜，我问了司机，司机告诉我，他们也不是靠拉个人单活着的。 还会拉企业的仓库单，因此，到杭州这边，他就一直在接杭州回上海的单，如果能顺利接到，其实也是不亏的，毕竟杭州回上海的单也 得有200以上才行，司机小哥拒绝了一单160的，觉得200以上接了才划算吧。</description>
    </item>
    <item>
      <title>入职体检</title>
      <link>http://www.huasay.com/2023/04/26/orientation-health-check/</link>
      <pubDate>Wed, 26 Apr 2023 22:38:19 +0800</pubDate>
      <guid>http://www.huasay.com/2023/04/26/orientation-health-check/</guid>
      <description>接了杭州的公司的offer，公司要求是要到三甲医院体检，所以又在即将入职时刻，快速找家三甲医院体验。从小红书上找了对应的攻略， 怎么快速一天内拿到体检报告。
医院选择 附近近点的三甲医院有复旦大学附属华山医院，上海六院，复旦大学附属中山医院。比较了三种入职体检的攻略，六院是只能看到普通体验， 华山是不知道一天之内能不能拿到，而且价格在270多，中山医院看小红书攻略，相比较来说，价格上便宜，只要200，最关键的是能一天之内完成。
流程 带好1寸照，7点半左右到医院，去预约体检，并且缴费 按照给的体检流程体检 先抽血，个人是体验了一把机器抽血，医生会判断血管大小是否合适，合适的可以走机器验血。不合适的走常规验血 我以为机器验血会很快，就过去排队，前面也就6-7个人，结果排了我半个小时以上。我觉得可能比传统的抽血还要慢。 个人预估一个人在5分钟左右，要是血管不行的，那估计还得慢 抽完血去尿检，直接去就行，我这笨蛋傻乎乎的等了好久，以为要先取东西 去做x光胸片，这个报告很费时间，其实可以一开始就去检查，他出结果比抽血慢的 去做其他的常规项，有些就很快，医生知道你是来体检的，直接写参数了 大概整体流程早上11点左右就完成的差不多了，就等血常规，x片报告 拿到报告后去服务台盖章，如果需要发票去二楼自助机上去取，以便以后报销 感想 整体还是很快的，一个早上就可以拿到体检报告，如果有急需的，就去尝试尝试。相比第三方机构体检来说，体检报告就一张纸，出报告快， 价格偏贵一点。</description>
    </item>
    <item>
      <title>退租记</title>
      <link>http://www.huasay.com/2023/04/22/renting-cancellation-record/</link>
      <pubDate>Sat, 22 Apr 2023 21:15:22 +0800</pubDate>
      <guid>http://www.huasay.com/2023/04/22/renting-cancellation-record/</guid>
      <description>下定决心接了杭州公司的offer，上海的房子还有两月才到期，自己一开始也没想特别清楚，怎么才能让自己的损失最小，没有特别好的解决 方案，房东就开始催收下一期的房租了。
对于退租，以往每次都是必会吃亏，所以这次也是在想有没有什么好的方法。按照以往的经验，房东会让我自己找到接手的租客，才能退押金。 而我本身也不是个谈判能手，因此在挣扎许久之后，还是没能想到两全其美的办法，惟一的希望竟寄托在房东身上，指望望房东能够善良。
房东是一个近70左右的老人，据上一代租客说，房东在上海拥有几套房子，人很好，不缺钱，不计较。基于这些，我甚至抱了一丁点希望，希望 这个本土拥有几套房子的房东能够宽容些。 但正是这一丁点希望，也让我彻底认清，人的欲望是无止境的，不是你现在70了就无欲无求， 不是你现在有几套房就可以躺平。
具体的谈判，我个人是给出了折衷的方案，告诉房东，我没时间去找租客接手，我自愿放弃押金。还有我这期我只能租半个月，我只付半个月的 房费，对于我来说，其实我已经给出了让步了，因为我根本租不到半个月，最多10天。第二，我放弃押金，相当于我违约，我也认。 但房东似乎很抗拒，抗拒到什么程度呢？认为我应该早点说（我怎么早点说呢？我也只能拿到offer后才能说吧），还有就是我应该自己挂转租出去， 帮他转租，尽管我耐心的解释我违约了，押金不要了，但老人家似乎觉得我在坑他，觉得我押金既不要，还得花时间去帮他转租，甚至还要我支付一个月的 房费，我都这个月只住10天而已，就想让我预付一个月，让我去承担他可能用的空窗期风险。我一整个人呆住了，两人僵持了一会，他让我 室友想法子，室友让我预支水电网费，简直了，你们两真是祸害下一个租客去吧，我也懒得折腾，水电网费我预支了800(两个月没付 + 现在住的10来天的)，真是 一点亏他们都不想吃，也是绝了。
所以，租房真得很难，没有几个房东真得会为租客考虑，他们只会考虑他们是否有空窗期，如果你押一付三，第一个月因为有事要离开这个城市， 嗯，他们就恨不得付二押一的钱全不想给你，就想让你承担房子空窗的风险，他们啥时候找到接手了才会给你，但理论上最多押金扣下而已。 我不知道国家对这样的房东会这样处置，我已经对现在的租房市场心如死灰。无论是二房东还是一房东，都是看房东人品的，并没有所谓的一房东 就可以好说话，实际上甚至比二房东还难说话。下次租房还是要谨慎点，特别别人转租的那种，还是和人合租的，千万不要轻信转租的人的话。</description>
    </item>
    <item>
      <title>跑之伤，伤之痛</title>
      <link>http://www.huasay.com/2023/04/07/run_hurt/</link>
      <pubDate>Fri, 07 Apr 2023 16:31:48 +0800</pubDate>
      <guid>http://www.huasay.com/2023/04/07/run_hurt/</guid>
      <description>在失业的焦虑与愈来愈肥的双重夹击下，本想让自己动起来，来缓解这些负面因子，未曾想到，最终的结果却是让自己躺了一个月，真是可悲可气。 有时候，在你准备奋起的时候的打击，是致命的，这打击，直接让我颓了。
计划 我原本的计划是一周跑三次，每次跑3公里-5公里，状态不好跑3公里结束，身体状态不错就多跑点。 计划是否很完美？就这样履行计划才两周，也就是只跑了6次，不幸的事情就发生了。
逞能的代价 天气一般，有点冷风。我很纠结要不要出去跑，毕竟如果坚持不下去，那一切都毫无意义。但内心却是极度不愿意，不是出于身体的累，仅仅是觉得 这天气不太适合出去，毕竟跑步穿得很少，很薄，多多少少会有点冷。但本着坚持的理念，还是去了。
跑逆风时，风阻力是真大，所以跑得并不快。大概配速也就7公里/小时的速度。但两圈跑下来，却觉得下腿很难受，在想要不要继续坚持跑一圈， 就是这次坚持，让自己损失大发，咬着牙跑完了，都没力气做拉伸，因为腿部当时就不舒服了，个人想着要不要多拉伸会，觉得这样会好点， 结果就是，回去时腿很不舒服，但想想应该歇两天就好了，也没多想。
作死乱跑 第二天，虽然小腿有点反应，但并不影响出去走走，失业时，我向来不喜欢白天呆在家里，我怕那种郁郁寡欢的感觉。因此还是找了个公司出去逛逛， 这一逛就是一下午，走的步数着实有点多了。但腿还成，也没反应激烈。第三天，还想着出去跑，又找了个公园逛逛，公司实在太大，最后， 自己一瘸一拐的回来，腿反应严重，这就是作死啊，简直后悔都来不及。
就医 作死乱跑后的几天，腿越来越伤，直到几乎走不了路，想着太严重了，必须得去医院瞧瞧。 第一次，去了华山医院，医生并没看腿，在膝盖处给我按了几处，认为我就是膝盖右侧下支撑位骨头支撑不住，才会这么疼，建议我不要 运动了，以防径骨处骨裂，我很赞同。医生给开了钙片和贴膏，一个星期如果没好转再去医院检查。
我对医生的建议是赞同的，并也在执行医嘱。无奈，很快一星期就过去了，腿更伤了，伤到啥程度呢？走个200米都走不下来，我再次去看 医生时，我是走到小区门口打车过去的，真得那时候觉得自己腿废了。在车上，我竟然哭了，觉得上天不公，本就焦虑抑郁的我，还要承担 腿伤带来的痛苦，真得苦不堪言。
我预约的专家号，期望他能给出更好的建议，很遗憾，专家给我的建议只有休息，然后给我开了检查，一次好像要700多的核磁共振，而且预约只能 两周后，我很犹豫要不要预约，毕竟两周的时间，还有没有必要呢？
想了两方法，一个是朋友告诉我的，走急诊通道。然后我就去急诊了，问了医生，我说走不了路了，医生很淡定的问，啥时候的事？我很天真的告诉他， 两周了，医生瞥了我一眼告诉我，你不符合规定，他们只接收24小时内出问题的。所以，现实是我很无奈，只能慢悠悠的瘸着去想办法。
另一个办法就是去另一家医院看看，能不能当天检查，在百度的排行榜上，六院的骨科才是全国有名的，上海最好的，我突然觉得当初自己就是做了错误的 决定，早应该去六院的。吃完中饭，就拖着我的老残腿过去，医生说的很简单直白，让我照个X光就行，X光排队就要1小时，那位置也是排得满满当当， 没地方坐，站着腿又受不了，蹲下的话，腿也受不了，那酸爽，大概等了10分多钟，才找到一个位置，简直艰难。
X光的结果又得半小时，所幸结果并未有异常。所以医生这边开的药也是药贴与药膏，还让我穿护膝，多保护保护膝盖。就这样，我拖着残腿安心的回去躺平了。
躺平 没有别的任何办法，只能贴药贴，涂药膏来慢慢缓解疼痛。 第一周，疼痛感没有明显消失，有点心急，第二周，慢慢开始缓解，终于看到希望。 果然伤筋动骨的事只能慢慢恢复的，欲速则不达。
忠告 跑完腿有反应千万要让自己多休息，别在外面瞎跑了，那是加速你腿伤的催化剂。 坚持的意义？拥有良好的身体状态才是坚持的最终目标，如果身体状态不佳，就不要有执念一定要坚持下去，那样可能得不偿失 就医最好找行业内最好的医院，能够更精准，设备更完善 </description>
    </item>
    <item>
      <title>无奈的摆烂</title>
      <link>http://www.huasay.com/2023/03/09/put-rotten/</link>
      <pubDate>Thu, 09 Mar 2023 23:37:41 +0800</pubDate>
      <guid>http://www.huasay.com/2023/03/09/put-rotten/</guid>
      <description>大概我的心里早就摆烂了吧，投了几十份简历后的心灰意冷，失业5个月后的心态失衡。
这些天，我一直在心底里给自己发问，我努力了么？ 似乎，我早已忘记了努力两个字，它代表的是什么意义。 我还在恐惧么？一直以来我都是社恐内向的，我很害怕被问的哑口无言，我很害怕突如其来的失败，可是，当失败来临的时候，我又该怎么与自己和解。
对于失败或者无人问津，我却也给自己找好了借口，一切都推给大环境，推给市场寒冬，却无法正视着自己的无能，我常常掩饰着内心的失落，笑着怪市场环境。但内心深处， 可能也只有我自己知道，我以后还能做些啥，我在被淘汰的边缘，挣扎过，无可适从过，却不知道如何爬起来。
夜深了，该死的焦虑感又来了，为我这几天的摆烂而烦恼。那死去的灵魂在呐喊，快为自己活着而努力吧。</description>
    </item>
    <item>
      <title>golang 面试题集</title>
      <link>http://www.huasay.com/2023/02/22/interview-go-overview/</link>
      <pubDate>Wed, 22 Feb 2023 23:32:10 +0800</pubDate>
      <guid>http://www.huasay.com/2023/02/22/interview-go-overview/</guid>
      <description> Go 中的 rune 和 byte 有什么区别？ Go 中的 string 和 []byte 有什么区别？ 什么是深拷贝和浅拷贝？ Go 中的 slice 和 array 有什么区别？slice的扩容机制与扩容时机，使用slice该注意什么 说说 Go 中闭包的底层原理？ 说一下 GMP 模型的原理 Go 的默认栈大小是多少？最大值多少？ Go 中的分段栈和连续栈的区别？ 简述一下 Go 栈空间的扩容/缩容过程？ GMP 为什么要有 P ？ Go 中的 GC 演变是怎样的？ 哪些情况会导致协程泄露？ 内存分配原理 gin框架的路由实现原理 go中http库的实现原理 代码题：使用n个并发，输出[]string{&amp;ldquo;a&amp;rdquo;, &amp;ldquo;b&amp;rdquo;, &amp;ldquo;c&amp;rdquo;, &amp;ldquo;d&amp;rdquo;, &amp;ldquo;e&amp;rdquo;, &amp;ldquo;f&amp;rdquo;, &amp;ldquo;g&amp;rdquo;} 代码题：实现一个简单的协程池 代码题：使用并发编排，使abc三个各输出100次 map的底层实现原理，如果一个协程在delete, 一个协程在读，会出现什么问题，原因是什么 uinptr和unsafe.Pointer的区别 singleFlight存在的坑 </description>
    </item>
    <item>
      <title>算法笔记</title>
      <link>http://www.huasay.com/2023/02/22/algorithm-overview/</link>
      <pubDate>Wed, 22 Feb 2023 23:32:10 +0800</pubDate>
      <guid>http://www.huasay.com/2023/02/22/algorithm-overview/</guid>
      <description> 滑动窗口 双指针 贪心 动态规划 排序 二叉树 </description>
    </item>
    <item>
      <title>算法笔记 - 二叉树</title>
      <link>http://www.huasay.com/2023/02/22/algorithm-tree/</link>
      <pubDate>Wed, 22 Feb 2023 23:32:10 +0800</pubDate>
      <guid>http://www.huasay.com/2023/02/22/algorithm-tree/</guid>
      <description>递归模板 1 2 3 4 5 6 7 8 9 10 func traverse(root *TreeNode) { if root == nil { return } // 前序位置 traverse(root.Left) // 中序位置 traverse(root.Right) // 后序位置 } 层序遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // 输入一棵二叉树的根节点，层序遍历这棵二叉树 func levelTraverse(root *TreeNode) { if root == nil { return } q := make([]*TreeNode, 0) q = append(q, root) // 从上到下遍历二叉树的每一层 for len(q) &amp;gt; 0 { sz := len(q) // 从左到右遍历每一层的每个节点 for i := 0; i &amp;lt; sz; i++ { cur := q[0] q = q[1:] // 将下一层节点放入队列 if cur.</description>
    </item>
    <item>
      <title>黄山行</title>
      <link>http://www.huasay.com/2023/02/07/huanshang/</link>
      <pubDate>Tue, 07 Feb 2023 14:24:58 +0800</pubDate>
      <guid>http://www.huasay.com/2023/02/07/huanshang/</guid>
      <description>期待 黄山，从大学时期至今，心中一直念念不忘，屡次在心中的萌发出的小火苗，都被一些小小借口浇灭的干干净净。 我曾想过，等我游历五岳后再登黄山，毕竟“黄山归来不看岳”的诗句，让我觉得黄山很神秘很美也怕归来后对五岳行的想法产生影响。 我曾想过，等我和至爱一起在光明顶上看日出日落，也是一件浪漫的事，当然也只是想想而已，因为哪有至爱。 我曾想过，离我家乡这么近的景点，如果哪天我想去甚至可以分分钟的达成心愿，这种可以唾手可得的感觉，总让人不免做出这样的优先级。 正是种种的思想，让我在一年年的岁月中，充满期待却不曾走进。
计划 契机，失业了，失业后的焦虑，常常让我夜不能寐。旅行，一种能消除焦虑的清洁剂，多多少少总能缓解这种负面的情绪的。 此时，黄山行，也该提上日程了，终于，按捺不住心中的那团火，开始规划行程与攻略，选择了雪后黄山。南方天气，向来见雪较少，见雪山的机会也是小的可怜。 也该了了心愿去体验一回南方的雪山。
对于自己曾经想过的那些借口，计划与他们相背驰，没有去征服五岳，也许一辈子都没机会。没有与至爱一起，也只是孤独前行。对，也许残缺也是一种美。
从上海到黄山的车票已就位，黄山的山底下是雨天，而山顶却在酝酿着一场大雪。第一天的行程就是坐车然后在山脚下住个旅店，然后买好装备(钉鞋，自热饭，手套等)，疫情才解封的黄山，甚是凄凉，寥寥数人，在风雨交迫的天气下，多少能感受到那种深入骨髓的冰冷，这种冷，却无法浇灭心中的热情。 第二天，7点钟到了酒店大堂，吃了早餐，7点30，酒店的车送到南大门，此时，还是可以看到不少游客慕雪而来，都想目睹雪后黄山的风采。 排着长队，跟着摆渡车进入黄山山脚，然后从山脚上坐缆车上山。我的计划是后山上前山下，前山陡峭险峻，后山平缓，对于我这种下山可以飞，上山像蜗牛的人来说，这种选择是极好的。
在缆车上，我们不禁惊叹，就像没见过世面的土狗一样，拍拍拍。然而，下了缆车的那一瞬间，你就会觉得这一趟值了。 洁白厚厚的雪，覆盖了青松与群山，世界已然变成了黑白灰，对，远处的景，就是水墨，那不是画中才有的景，那一刻在脑海里的，都想永远的记住。而拿起手机准备好好记录时，冷风让手冻的麻木，匆匆几分钟，就已经禁受不住了。也许雪山，更多的只能印在心里。
说说几个值得去的点，如信峰，看群山绝佳位置，有点险，特别是雪天。梦笔生花，简直就是水墨画里出来的。猴子观海，要走比较多的路，不太好拍。飞来石，很不错。光明顶，看日落日出绝佳位置，人很多，没有好机位，可能就是看个寂寞。
光明顶的日落，很美，只是拍摄技术一般，没拍出那种感觉。
晚上的黄山是绝冷的，但有兴趣的可以在黄山上拍到银河。住的是200左右一晚的白鹅宾馆，看日出也可以他们这边看，也许比光明顶人少，更容易观看。但200一晚的10人间，体验只能说，想睡着很难，打呼的至少有3个以上，此起彼伏，这辈子我都没见过这么大的阵仗。当然也可以听听老摄影师讲他的摄影心得以及他的摄影作品。
第二天一早就光明顶看日出了，但果然已经人满为患了，扑腾半天，只能看看，拍是不可能的了。这也许是个错误的决定，还不如在白鹅那边观赏。
日出结束，就匆忙下山了，前山确实要险峻与陡峭很多，下山如果有雪最好穿钉鞋。迎客松在前山索道位置，下来还是有一段距离的。但迎客松怎么都得打卡一下的吧
感想 </description>
    </item>
    <item>
      <title>面试 - 网络</title>
      <link>http://www.huasay.com/2022/11/06/interview-http/</link>
      <pubDate>Sun, 06 Nov 2022 17:39:39 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/06/interview-http/</guid>
      <description>网络面试要点整理 标签（空格分隔）： tcp udp socket 网络
tcp为什么是三次握手 1 2 3 4 TCP 建立连接时通过三次握手可以有效地避免历史错误连接的建立，减少通信双方不必要的资源消耗，三次握手能够帮助通信双方获取初始化序列号，它们能够保证数据包传输的不重不丢，还能保证它们的传输顺序，不会因为网络传输的问题发生混乱，到这里不使用『两次握手』和『四次握手』的原因已经非常清楚了： 『两次握手』：无法避免历史错误连接的初始化，浪费接收方的资源； 『四次握手』：TCP 协议的设计可以让我们同时传递 ACK 和 SYN 两个控制信息，减少了通信次数，所以不需要使用更多的通信次数传输相同的信息； 三次握手流程 1 2 刚开始客户端处于 Closed 的状态，服务端处于 Listen 状态。 客户端发送一个 SYN (Synchronize) 标志设为1 的包，指明客户端要连接服务器端的接口，发送完毕后，客户端进入 SYN_SENT 状态 服务器发回确认包 (ACK) 应答，即 SYN标志位和ACK标志位均为1。服务器端选择自己ISN序列号（为防止固定值可能被攻击，而使用相关的算法得到的一个随机序列号），放到 Seq 域里，同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1，即X+1。 发送 完毕后，服务器端进入 SYN_RCVD 状态。 客户端再次发送确认包(ACK)，SYN 标志位为0，ACK 标志位为1，并且把服务器发来 ACK 的 序号字段+1，放在确定字段中发送给对方，并且在数据段放写ISN的+1, 最后双方都会进入established状态 四次挥手流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 刚开始双方都处于 ESTABLISHED 状态，假如是客户端先发起关闭请求。四次挥手的过程如下： 第一次挥手：客户端发送一个 FIN 报文，报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。 即发出连接释放报文段（FIN=1，序号seq=u），并停止再发送数据，主动关闭TCP连接，进入FIN_WAIT1（终止等待1）状态，等待服务端的确认。 第二次挥手：服务端收到 FIN 之后，会发送 ACK 报文，且把客户端的序列号值 +1 作为 ACK 报文的序列号值，表明已经收到客户端的报文了，此时服务端处于 CLOSE_WAIT 状态。 即服务端收到连接释放报文段后即发出确认报文段（ACK=1，确认号ack=u+1，序号seq=v），服务端进入CLOSE_WAIT（关闭等待）状态，此时的TCP处于半关闭状态，客户端到服务端的连接释放。客户端收到服务端的确认后，进入FIN_WAIT2（终止等待2）状态，等待服务端发出的连接释放报文段。 第三次挥手：如果服务端也想断开连接了，和客户端的第一次挥手一样，发给 FIN 报文，且指定一个序列号。此时服务端处于 LAST_ACK 的状态。 即服务端没有要向客户端发出的数据，服务端发出连接释放报文段（FIN=1，ACK=1，序号seq=w，确认号ack=u+1），服务端进入LAST_ACK（最后确认）状态，等待客户端的确认。 第四次挥手：客户端收到 FIN 之后，一样发送一个 ACK 报文作为应答，且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值，此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态，服务端收到 ACK 报文之后，就处于关闭连接了，处于 CLOSED 状态。 即客户端收到服务端的连接释放报文段后，对此发出确认报文段（ACK=1，seq=u+1，ack=w+1），客户端进入TIME_WAIT（时间等待）状态。此时TCP未释放掉，需要经过时间等待计时器设置的时间2MSL后，客户端才进入CLOSED状态。 收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的，服务端通常执行被动关闭，不会进入TIME_WAIT状态。 为什么需要四次挥手 1 2 3 因为当服务端收到客户端的SYN连接请求报文后，可以直接发送SYN+ACK报文。其中ACK报文是用来应答的，SYN报文是用来同步的。 但是关闭连接时，当服务端收到FIN报文时，很可能并不会立即关闭SOCKET，所以只能先回复一个ACK报文，告诉客户端，“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了，我才能发送FIN报文，因此不能一起发送。故需要四次挥手。 time_wait状态为什么需要等待2MSL 1 2 1.</description>
    </item>
    <item>
      <title>golang面试 - map</title>
      <link>http://www.huasay.com/2022/11/04/interview-map/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:57 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-map/</guid>
      <description>golang map底层实现 1 2 3 4 5 6 7 golang使用数组的方式实现map，hmap里包含buckets，buckets的长度为2^B次方的数组，每个bucket的元素为bMap，当有hash(计算出来的hash的后B位)冲突时，会将其塞到bMap的keys与vaLues，bMap的topbits存储的是topHash(计算出来完整的hash的前8位) 如果冲突的数量太多，会有指针指向溢出桶的位置。 相比最常规的hashmap，有什么优点： 使用掩码方式获取偏移，减少判断。 bucket 存储方式的优化。 通过tophash 先进行一次比较，减少key 比较的成本。 map的底层实现原理 一般map的实现，有一个数组，用于指向真正的值的指针，使用拉链法来解决key值冲突 整个流程大致如下：
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 key | v +------------------------------------+ | key通过hash函数得到key的hash | +------------------+-----------------+ | v +------------------------------------+ | key的hash通过取模或者位操作 | | 得到key在数组上的索引 | +------------------------------------+ | v +------------------------------------+ | 通过索引找到对应的链表 | +------------------+-----------------+ | v +------------------------------------+ | 遍历链表对比key和目标key | +------------------+-----------------+ | v +------------------------------------+ | 相等则返回value | +------------------+-----------------+ | v value go中的map</description>
    </item>
    <item>
      <title>golang面试 - 内存结构</title>
      <link>http://www.huasay.com/2022/11/04/interview-memory/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:57 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-memory/</guid>
      <description>参考文章 https://zhuanlan.zhihu.com/p/59125443 https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-memory-allocator/ https://mp.weixin.qq.com/s/3gGbJaeuvx4klqcv34hmmw https://www.cnblogs.com/zkweb/p/7880099.html https://www.infoq.cn/article/IEhRLwmmIM7-11RYaLHR
逃逸分析 通过检查变量的作用域是否超出了它所在的栈来决定是否将它分配在堆上的技术， 其中变量的作用域超出了它所在的栈，这种行为称为逃逸。
好处：
函数返回直接释放，不会引起垃圾回收，对性能没有影响 减少内存碎片的产生 减轻分配堆内存的开销，提高程序的运行速度 可能产生逃逸的情况
指针作为返回值（方法得非内联,如果被内联优化，有可能并未逃逸）
什么时候从Heap分配对象 很多讲解go的文章和书籍中都提到过, go会自动确定哪些对象应该放在栈上, 哪些对象应该放在堆上. 简单的来说, 当一个对象的内容可能在生成该对象的函数结束后被访问, 那么这个对象就会分配在堆上. 在堆上分配对象的情况包括:
可能逃逸的场景： 返回对象的指针 传递了对象的指针到其他函数 在闭包中使用了对象并且需要修改对象 使用new
1 2 3 4 5 6 7 8 9 10 11 12 type People struct { Name string Age int } //go:noinline func NewPeople(name string, age int) *People{ p := new(People) p.Name = name p.Age = age return p } 栈空间不足逃逸,比如大array或者slice 1 2 3 4 5 6 func BigArr() { arr := make([]int,8193) for i :=0;i &amp;lt;=1000;i++ { arr[i] = i } } 动态类型逃逸 1 2 3 4 5 func DynamicType() { var a interface{} a = 5 fmt.</description>
    </item>
    <item>
      <title>golang面试 - 接口</title>
      <link>http://www.huasay.com/2022/11/04/interview-interface/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:39 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-interface/</guid>
      <description>golang 实现多态的方法 1 2 3 4 5 6 7 8 9 10 11 继承与多态的特点 在golang中对多态的特点体现从语法上并不是很明显。 我们知道发生多态的几个要素： 1、有interface接口，并且有接口定义的方法。 2、有子类去重写interface的接口。 3、有父类指针指向子类的具体对象 空接口与非空接口与nil的判断 空接口eface结构 1 2 3 4 type eface struct { //空接口 _type *_type //类型信息 data unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*) } _type属性：是GO语言中所有类型的公共描述，Go语言几乎所有的数据结构都可以抽象成 _type，是所有类型的公共描述，**type负责决定data应该如何解释和操作，**type的结构代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 type _type struct { size uintptr //类型大小 ptrdata uintptr //前缀持有所有指针的内存大小 hash uint32 //数据hash值 tflag tflag align uint8 //对齐 fieldalign uint8 //嵌入结构体时的对齐 kind uint8 //kind 有些枚举值kind等于0是无效的 alg *typeAlg //函数指针数组，类型实现的所有方法 gcdata *byte str nameOff ptrToThis typeOff } data属性: 表示指向具体的实例数据的指针，他是一个unsafe.</description>
    </item>
    <item>
      <title>[转]golang面试 - Rune与Byte的区别</title>
      <link>http://www.huasay.com/2022/11/04/diff_rune_byte/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:25 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/diff_rune_byte/</guid>
      <description>以下文章转自 https://iswbm.com/517.html
一个字符串是由若干个字符组合而成的，比如 hello，就由 5 个字符组成。
在 Go 中字符类型有两种，分别是：
byte 类型：字节，是 uint8 的别名类型 rune 类型：字符，是 int32 的别名类型 byte 和 rune ，虽然都能表示一个字符，但 byte 只能表示 ASCII 码表中的一个字符（ASCII 码表总共有 256 个字符），数量远远不如 rune 多。
rune 表示的是 Unicode字符中的任一字符，而我们都知道，Unicode 是一个可以表示世界范围内的绝大部分字符的编码， 这张表里几乎包含了全世界的所有的字符，当然中文也不在话下。
能表示的字符更多，意味着它占用的空间，也要更大，所占空间是 4个 byte 的大小。
下面以一段代码来验证一下他们的占用空间的差异
1 2 3 4 5 6 7 8 var a byte = &amp;#39;A&amp;#39; var b rune = &amp;#39;B&amp;#39; fmt.Printf(&amp;#34;a 占用 %d 个字节数\n&amp;#34;, unsafe.Sizeof(a)) fmt.Printf(&amp;#34;b 占用 %d 个字节数\n&amp;#34;,unsafe.Sizeof(b)) // output a 占用 1 个字节数 b 占用 4 个字节数 参考文档： https://iswbm.</description>
    </item>
    <item>
      <title>golang面试 - channel全解析</title>
      <link>http://www.huasay.com/2022/11/04/interview-channel/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:25 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-channel/</guid>
      <description>channel 什么情况下会出现panic 1 2 3 1. 试图往已close的channel继续发送 2. 试图关闭已关闭的channel 3. 试图关闭一个nil的channel 向为nil的channel发送数据会怎样 1 2 3 给定一个 nil channel c: &amp;lt;-c 从 c 接收将永远阻塞 c &amp;lt;- v 发送值到 c 会永远阻塞 channel close后读的问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 关闭后继续读数据，已在缓冲区内的可以读取到数据，而后得到的是零值(对于int，就是0)。 z 我们可以通过for循环遍历channel，来获取到已经写入的值 for _, v := range channel{ } 对于可能获取到零值，我们可以使用断言判断，ok为false代表channel已关闭后读取的 value, ok := &amp;lt;- channel 也可以在close channel之后有意将channel 置为 nil， 如此再使用，并不会读取到零值 对于不带缓冲的ch，和带缓冲的一样，channel close掉之后并不影响读，只影响写入 channel的底层结构 底层结构体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 type hchan struct { qcount uint // total data in the queue 代表 chan 中已经接收但还没被取走的元素的个数。内建函数 len 可以返回这个字段的值。 dataqsiz uint // size of the circular queue 循环队列的大小 buf unsafe.</description>
    </item>
    <item>
      <title>golang面试 - string与[]byte的区别，如何互相转化</title>
      <link>http://www.huasay.com/2022/11/04/diff_string_byte/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:25 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/diff_string_byte/</guid>
      <description>string是一个8位字节的集合，通常但不一定代表UTF-8编码的文本。string可以为空，但是不能为nil。string的值是不能改变的。string类型本质也是一个结构体，底层本质就是一个byte类型的数组。 byte就是uint8的别名，它是用来区分字节值和8位无符号整数值
string与[]byte的区别 对于[]byte与string而言，两者之间最大的区别就是string的值不能改变。string在底层都是结构体stringStruct{str: str_point, len: str_len}，string结构体的str指针指向的是一个字符常量的地址， 这个地址里面的内容是不可以被改变的，因为它是只读的，但是这个指针可以指向不同的地址。 string的好处：以在不加锁的控制下，多次使用同一字符串，在保证高效共享的情况下而不用担心安全问题
对于[]byte来说，以下操作是可行的：
1 2 b := []byte(&amp;#34;hello world&amp;#34;) b[1] = &amp;#39;i&amp;#39; string修改操作是被禁止的：
1 2 s := &amp;#34;hello world&amp;#34; s[1] = &amp;#39;i&amp;#39; string支持这样的操作：
1 2 s := &amp;#34;hello world&amp;#34; s = &amp;#34;iello world&amp;#34; string与[]byte的互相转化 string的底层数据结构类型：
1 2 3 4 type stringStruct struct { str unsafe.Pointer len int } []byte对应的底层数据结构（本质上是个slice）：
1 2 3 4 5 type slice struct { array unsafe.Pointer len int cap int } 两者对应的结构非常相似。</description>
    </item>
    <item>
      <title>golang面试 - 米哈游第三方编制一面复盘</title>
      <link>http://www.huasay.com/2022/11/04/interview-mhywb/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:25 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-mhywb/</guid>
      <description>代码题 以n个协程，去输出[]string{&amp;ldquo;a&amp;rdquo;,&amp;ldquo;b&amp;rdquo;,&amp;ldquo;c&amp;rdquo;,&amp;ldquo;d&amp;rdquo;,&amp;ldquo;e&amp;rdquo;, &amp;ldquo;f&amp;rdquo;, &amp;ldquo;g&amp;rdquo;}。 代码题真得很简单，自己手生的很，竟然没写出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func main() { var wg sync.WaitGroup sem := make(chan struct{}, 5) // 创建一个大小为5的信号量 letters := []string{&amp;#34;a&amp;#34;, &amp;#34;b&amp;#34;, &amp;#34;c&amp;#34;, &amp;#34;d&amp;#34;, &amp;#34;e&amp;#34;, &amp;#34;f&amp;#34;, &amp;#34;g&amp;#34;} for _, letter := range letters { sem &amp;lt;- struct{}{} // 尝试写入信号量，如果已满，则阻塞 wg.Add(1) go func(l string) { defer wg.Done() fmt.Println(l) time.Sleep(5 * time.Second) &amp;lt;-sem // 认领信号量 }(letter) } wg.</description>
    </item>
    <item>
      <title>golang面试 - 深拷贝与浅拷贝</title>
      <link>http://www.huasay.com/2022/11/04/diff_deep_copy/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:25 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/diff_deep_copy/</guid>
      <description>深拷贝是指两个变量，如果其内部引用其他的地址，那么深拷贝会将其内部的指针所指向的值重新分配地址用于存储这个值，因此他们内部的一些引用指针会变化。
浅拷贝是指两个变量，实际上其内部引用部分的地址并没有变化。
常见的浅拷贝，像slice的赋值，map的赋值
1 2 s := []int{1，2，3} s1 = s 如上所示，s1实际上就是对s的浅拷贝
对于深拷贝，我们在代码里应该这么使用
1 2 3 s := []int{1，2，3} var s1 []int copy(s, &amp;amp;s1) </description>
    </item>
    <item>
      <title>golang 面试 - gin</title>
      <link>http://www.huasay.com/2022/11/04/interview-gin/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:10 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-gin/</guid>
      <description>1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 协程和线程的区别 goroutine初始栈大小，上下文如何切换，存在哪里 - 初始栈：2kb GMP说一下，P有多少个，G有多少个，M有多少个。系统调用的时候M会如何，网络IO的时候M会怎样。 - P的个数默认等于cpu个数，可以通过GOMAXPROCS环境变量更改 - M的默认值10000，go程序启动时，会设置M的最大数量，默认10000.</description>
    </item>
    <item>
      <title>golang 面试 - 读写锁</title>
      <link>http://www.huasay.com/2022/11/04/interview-rwmutex/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:10 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-rwmutex/</guid>
      <description>golang中读写锁的原理 1 2 3 4 5 6 7 8 9 10 11 Go 标准库中的 RWMutex 设计是 Write-preferring（写优先） 方案。 如果已经有一个 writer 在等待请求锁的话，它会阻止新来的请求锁的 reader获取到锁，所以优先保障 writer。 当然，如果有一些 reader 已经请求了锁的话，新请求的 writer 也会等待已经存在的 reader 都释放锁之后才能获取。 所以，写优先级设计中的优先权是针对新来的请求而言的。这种设计主要避免了 writer 的饥饿问题。 Go RwMutex使用了readerCount记录目前读请求的总数量 将readerCount进行取反操作 这也是此字段除了标记reader数量的第二个功能，进行写锁标记 此时将取反的r值交给readerWait代表仍需要等待释放锁的reader的数量 如果该数量为0 那么代表不需要等待则直接获取写锁即可，否则就将writer挂起阻塞直至readerWait中的所有读请求全部释放掉，然后RUlock唤醒该写请求 写锁释放时，会将readerCount再加回来，所以负的代表有写请求在，正的代表只有读请求 如果你遇到可以明确区分 reader 和 writer goroutine 的场景，且有大量的并发读、少量的并发写，并且有强烈的性能需求，你就可以考虑使用读写锁 RWMutex 替换 Mutex。
Read-preferring：读优先的设计可以提供很高的并发性，但是，在竞争激烈的情况下可能会导致写饥饿。这是因为，如果有大量的读，这种设计会导致只有所有的读都释放了锁之后，写才可能获取到锁。
Write-preferring：写优先的设计意味着，如果已经有一个 writer 在等待请求锁的话，它会阻止新来的请求锁的 reader获取到锁，所以优先保障 writer。当然，如果有一些 reader 已经请求了锁的话，新请求的 writer 也会等待已经存在的 reader 都释放 锁之后才能获取。所以，写优先级设计中的优先权是针对新来的请求而言的。这种设计主要避免了 writer 的饥饿问题。
不指定优先级：这种设计比较简单，不区分 reader 和 writer 优先级，某些场景下这种不指定优先级的设计反而更有效，因为第一类优先级会导致写饥饿，第二类优先级可能</description>
    </item>
    <item>
      <title>golang 面试 - 互斥锁， 互斥锁的前世今生</title>
      <link>http://www.huasay.com/2022/11/04/interview-mutex/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:10 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-mutex/</guid>
      <description>坑：Unlock 方法可以被任意的 goroutine 调用释放锁，即使是没持有这个互斥锁的 goroutine，也可以进行这个操作。这是因为，Mutex 本身并没有包含持有这把锁的 goroutine 的信息，所以，Unlock 也不会对此进行检查。Mutex 的这个设计一直保持至 今。
互斥锁是怎么实现的 1 2 3 4 5 如果锁是空闲状态且没等待的goroutine，直接获取锁 正常模式： 当前的`goroutine`会与被唤醒的`goroutine`进行抢锁，如果锁未抢到，则会进入自旋状态，自旋多次后，还未竞争到锁，如果是第1次未获取到锁，则加入到等待队列的尾部，如果超过阈值1毫秒，那么，将这个Mutex设置为饥饿模式。 饥饿模式：饥饿模式下，`mutex`将锁直接交给等待队列的最前面的`goroutine`,新来的`goroutine`不会尝试获取锁，即使锁没有被持有，也不会去抢，也不会`spin`，会加入到等待队列的尾部. 如果当前等待的`goroutine`是最后一个`waiter`，没有其他等待的`goroutine` 或者此`goroutine`等待的时间小于1ms，退出饥饿模式。 初版（最普通的做法） 数据结构
1 2 3 4 type Mutex struct { key int32 // 锁是否被持有的标识 sema int32 // 信号量专用，用以阻塞/唤醒goroutine } 具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 // 保证成功在val上增加delta的值 func xadd(val *int32, delta int32) (new int32) { for { v := *val if cas(val, v, v+delta) { return v + delta } } panic(&amp;#34;unreached&amp;#34;) } // 请求锁 func (m *Mutex) Lock() { if xadd(&amp;amp;m.</description>
    </item>
    <item>
      <title>golang 面试 - 内存模型</title>
      <link>http://www.huasay.com/2022/11/04/interview-memory-model/</link>
      <pubDate>Fri, 04 Nov 2022 23:32:10 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-memory-model/</guid>
      <description>通俗定义 1 2 内存模型描述的是并发环境中多goroutine 读相同变量的时候，变量的可见性条件，具体点说，就是指，在什么条件下， goroutine 在读取一个变量的值的时候，能够看到其它 goroutine 对这个变量进行的写的结果。 Go内存模型限定了一些条件 满足这些条件 才能让变量 安全地在不同的goroutine之间读写。换句话说就是如何保证在一个 goroutine中看到在另一个goroutine修改的变量的值，如果程序中修改数据时有其他 goroutine 同时读取，那么必须将读取串行化。为了串行化访问，请使用 channel 或其他同步原语，例如 sync 和 sync/atomic 来保护数据。
happens before 谁前谁后 多个go routine的可见性问题，如果存在多个go routine访问数据的时候，必须序列化访问 单个go routine当中编写 的代码 总是会按照我们的编写代码的顺序来执行
当然这是符合我们的习惯的 当然这并不表示编辑器在编译的时候不会对我们的程序进行指令重排 而是说只会在不影响语言规范的情况下对go routine的行为定义的时候，编辑器和CPU才会对读取与写入的顺序进行重排 happens before（先行发生）的定义
1 2 3 4 5 6 7 当下面条件满足时，对变量 v 的读操作 r 是被允许看到对 v 的写操作 w 的： 1. r 不先行发生于 w 2. 在 w 后 r 前没有对 v 的其他写操作 为了保证对变量 v 的读操作 r 看到对 v 的写操作 w，要确保 w 是 r 允许看到的唯一写操作。即当下面条件满足时，r 被保证看到 w： 1.</description>
    </item>
    <item>
      <title>golang面试 - gc</title>
      <link>http://www.huasay.com/2022/11/04/interview-gc/</link>
      <pubDate>Fri, 04 Nov 2022 23:31:55 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-gc/</guid>
      <description>相关文章 https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-garbage-collector/ https://www.cnblogs.com/luozhiyun/p/14564903.html https://www.kancloud.cn/aceld/golang/1958308#Go_V13mark_and_sweep_21 https://www.bilibili.com/video/BV1wz4y1y7Kd?p=14&amp;amp;spm_id_from=pageDriver https://cloud.tencent.com/developer/article/1756163 https://blog.haohtml.com/archives/26358
https://mp.weixin.qq.com/s/5xjH-LJ53XiNm2sMNQZiGQ
GCMark	标记准备阶段，为并发标记做准备工作，启动写屏障	STW GCMark	扫描标记阶段，与赋值器并发执行，写屏障开启	并发 GCMarkTermination	标记终止阶段，保证一个周期内标记任务完成，停止写屏障	STW GCoff	内存清扫阶段，将需要回收的内存归还到堆中，写屏障关闭	并发 GCoff	内存归还阶段，将过多的内存归还给操作系统，写屏障关闭	并发
Go 语言中对 GC 的触发时机存在两种形式：
主动触发，通过调用 runtime.GC 来触发 GC，此调用阻塞式地等待当前 GC 运行完毕。
被动触发，分为两种方式：
使用系统监控，当超过两分钟没有产生任何 GC 时，强制触发 GC。
使用步调（Pacing）算法，其核心思想是控制内存增长的比例。</description>
    </item>
    <item>
      <title>golang面试 - gmp</title>
      <link>http://www.huasay.com/2022/11/04/interview-gmp/</link>
      <pubDate>Fri, 04 Nov 2022 23:31:55 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-gmp/</guid>
      <description>相关文章 https://mp.weixin.qq.com/s/jIWe3nMP6yiuXeBQgmePDg https://tonybai.com/2017/06/23/an-intro-about-goroutine-scheduler/ https://tonybai.com/2020/03/21/illustrated-tales-of-go-runtime-scheduler/ https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-goroutine/ https://www.kancloud.cn/aceld/golang/1958305#GoroutineGMP_164 https://segmentfault.com/a/1190000023869478 https://www.luozhiyun.com/archives/448 https://zboya.github.io/post/go_scheduler/ https://www.bilibili.com/video/BV19r4y1w7Nx?p=2&amp;amp;spm_id_from=pageDriver https://mp.weixin.qq.com/s/XiqVIR3U5ZmRD7xwJZKipA
进程，线程，协程的区别 进程： 进程是程序的一次执行过程，是程序在执行过程中的分配和管理资源的基本单位，每个进程都有自己的地址空间,进程是系统进行资源分配和调度的一个独立单位。 每个进程都有自己的独立内存空间，由于进程比较重量，占据独立的内存，所以上下文进程间的切换开销（栈、寄存器、虚拟内存、文件句柄等）比较大，但相对比较稳定安全。
线程：在同一个进程中的不同线程共享相同的地址空间(虚拟内存，代表切换不需要切换页表)，每个线程有独立的栈区，程序计数器（执行指令的信息），栈指针以及函数运行的寄存器。 初始栈大小8M，ulimit - s可以查看。调度由系统调度。从用户态切换到内核态，上下文切换消耗相对大
协程：用户态线程，不由内核管理，由go的底层调度器控制，协程初始栈大小2K。由用户调度
goroutine初始栈大小，上下文如何切换，存在哪里 协程初始栈大小2K，上下文由g0去调度找到对应可以运行的goroutine，存在gorountine的gobuf中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 组织下面试的语言 gmp是go为了提高并发能力实现的协程调度模型 g代表我们常说的协程，代码里的体现就是go关键字 m代表操作系统的线程，系统最大值默认为10000 p代表逻辑处理器，默认与cpu的核数想同，当然也可以通过runtime.GOMAXPROCS()来设置p的数量，m一般需要与p关联才能执行g。 调度策略： p会切换到g0栈上，执行调度函数，查找到可执行的goroutine，然后调用gogo函数，切换到goroutine的执行流程上。 1. 每隔61次调度轮回从全局队列找，避免全局队列中的g被饿死。 2. 从p.runnext获取g，从p的本地队列中获取。 3. 调用 findrunnable 找g，找不到的话就将m休眠，等待唤醒。 findrunnable 查找G的过程： 1. 调用 runqget ，尝试从P本地队列中获取G，获取到返回 2. 调用 globrunqget ，尝试从全局队列中获取G，获取到返回 3.</description>
    </item>
    <item>
      <title>golang 基础面试题</title>
      <link>http://www.huasay.com/2022/11/04/interview-base/</link>
      <pubDate>Fri, 04 Nov 2022 23:22:21 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/interview-base/</guid>
      <description>Go语言中是如何实现继承的? 1 2 go语言没有像java，c++等传统的语言一样，有extends关键字用于继承 go语言实现继承可使用组合模式 1 2 3 4 5 6 type User struct { Name string } type Man struct { User } go struct 能不能比较 1 2 3 4 5 6 7 8 9 10 11 12 13 需要具体情况具体分析，如果struct中含有不能被比较的字段类型，就不能被比较，如果struct中所有的字段类型都支持比较，那么就可以被比较。 不可被比较的类型: ① slice，因为slice是引用类型，除非是和nil比较 ② map，和slice同理，如果要比较两个map只能通过循环遍历实现 ③ 函数类型 其他的类型都可以比较。 还有两点值得注意： 结构体之间只能比较它们是否相等，而不能比较它们的大小。 只有所有属性都相等而属性顺序都一致的结构体才能进行比较。 深拷贝和浅拷贝 1 2 3 4 5 6 7 8 深拷贝: 拷贝的是数据本身，创造一个新对象，新创建的对象与原对象不共享内存，新创建的对象在内存中开辟一个新的内存地址，新对象值修改时不会影响原对象值。 实现深拷贝的方式: copy(slice2, slice1)； 遍历slice进行append赋值 浅拷贝∶拷贝的是数据地址，只复制指向的对象的指针，此时新对象和老对象指向的内存地址是一样的，新对象值修改时老对象也会变化。 实现浅拷贝的方式：引用类型的变量,默认赋值操作就是浅拷贝 如slice2 := slice1 make 与 new 的区别 1 2 3 4 5 6 7 8 9 new()对类型进行内存分配,入参为类型,返回为类型的指针，指向分配类型的内存地址 make()也是用于内存分配的，但是和new不同，它只用于channel、map以及切片的内存创建，而且它返回的类型就是这三个类型本身，而不是他们的指针类型，因为这三种类型就是引用类型，所以就没有必要返回他们的指针了。 注意，因为这三种类型是引用类型，所以必须得初始化，但是不是置为零值，这个和new是不一样的。 通过make创建对象 make只能创建slice 、channel、 map。 new和make对比： 1）make 只能用来分配及初始化类型为 slice、map、chan 的数据。new 可以分配任意类型的数据； 2）new 分配返回的是指针，即类型 *Type。make 返回引用，即 Type； 3）new 分配的空间被清零。make 分配空间后，会进行初始化； 4）make 函数只用于 map，slice 和 channel，并且不返回指针 array 与 slice的区别 go语言的引用类型有什么？ 1 切片(slice)类型, map类型 ,管道(channel)类型 , 接口(interface)类型 获取不到锁会一直等待吗？ 1 2 3 4 5 如果锁未被持有，直接获取锁 正常模式： 当前的goroutine会与被唤醒的goroutine进行抢锁，如果锁未抢到，则会进入自旋状态，自旋多次后，还未竞争到锁，如果是第1次未获取到锁，则加入到等待队列的尾部，如果超过阈值1毫秒，那么，将这个Mutex设置为饥饿模式。 饥饿模式：饥饿模式下，mutex将锁直接交给等待队列的最前面的goroutine,新来的goroutine不会尝试获取锁，即使锁没有被持有，也不会去抢，也不会spin，会加入到等待队列的尾部.</description>
    </item>
    <item>
      <title>golang 可重入锁</title>
      <link>http://www.huasay.com/2022/11/04/reentrantLock/</link>
      <pubDate>Fri, 04 Nov 2022 23:22:21 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/reentrantLock/</guid>
      <description>可重入锁的应用场景，用同一段代码的多次调用(递归调用)，方法体之内有锁嵌套。golang官方并不推荐使用可重入锁。但一些面试官比较喜欢让人去手撕可重入锁的代码。一般是java面试官，因为在java中，锁的概念非常丰富， 在golang中相对来说还是比较简单且实用的
什么是可重入锁 可重入锁又称为递归锁，是指在同一个线程在外层方法获取锁的时候，在进入该线程的内层方法时会自动获取锁，不会因为之前已经获取过还没释放而阻塞。
举个简单的例子：
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var mu = &amp;amp;sync.Mutex{} func A() { mu.Lock() fmt.Println(&amp;#34;A&amp;#34;) B() mu.Unlock() } func B() { mu.Lock() fmt.Println(&amp;#34;B&amp;#34;) mu.Unlock() } 以下的代码，在目前golang使用mutex的时候，会导致死锁的情况
1 fatal error: all goroutines are asleep - deadlock! 可重入锁的思路 记住持有锁的线程（golang中对应的是协程） 累计重入的次数 相关代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 type ReentrantMutex struct { mutex sync.</description>
    </item>
    <item>
      <title>golang 设计模式 - 单例模式</title>
      <link>http://www.huasay.com/2022/11/04/designPatternSingleton/</link>
      <pubDate>Fri, 04 Nov 2022 23:22:21 +0800</pubDate>
      <guid>http://www.huasay.com/2022/11/04/designPatternSingleton/</guid>
      <description></description>
    </item>
    <item>
      <title>Leetcode 5 最长回文子串</title>
      <link>http://www.huasay.com/2022/10/26/leetcode-5-longestPalindrome/</link>
      <pubDate>Wed, 26 Oct 2022 14:26:53 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/26/leetcode-5-longestPalindrome/</guid>
      <description>给你一个字符串 s，找到 s 中最长的回文子串。
示例 1:
输入：s = &amp;quot;babad&amp;quot;输出：&amp;quot;bab&amp;quot;解释：&amp;quot;aba&amp;quot; 同样是符合题意的答案。示例 2:
输入：s = &amp;quot;cbbd&amp;quot;输出：&amp;quot;bb&amp;quot;说明:
1 &amp;lt;= s.length &amp;lt;= 1000s 仅由数字和英文字母组成1.暴力解法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // 暴力法 func longestPalindrome(s string) string { var left, right, length int for i := 0; i &amp;lt;= len(s)-1; i++ { for j := i + 1; j &amp;lt;= len(s)-1; j++ { if s[i] !</description>
    </item>
    <item>
      <title>Leetcode 14 最长公共前缀</title>
      <link>http://www.huasay.com/2022/10/26/leetcode-14-longestCommonPrefix/</link>
      <pubDate>Wed, 26 Oct 2022 14:19:16 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/26/leetcode-14-longestCommonPrefix/</guid>
      <description>编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀，返回空字符串 &amp;ldquo;&amp;quot;。
示例 1:
输入: [&amp;quot;flower&amp;quot;,&amp;quot;flow&amp;quot;,&amp;quot;flight&amp;quot;]输出: &amp;quot;fl&amp;quot;示例 2:
输入: [&amp;quot;dog&amp;quot;,&amp;quot;racecar&amp;quot;,&amp;quot;car&amp;quot;]输出: &amp;quot;&amp;quot;解释: 输入不存在公共前缀。说明:
所有输入只包含小写字母 a-z 。思路： 现在只想到暴力方法，对几个字符串遍历判断，如果相等，则记录下，如果不相等，则停止。特殊情况，只输入一个字符串的时候，此时，返回本身
golang实现版本 纵向扫描法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 func longestCommonPrefix(strs []string) string { if len(strs) == 0 { return &amp;#34;&amp;#34; } if len(strs) == 1 { return strs[0] } var commPrefix string for _,v := range strs[0] { hasPrefix := true tempPrefix := commPrefix + string(v) for i := 1; i &amp;lt; len(strs); i ++ { if !</description>
    </item>
    <item>
      <title>Nowcoder Ab1</title>
      <link>http://www.huasay.com/2022/10/25/nowcoder-ab1/</link>
      <pubDate>Tue, 25 Oct 2022 13:28:06 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/25/nowcoder-ab1/</guid>
      <description>描述 1 2 3 4 5 请你实现一个栈。 操作： push x：将 加x 入栈，保证 x 为 int 型整数。 pop：输出栈顶，并让栈顶出栈 top：输出栈顶，栈顶不出栈 输入描述： 第一行为一个正整数 n ，代表操作次数。(1 &amp;lt;= n &amp;lt;= 100000) 接下来的 n，每行为一个字符串，代表一个操作。保证操作是题目描述中三种中的一种。
输出描述： 1 2 3 如果操作为push，则不输出任何东西。 如果为另外两种，若栈为空，则输出 &amp;#34;error“ 否则按对应操作输出。 </description>
    </item>
    <item>
      <title>Redis 面试概览</title>
      <link>http://www.huasay.com/2022/10/21/redis-interview-overview/</link>
      <pubDate>Fri, 21 Oct 2022 13:24:23 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/21/redis-interview-overview/</guid>
      <description>redis基本数据结构 ![image.png-214kB][1]
1 2 3 4 5 6 7 1. 字符串：redis没有直接使用C语言传统的字符串表示，而是自己实现的叫做简单动态字符串SDS的抽象类型。C语言的字符串不记录自身的长度信息，而SDS则保存了长度信息，这样将获取字符串长度的时间由O(N)降低到了O(1)，同时可以避免缓冲区溢出和减少修改字符串长度时所需的内存重分配次数。 2. 链表linkedlist：redis链表是一个双向无环链表结构，很多发布订阅、慢查询、监视器功能都是使用到了链表来实现，每个链表的节点由一个listNode结构来表示，每个节点都有指向前置节点和后置节点的指针，同时表头节点的前置和后置节点都指向NULL。 3. 字典hashtable：用于保存键值对的抽象数据结构。redis使用hash表作为底层实现，每个字典带有两个hash表，供平时使用和rehash时使用，hash表使用链地址法来解决键冲突，被分配到同一个索引位置的多个键值对会形成一个单向链表，在对hash表进行扩容或者缩容的时候，为了服务的可用性，rehash的过程不是一次性完成的，而是渐进式的。 4. 跳跃表skiplist：跳跃表是有序集合的底层实现之一，redis中在实现有序集合键和集群节点的内部结构中都是用到了跳跃表。redis跳跃表由zskiplist和zskiplistNode组成，zskiplist用于保存跳跃表信息（表头、表尾节点、长度等），zskiplistNode用于表示表跳跃节点，每个跳跃表的层高都是1-32的随机数，在同一个跳跃表中，多个节点可以包含相同的分值，但是每个节点的成员对象必须是唯一的，节点按照分值大小排序，如果分值相同，则按照成员对象的大小排序。 5. 整数集合intset：用于保存整数值的集合抽象数据结构，不会出现重复元素，底层实现为数组。 6. 压缩列表ziplist：压缩列表是为节约内存而开发的顺序性数据结构，他可以包含多个节点，每个节点可以保存一个字节数组或者整数值。（新版本已被替换） 7. listpack: redis5之后替换ziplist sds 简单动态字符串 结构：
1 2 3 4 5 6 7 8 9 10 11 12 13 //最长 2^8-1 长度的 sdshdr struct __attribute__ ((__packed__)) sdshdr8 { //len 表示已使用长度 uint8_t len; /* used */ //buf分配的总长度, 也就是数组的总大小, 剩余大小 = alloc - len uint8_t alloc; /* excluding the header and null terminator */ //低3位保存类型标志 unsigned char flags; /* 3 lsb of type, 5 unused bits */ //字符数组 char buf[]; }; - 参考： https://zhuanlan.</description>
    </item>
    <item>
      <title>mysql 要点整理</title>
      <link>http://www.huasay.com/2022/10/21/mysql-overview/</link>
      <pubDate>Fri, 21 Oct 2022 13:20:45 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/21/mysql-overview/</guid>
      <description>一条sql语句是怎么执行的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1.客户端 --&amp;gt; 2.连接器(管理连接，权限校验)--&amp;gt; 3.分析器(词法分析,语法分析)--&amp;gt;4.优化器(执行计划生成，索引选择)--&amp;gt;5.执行器(操作引擎，返回结果)--&amp;gt;6.存储引擎（存储数据,提供读写接口） 2~5 是server层，大部分核心功能在此 6是存储引擎层，负责数据的存储和提取 不同的存储引擎共用一个server 连接器：mysql -h host -P port -u user -p 此步会进行权限的校验，成功则会从数据库中读取该用户支持的权限，不成功则直接会提示access denied for user 分析器：词法分析，识别各种关键字，根据词法分析的结果，进行语法分析，如出错，一般会收到“you have an error in your SQL syntax” 优化器：决定使用哪个索引，关联查询的时候表连接顺序等 执行器：执行语句，再次判断权限，但是对表的操作权限，有权限，则根据表的引擎调用对应的数据引擎的接口 select notExistField from t; 查询一个字段不存在的语句，是发生在分析器这个步骤中。 binlog与redolog的写入流程 redo log(重做日志) 1 2 3 4 5 redo log是innodb特有的日志。当一条记录更新时，先写将其写到redo log，并更新内存。innodb引擎会在适当的时候，将这个操作记录更新到磁盘中，往往是在系统比较空闲的时候 redo log的大小是固定的，可以配置为一组合4个文件，每个文件大小1G，总共可记录4G，当写满时，会循环到开头重新写 有了redo log innodb可以保证在数据库异常重启时，之前提交的记录也不会丢失，这个能力称为crash-safe bin log(归档日志) 1 bin log属于mysql server层自带的日志，与存储引擎无关。binlog日志只能用于归档，并不带有crash-safe能力 两者区别 1 2 3 4 1.</description>
    </item>
    <item>
      <title>Docker 原理</title>
      <link>http://www.huasay.com/2022/10/19/docker-principle/</link>
      <pubDate>Wed, 19 Oct 2022 18:38:53 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/19/docker-principle/</guid>
      <description>虚拟机与docker的区别 可以从以下几个维度具体阐述Docker和虚拟机的区别：
架构 Docker和虚拟机的架构不同，虚拟机是一种完整的虚拟化技术，它需要在物理主机上运行一个虚拟机监视器（hypervisor）来实现虚拟化，每个虚拟机都有自己的操作系统和内核。而Docker是一种轻量级的虚拟化技术，它利用Linux操作系统的容器（container）功能来实现虚拟化，每个Docker容器共享宿主机的操作系统和内核。
资源消耗 由于虚拟机需要模拟整个硬件环境，因此它需要更多的资源，包括内存、CPU和磁盘空间等。而Docker容器只需要使用宿主机的操作系统和内核，因此它的资源消耗更少。
启动速度 由于虚拟机需要启动整个操作系统和内核，因此它的启动速度较慢。而Docker容器只需要启动应用程序和相关依赖，因此它的启动速度较快。
部署方式 虚拟机通常使用镜像（image）来部署应用程序，镜像包括整个操作系统和应用程序等。而Docker使用容器镜像（container image）来部署应用程序，容器镜像只包括应用程序和相关依赖等，因此它更加轻量级，可以更快地部署应用程序。
隔离性 虚拟机之间的隔离性更高，每个虚拟机都有自己的操作系统和内核，可以避免依赖冲突等问题。而Docker容器之间也有隔离性，但是它们共享宿主机的操作系统和内核，因此在某些情况下可能存在一些隔离性问题。
安全性 虚拟机提供了更高的安全性，每个虚拟机都有自己的操作系统和内核，可以避免恶意软件和攻击等问题。而Docker容器也提供了一定的安全性，但是由于共享宿主机的操作系统和内核，因此在某些情况下可能存在一些安全问题。
综上所述，Docker和虚拟机都有各自的优点和缺点，应根据实际情况选择合适的虚拟化技术。如果需要运行不同操作系统的应用程序或者需要更高的隔离性，可以选择虚拟机；如果需要运行相同操作系统的应用程序或者需要更轻量级的虚拟化环境，可以选择Docker。
docker的实现原理 Docker的实现原理涉及以下几个关键技术：
Linux Namespaces：Docker使用Linux命名空间技术来实现容器内部的虚拟隔离环境，例如PID命名空间、UTS命名空间、IPC命名空间、网络命名空间和挂载命名空间等。这些命名空间使用Linux内核提供的特殊机制来实现，使得Docker能够在一个宿主机上创建多个容器，每个容器之间完全隔离。
Cgroups：Docker使用Linux控制组（Cgroups）技术来限制容器使用的资源，例如CPU、内存、硬盘I/O、网络带宽等。Cgroups技术可以将进程分为多个层次结构，并为每个层次结构分配特定的资源限制和优先级，以确保容器使用的资源不会超出宿主机的资源限制。
Union FS：Docker使用联合文件系统（Union FS）技术来实现容器的分层存储。使用Union FS ，Docker将基础镜像的文件系统与容器所需的文件系统叠加在一起，使得容器能够共享基础镜像，减少存储空间和网络带宽。
容器镜像：Docker容器镜像是Docker的核心概念，容器镜像文件包含了应用程序及其所有依赖的库和环境等，Docker引擎可以使用这些镜像来创建容器。Docker容器镜像是基于Union FS实现的分层存储结构，容器镜像的所有层都是只读的，因此修改其中一个层不会影响其他层，这使得Docker容器镜像变得方便、灵活和可复用。
容器网络：Docker使用特殊的网络接口来实现容器的网络，Docker容器默认使用Bridge模式，Docker Daemon将为每个容器创建一个虚拟网桥，并将其连接到主机网桥上，这使得容器之间可以互相通信以及与外部网络进行通信。
总之，Docker实现原理是基于Linux系统的命名空间、Cgroups、Union FS等技术，通过这些技术实现了容器虚拟隔离、资源限制、分层存储和容器网络等功能，从而使得Docker成为一种轻量级的容器化技术，提供了生产环境中管理应用程序的一种新方法。
Namespace pid namespace 不同用户的进程就是通过pid namespace隔离的，且不同的namespace中可以有相同的pid net namespace 网络隔离是通过net namespace实现的，每个net namespace有独立的network devices, ip addresses, ip routing tables, /proc/net目录 docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge:docker0连接在一起 ipc namespace container中进程交互还是采用linux常见的进程间交互方式 mnt namespace mnt namespace允许不同的namespace的进程看到的文件结构不同，这样每个namespace中的进程所看到的文件目录就被隔离开了 uts namespace uts(unix time-sharing system)namespace允许每个container拥有独立的hostname和domain name， 使其在网络上可以被视作一个独立的节点而非host的一个进程 user namespace 每个container可以有不同的user和group id，也就是说可以在container内部用container内部的用户执行程序而非host上的用户 CGroup docker网络错误怎么排查 Docker中出现网络问题的原因有很多，例如网络配置错误、DNS问题、防火墙设置等。下面是一些排查网络问题的方法：</description>
    </item>
    <item>
      <title>sentinel go</title>
      <link>http://www.huasay.com/2022/10/18/sentinel/</link>
      <pubDate>Tue, 18 Oct 2022 20:28:43 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/18/sentinel/</guid>
      <description>https://sentinelguard.io/zh-cn/docs/golang/basic-api-usage.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 func MakeGrpcServerInterceptor() func(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (interface{}, error) { sentinel.Logger.Info(&amp;#34;sentinel breaker server is open&amp;#34;) ruleLoadMap := sync.Map{} return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { _scope := &amp;#34;server.grpc.&amp;#34; + info.</description>
    </item>
    <item>
      <title>Docker 常用命令</title>
      <link>http://www.huasay.com/2022/10/16/docker-cmd/</link>
      <pubDate>Sun, 16 Oct 2022 21:49:21 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/16/docker-cmd/</guid>
      <description>在当前目录创建镜像 1 docker build -t newImage . 运行nginx映射本地端口4000映射容器内80端口 1 docker run -p 8080:80 nginx 容器相关 查看运行中的容器 1 docker container ls 查看所有的容器 1 docker container ls - a 优雅的关闭一个容器 1 docker container stop &amp;lt;hash&amp;gt; 强制关闭一个容器 1 docker container kill &amp;lt;hash&amp;gt; 从设备中移除指定的容器 1 docker container rm &amp;lt;hash&amp;gt; 从设备中移除所有的容器 1 docker container rm $(docker container ls -a -q) 镜像相关 查看所有的镜像 1 docker image ls -a 移除指定的对象 1 docker image rm &amp;lt;image id&amp;gt; 移除所有的镜像 1 docker image rm $(docker image ls -a -q) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 docker build -t friendlyhello .</description>
    </item>
    <item>
      <title>linux 常用命令</title>
      <link>http://www.huasay.com/2022/10/16/linux/</link>
      <pubDate>Sun, 16 Oct 2022 21:49:21 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/16/linux/</guid>
      <description>linux常用命令 1 ls cp rm mkdir touch vim chmod chgrp chroot ss, tcp ping netstat top等 vim 常用命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 0 跳至行首，不管有无缩进，就是跳到第0个字符 (常用) $ 跳至行尾 (常用) gg 跳至文首 (常用) G 调至文尾 (常用) dd 删除光标所在行 (常用) n+[Enter]	n 为数字。光标向下移动 n 行(常用) :1,$s/word1/word2/g	从第一行到最后一行寻找 word1 字符串，并将该字符串取代为 word2 ！(常用) dw 删除一个字(word) 𝑦𝑦复制一行 /pattern 向后搜索字符串pattern n 下一个匹配(如果是/搜索，则是向下的下一个，?</description>
    </item>
    <item>
      <title>K8s 概览</title>
      <link>http://www.huasay.com/2022/10/16/k8s-overview/</link>
      <pubDate>Sun, 16 Oct 2022 21:02:07 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/16/k8s-overview/</guid>
      <description>组成 kubectl：客户端命令行工具，作为整个系统的操作入口。
kube-apiserver：以 REST API 服务形式提供接口，作为整个系统的控制入口。
kube-controller-manager：执行整个系统的后台任务，包括节点状态状况、Pod 个数、Pods 和Service 的关联等。
kube-scheduler：负责节点资源管理，接收来自 kube-apiserver 创建 Pods 任务，并分配到某个节点。
etcd：负责节点间的服务发现和配置共享。
kube-proxy：运行在每个计算节点上，负责 Pod 网络代理。定时从 etcd 获取到 service 信息来做相应的策略。
kubelet：运行在每个计算节点上，作为 agent，接收分配该节点的 Pods 任务及管理容器，周期性获取容器状态，反馈给 kube-apiserver。
DNS：一个可选的 DNS 服务，用于为每个 Service 对象创建 DNS 记录，这样所有的 Pod 就可以通过 DNS 访问服务了。
Kubernetes 的所有管理能力构建在对象抽象的基础上，核心对象包括: • Node:计算节点的抽象，用来描述计算节点的资源抽象、健康状态等。 • Namespace:资源隔离的基本单位，可以简单理解为文件系统中的目录结构。 • Pod:用来描述应用实例，包括镜像地址、资源需求等。 Kubernetes 中最核心 的对象，也是打通应用和基础架构的秘密武器。 • Service:服务如何将应用发布成服务，本质上是负载均衡和域名服务的声明。
Master Node:
Api服务器（API SERVER）：这是 Kubernetes 控制面板中唯一带有用户可访问 API 以及用户可交互的组件。API 服 务器会暴露一个 RESTful 的 Kubernetes API 并使用 JSON 格式的清单文件(manifest files)。 群的数据存储 Cluster Data Store ：Kubernetes 使用“etcd”。这是一个强大的、稳定的、高可用的键值存储，被 Kubernetes 用于长久储存所有的 API 对象。 控制管理器 Controller Manager：被称为“kube-controller manager”，它运行着所有处理集群日常任务的控制器。包 括了节点控制器、副本控制器、端点(endpoint)控制器以及服务账户等。 调度器 Scheduler：调度器会监控新建的 pods(一组或一个容器)并将其分配给节点 Worker Node:</description>
    </item>
    <item>
      <title>Golang 面试资料整理</title>
      <link>http://www.huasay.com/2022/10/15/golang-interview-doc/</link>
      <pubDate>Sat, 15 Oct 2022 14:38:46 +0800</pubDate>
      <guid>http://www.huasay.com/2022/10/15/golang-interview-doc/</guid>
      <description>golang基础 defer golang底层 GMP模型 Sync包实现 Interface底层实现 Map底层实现 数据库 mysql mongo redis 消息队列 rabbitMQ kafka rocketMQ 微服务 konga 服务发现 服务熔断 服务降级 docker与k8s docker docker实现原理 docker的常用命令 docker编排 k8s istio 计算机网络 算法 排序算法 查找算法 树 </description>
    </item>
    <item>
      <title>Redis Multi Set With ttl</title>
      <link>http://www.huasay.com/2022/06/14/redis-multi-set-with-ttl/</link>
      <pubDate>Tue, 14 Jun 2022 10:07:41 +0800</pubDate>
      <guid>http://www.huasay.com/2022/06/14/redis-multi-set-with-ttl/</guid>
      <description>最近项目里需要将原来的一批数据，重新赋值。但同时也得设置好过期时间。为了减少网络的开销，第一想法就是使用MSET的命令。 然而使用该命令，会将key的过期时间直接设置成永久，显然，不能直接这么用。
为什么官方没有提供相关的API 1 Unfortunately, we&amp;#39;re not going to add more commands that can work on multiple keys because they are inherently difficult to distribute. Instead, explicitly calling EXPIRE for every key you want to expire is much easier to distribute (you can route every command to a different server if needed). If you want to EXPIRE keys atomically, you can wrap multiple calls in a MULTI/EXEC block. 根据官方人员的回复，类似批量设置过期时间的主要难点，是在于分布式集群的环境下，如果MSET对应不同的集群的slot，那么就不太容易处理。所以像mset的操作，在事先不清楚每个key所在的slot的情况下，是不推荐使用的。 同理，批量的设置key的过期时间亦是如此。</description>
    </item>
    <item>
      <title>Golang Http Source Code</title>
      <link>http://www.huasay.com/2022/03/14/golang-http-source-code/</link>
      <pubDate>Mon, 14 Mar 2022 11:34:18 +0800</pubDate>
      <guid>http://www.huasay.com/2022/03/14/golang-http-source-code/</guid>
      <description>如果要更深入的理解golang的http处理，那么net/http包的源码就得研读一番。
我们使用原生的golang来处理http处理，一般我们的代码是这样写的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;log&amp;#34; &amp;#34;net/http&amp;#34; ) func main() { // set route and handler 设置路由及处理请求 http.HandleFunc(&amp;#34;/hello&amp;#34;, helloHandle) http.HandleFunc(&amp;#34;/test&amp;#34;, testHandle) http.HandleFunc(&amp;#34;/&amp;#34;, indexHandle) fmt.Println(&amp;#34;Listening at port 8080...&amp;#34;) // listen at port 8080 监听8080端口 err := http.ListenAndServe(&amp;#34;:8080&amp;#34;, nil) if err !</description>
    </item>
    <item>
      <title>mac使用cLion调试redis</title>
      <link>http://www.huasay.com/2022/03/09/redis-debug/</link>
      <pubDate>Wed, 09 Mar 2022 16:04:32 +0800</pubDate>
      <guid>http://www.huasay.com/2022/03/09/redis-debug/</guid>
      <description>想更深入的了解redis的底层实现，当然看源码是必不可少的。 redis是c语言开发的，因此如果需要本地运行调试，就需要相关的c语言编译运行环境。 我们可以选择vscode + 相关插件，也可以选择cLion等ide去处理。基于对JetBrains家族的信任，我选择的是cLion。
C环境依赖检测 1 2 3 4 ~ whereis g++ /usr/bin/g++ ~ whereis gcc /usr/bin/gcc 如果没装过gcc等C语言环境，则可以通过命令安装
1 ~ brew install gcc 下载cLion jetbrains官网可直接下载，不过是试用版 https://www.jetbrains.com/clion/ 目前最新版本 cLion 2021.3 版本开始支持 Makefile 的项目了，所以并不需要额外的将makefile转成cMakefile, 所以就不太需要折腾啦 查看clion的环境是否正确 下载redis 直接从github上克隆仓库
1 ~ git clone https://github.com/redis/redis.git 将项目导入到clion中 导入项目时会提示是否trust project，选择trust project。 是否 clean 项目，选择 clean 即可.
打开 Makefile 并运行 配置redis-server运行选项 点击工具栏右上侧的运行按钮，启动服务 参考文档 https://www.modb.pro/db/73281</description>
    </item>
    <item>
      <title>Redis Sds 简单动态字符串</title>
      <link>http://www.huasay.com/2022/03/09/redis-sds-source-code/</link>
      <pubDate>Wed, 09 Mar 2022 16:04:15 +0800</pubDate>
      <guid>http://www.huasay.com/2022/03/09/redis-sds-source-code/</guid>
      <description></description>
    </item>
    <item>
      <title>Goland 设置</title>
      <link>http://www.huasay.com/2022/03/03/goland-plugins/</link>
      <pubDate>Thu, 03 Mar 2022 14:07:49 +0800</pubDate>
      <guid>http://www.huasay.com/2022/03/03/goland-plugins/</guid>
      <description>go imports go的导入包的顺序有时候挺影响查阅导入的是哪些包的，而一个文件的最头部就是imports，因此看一个文件的头部，如果杂乱无章，心情就不那么美好。
安装goimports包
1 go install golang.org/x/tools/cmd/goimports@latest 文件发生改变时，调用goimports来自动排序我们的import包的顺序 goland &amp;gt; preferences &amp;gt; file watchers &amp;gt; + &amp;gt; goimports 设置import的包顺序排序规则： goland &amp;gt; preferences &amp;gt; editor &amp;gt; code style &amp;gt; go &amp;gt; imports 可根据规范或自己的习惯进行设置 http://cdn.huasay.com/1646791777936.png
golanglint-cli 代码中往往会出现一些未处理的error,一些拼写错误，一些优化建议，那么配置golanglint是个不错的选择。 安装go linter插件： plugins -&amp;gt; go linter 安装golanglint-cli go install github.com/golangci/golangci-lint/cmd/golangci-lint file watcher 添加 golangcli-lint 并可对file watcher进行配置 </description>
    </item>
    <item>
      <title>Golang Function Optional 功能选项</title>
      <link>http://www.huasay.com/2022/03/01/golang-function-optional/</link>
      <pubDate>Tue, 01 Mar 2022 17:35:00 +0800</pubDate>
      <guid>http://www.huasay.com/2022/03/01/golang-function-optional/</guid>
      <description>在看uber的golang最佳实践时，如果初始化一个结构时，在功能迭代中，初始化的参数不断地增加或改变，怎么才能让初始化结构变得可扩展。 uber提出的解决方案是功能选项。
几种备选方案 横冲直幢型 这是初学者最容易做到的，也是最不理想的，当我们每添加一项，就起一个新的初始化方法
1 2 3 4 5 6 type HttpServer struct{ Host string Port string } func NewHttpServer(host, port string) *HttpServer{} 当功能需要我们http服务器能同时支持tls时, 我们可能就换成以下写法
1 2 3 4 5 6 7 8 9 type HttpServer struct{ Host string Port string Cert tls.Cert Timeout int32 } func NewHttpServerWithTls(host,port string) *HttpServer{} func NewHttpServerWithTimeOut(host,port string, timeOut int32) *HttpServer{} 这种写法是没有任何扩展性可言的，当加入更多的配置选项，比如maxConn(最大并发连接数)等，导致针对不同的配置项，都可能产生一种组合，这种方式明显不太可取
没有一个config解决不了的事 显然，上面的方法太不灵活了，只适用于基本不动的配置处理，对于可能新增的选项，修改起来就是灾难。 当然，我们可以用万能的config作参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type HttpServer struct{ Host string Config *Config } type Config struct { Port string Cert tls.</description>
    </item>
    <item>
      <title>搬家记</title>
      <link>http://www.huasay.com/2022/01/24/house-moving-note/</link>
      <pubDate>Mon, 24 Jan 2022 10:34:13 +0800</pubDate>
      <guid>http://www.huasay.com/2022/01/24/house-moving-note/</guid>
      <description>换了公司之后，离原先租的房实在太远，每天早晚通勤时间在1个半小时，来回3小时，也是累的够呛。工作也繁忙, 有时候会加班到很晚，回到家已是10点11点, 疲惫的一天，为了让自己更舒坦点，更希望能够找个离公司近的房子。
能捡漏么？ 租房市场的乱相 都说年底租房可以捡漏。也不知道是不是真的，但年底的房源应该相比是会少点的。
从自己的找房经历来说，是否能捡漏？
答案： 不一定
本次找房接触过中介，个人转租，豆瓣，还有其他的途径。
锁定目标 时间：离公司通勤40分钟内都可以接受，在经历过1个半小时的通勤时间，竟然觉得40分钟也是种享受了。 地点：地铁站1公里以内，当然越近越好。总地铁站数不能超过8站。 房子：可合租独立，可一室户，可两户合租，可以养猫。
房在哪找
链家，我爱我家，中原地产等中介产品，链家适合找1室户，因为价格真实，可以作为参考依据，相比其他的中介，这些更有知名度，门店更多，房源更多，更靠谱点 缺点就是要50%的中介费，这些如果算在预算里，也是不小的一笔费用。
豆瓣租房小组，目前里面也是鱼龙混杂的，大多数都是中介与二房东占领，而且很能伪装。所以这里面想找些个人房源，其实也很难。最后加微信发现的其实都是房产中介/房产经理。当然眼光好点的可以找到个人转租房源
巴乐兔，二房东集中营，好处是不需要自己额外付中介费。之前的设计很不合理，一点开房子就有房产经纪来加微信。后面好像是改成让客户加了，更合理一点了
知乎，微博，贴吧等，不用试了，连人理都没有，直接放弃。
58同城，虚假房源集中营，价格假，房源架，好牌打烂自己作死的一个平台，尽管推出来个人房源，之前体验过也是假的，而且还会骗你到大老远，主动问他们是真是假，还不承认
什么微信公众号，适我家等，其实体验很一般，基本上没符合需求的。
找房历程 我爱我家小哥带我找一室户，看了一些图片，我说不喜欢的，但当天也带我去看了，可能他觉得来了都来了，可以都看看，我是觉得我连图片都不喜欢了，就不需要看了，省时省心。其实看中了一套3800的，我的预算是3500，显然我是想让他给我谈下价格的，结果也没谈下来多少，一般我认为挂牌价至少得谈下来200，最终谈下50，也是没办法
二房东，假房源骗去，说二楼刚10分钟之前被租，问我要不要看下一楼的，一楼的实际上连隔都没隔出来，这还租个毛，我觉得有点诚意的应该房间至少成型吧。另一个二房东，看的几间房子，说实话我心动了，但我还是介意房间隔音，实际上我感觉隔音也行，但更喜欢那间实体墙的。后面因为他没联系我，也没主动说降价，我也放弃了。
转租房源两套，都不错，一套室友人很好，装修也好，但6楼，搬家可能要命吧。另一套在1楼，房间还行，室友没见到，价格更便宜，离公司更近，其实两个方面的比较，最后还是选择了更便宜的。当然我是希望第一套的室友能够降点价，说也挺想租给我这种话的，表达了自己想租的欲望之后，对方也挺风轻云淡的，我觉得就是对室友没有很满意，也没有觉得很不好，我是个感性的人，需要别人的肯定。
搬家小记 确定了房间之后，就轮到搬家了，搬家是累人的，特别是只能自己搬的情况下，打包了很多东西，大概有8个纸箱+3个行李包+自行车，原住址有两级台阶，不过还好, 毕竟还算是个电梯房了。新地址是个一楼，我觉得如果再多一楼，我可能当天就趴下了。搬家小哥也是疲劳驾驶，一直在念叨着自己很困，这种驾驶让我有点担心，但所幸最后安然抵达。
对于猫，我觉得我很生气，它觉得它很郁闷。我拆了猫爬架，扔了；我把它装进背包里，它挣扎；在它们的世界里，我是个恶人吧。事实上，我忙得心情很复杂，我给它包里拉开了点缝隙，这是导致它最终跑出去的来源，最后它从窗户中翻出去了，我挺郁闷的，在搬家小哥在楼下等了10分钟之后，我放弃了它，我觉得它给我带来了很大的负担。第二天，房东和我说它在空调外机旁，我也去了，想方设法让它回来，但是它没有选择回来，我觉得那一刻起，这个世界上，不管是我抛弃它，还是它抛弃我，只能各自安好。尝试了所有方法后，也是无奈了，最后用猫叫声想吸引它回来，但失败了，它朝反方面头也不回的走了，那是对我的一种打击。我抱着一丝希望它能回头，或者能到隔壁室友房间里去，等了整整一下午，那点希望破灭了。我觉得我白养它两年了，至此恩断义绝，我不可能再回去找它了，我有自己的生活需要过，那是它的选择，或流浪，或被领养，都是它的命，与我无关。
在新房间，与新室友没见过面，自己有点说不出来的滋味，与人相处是种学问。不一定能相处好，但希望能够好好的相处，做好朋友。</description>
    </item>
    <item>
      <title>Git Reset hard后的恢复</title>
      <link>http://www.huasay.com/2022/01/24/git-reset-recovery/</link>
      <pubDate>Mon, 24 Jan 2022 10:32:05 +0800</pubDate>
      <guid>http://www.huasay.com/2022/01/24/git-reset-recovery/</guid>
      <description> 缘于某次手贱，利用git工具的时候，没注意，直接用reset hard的方式将之前提交的内容给reset掉了，这直接导致了这一部分提交的内容直接丢失。
那么怎么才能恢复这些commit呢。也找了一些教程，大致可以使用以下几种途径去处理。
git reflog git reflog 命令读取本地的最近的操作记录，我们可以找到reset前的最后一次提交的commit。 可以看到，reset操作之前提交了两次，我们选取最近的一次commit：fbcf5ad
1 git reset --hard fbcf5ad 执行上面命令后，发现又回到了最后一次提交的commit上了，也算是完美的恢复了。
对于已经commit的分支，都推荐使用这种方式恢复
git fsck &amp;ndash;lost-found 使用该命令也可以查找到对应的悬空的commit(dangling commit)，同样可以使用git reset或者git cherry-pick等命令恢复。 对于已提交的，使用该方式去恢复显然没有使用git reflog更直观
但对于未提交但已add的内容，git fsck --lost-found 也是有可能帮助恢复的。
我们通过git fsck --lost-found查看到的内容不仅能查看到悬空的commit,还能查看到悬空的blob(dangling blob), 而这些blob的内容实际就是我们未提交的内容，我们可以通过
1 git show 00bcb6e3738c7392875d6c3e65c22d569eaff069 的方式去读取到该blob对应的内容。 使用
1 git show 00bcb6e3738c7392875d6c3e65c22d569eaff069 &amp;gt; lost_file 的方式去将内容保存至丢失的文件中。
这样我们就可以将这些文件一个个恢复，当然过程是繁琐的。
总结 尽量少使用git reset --hard 命令，一不小心可能让你头脑崩溃 如果使用了该命令，却又想找回，commit过的直接使用git reflog命令找回，所以阶段性的commit是种好习惯 如果未commit过的，只能使用git fsck --lost-found尝试恢复，少量的文件还是容易恢复的，但大量的文件恢复也会让你疯狂。 未add过的文件很难恢复，所以如果有大量文件修改，最好还是阶段性的add或者commit 参考文献 https://mp.weixin.qq.com/s/58W1ljewwvextw05_OKE1w https://www.wencst.com/archives/470 </description>
    </item>
    <item>
      <title>golang 结构体复制库 Copier</title>
      <link>http://www.huasay.com/2022/01/13/go-lib-copier/</link>
      <pubDate>Thu, 13 Jan 2022 09:39:47 +0800</pubDate>
      <guid>http://www.huasay.com/2022/01/13/go-lib-copier/</guid>
      <description>在一些业务场景下，两个不同的结构需要赋值，他们大部分字段是相同的，只有少部分不同，而字段又很多，有几十个，通过 手工的赋值就会觉得代码量很多，而且也不算是很有意义的工作。因此，这个场景下可以使用copier库来复制一些相同的字段 减少手工复制的处理。
下面是一些小场景下使用copier库，以防踩坑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 type Copier1 struct { Name string Age int32 Hobby string } type Copier2 struct { Name string Age int32 } type Copier3 struct { Hobby string } v1 := &amp;amp;Copier1{Name: &amp;#34;zs&amp;#34;, Age: 20} v2 := &amp;amp;Copier2{Name: &amp;#34;ls&amp;#34;, Age: 30} copier.</description>
    </item>
    <item>
      <title>2022年</title>
      <link>http://www.huasay.com/2022/01/13/2022-year/</link>
      <pubDate>Thu, 13 Jan 2022 09:37:12 +0800</pubDate>
      <guid>http://www.huasay.com/2022/01/13/2022-year/</guid>
      <description>2021年是怎样度过的，有点苦涩，有点累，有点不舍。
2021年是非常特殊的一年，疫情当前，甚至都没回家过年。异地过年，草草地应付下，买了点火锅食材，也算丰盛了，临时用箱子搭了个小桌，在出租房里独自过了一年。
2021年，已过而立之年，催婚的压力毫无意外的大，但却无法真正的找到互相有点心灵相通的对象，事实上，我还是觉得单身好，也因此与父母冷战。
2021年，应该理论上已经刷新了全年去医院的次数，日常的配药，因为吃鱼被卡喉，因为脚上起鸡眼，因为身体的里面疼痛，这些都让我痛苦无比，却又不得不进医院。
2021年，换了工作，其实是想提早换的，但无奈一直以自己没准备好为借口没出去找，纠结，犹豫。对于原工作，不开心是因为绩效的问题，还有被大佬的压迫感，绩效给我打C因为嫌我活少，离职又扣绩效，这点我忍不了。 我觉得，对于一家公司以价值观为利他心的，最后一直都在利己，都有点谈不过去了，空谈口号又有什么意思呢。对于新公司，说实话，有点累，有点失望，但不后悔换了工作。
2021年，工作的调整，也带来通勤的时间非常长，基本上在1个半小时左右，这让自己身心俱疲，因此在年末也是找了离公司近的一间合租房，相比于合租需要与人相处，不知道之后相处会怎样。
2021年，开始玩基金，嗯，从年初到年底，好像玩了个寂寞。
2022年，希望能够身体健康，能够有份不错的工作，能够开心，能够拥有友谊</description>
    </item>
    <item>
      <title>Grpc Int64的坑</title>
      <link>http://www.huasay.com/2021/12/27/grpc-int64/</link>
      <pubDate>Mon, 27 Dec 2021 09:36:44 +0800</pubDate>
      <guid>http://www.huasay.com/2021/12/27/grpc-int64/</guid>
      <description>在使用grpc的时候，proto的类型定义成int64，但结果展示却显示成string类型。刚开始还纳闷客户端说文档上定义int类型，为啥不和文档统一呢? 自信的我坚定的回答我定义的就是int类型的，统一的很。然后模拟完接口请求，打脸来得真快。
问题复现 定义proto文件 1 2 3 4 5 6 7 8 9 10 // 音乐搜索项 message PartyMusicSearchItem { string name = 1; int32 fileSize = 2; string author = 3; string musicId = 4; int32 type = 6; int64 createdAt = 7; int64 lastTime = 8; } 返回值： 1 2 3 4 5 6 7 8 9 { &amp;#34;author&amp;#34;: &amp;#34;张碧晨&amp;#34;, &amp;#34;createdAt&amp;#34;: &amp;#34;1640157765000&amp;#34;, &amp;#34;fileSize&amp;#34;: 10907, &amp;#34;lastTime&amp;#34;: &amp;#34;1640157765000&amp;#34;, &amp;#34;musicId&amp;#34;: &amp;#34;61c2d2459a01c38927334b03&amp;#34;, &amp;#34;name&amp;#34;: &amp;#34;年轮&amp;#34;, &amp;#34;type&amp;#34;: 0 } 我们看到返回值中createdAt与lastTime已经变成是string类型的。</description>
    </item>
    <item>
      <title>Golang Defer</title>
      <link>http://www.huasay.com/2021/12/12/golang-defer/</link>
      <pubDate>Sun, 12 Dec 2021 17:05:20 +0800</pubDate>
      <guid>http://www.huasay.com/2021/12/12/golang-defer/</guid>
      <description></description>
    </item>
    <item>
      <title>redis lua 脚本运行工具</title>
      <link>http://www.huasay.com/2021/12/06/redis-lua-script-tool/</link>
      <pubDate>Mon, 06 Dec 2021 10:38:39 +0800</pubDate>
      <guid>http://www.huasay.com/2021/12/06/redis-lua-script-tool/</guid>
      <description> 测试环境中，redis使用的是阿里云的rds，目前是没有权限运行redis-cli这种命令。如果对于lua长脚本，官方是推荐使用redis-cli去加载script然后运行的。 针对这样的环境，如果我们需要调试复杂或有不少逻辑的lua脚本，怎么调试？ 一是直接用代码，调用端改代码调试，因为现在改代码不太方便，每次都要部署测试环境。 因此在想有没有更容易的方式，我们是有权限登录redis的，只是没有redis-cli的执行命令而已，因此我们还可以选择eval script &amp;hellip;的命令去执行。 但是script脚本很长，这时候我们可以借助压缩工具去处理。
其实说来说去，就是得找个lua脚本的压缩工具。
工具1：Lua 压缩器 工具2：vscode + Lua Minify 插件 </description>
    </item>
    <item>
      <title>Golang 多条件下的switch</title>
      <link>http://www.huasay.com/2021/11/25/golang-switch-case/</link>
      <pubDate>Thu, 25 Nov 2021 11:12:04 +0800</pubDate>
      <guid>http://www.huasay.com/2021/11/25/golang-switch-case/</guid>
      <description>在业务场景下，如果有多条件，怎么处理？ 比如条件isModifyName是否修改姓名，条件isModifyAge是否修改姓名。 我们可以使用if else来拼凑出4个条件，那么怎么使用switch case呢，switch case是比if else效率高的，可读性也更好，所以在条件多于2个的时候，会优先选择switch case。
方式一： case相当于一个if
1 2 3 4 5 6 7 8 9 10 11 12 13 isModifyName := 1 isModifyAge := 1 switch { case isModifyName == 0 &amp;amp;&amp;amp; isModifyAge == 0: fmt.Println(&amp;#34;all not modify&amp;#34;) case isModifyName == 1 &amp;amp;&amp;amp; isModifyAge == 1: fmt.Println(&amp;#34;all modify&amp;#34;) case isModifyName == 0 &amp;amp;&amp;amp; isModifyAge == 1: fmt.Println(&amp;#34;age modify&amp;#34;) case isModifyName == 1 &amp;amp;&amp;amp; isModifyAge == 0: fmt.</description>
    </item>
    <item>
      <title>Golang 将int转换成bool类型</title>
      <link>http://www.huasay.com/2021/11/24/golang-int-to-bool/</link>
      <pubDate>Wed, 24 Nov 2021 17:34:02 +0800</pubDate>
      <guid>http://www.huasay.com/2021/11/24/golang-int-to-bool/</guid>
      <description> 没有三目运算符的golang，有时候怎么处理才优雅简洁。最简单的方法就是if&amp;hellip;else&amp;hellip;判断
1 2 3 testValue := 1 testBool := test-1 == 0 fmt.Println(testBool) </description>
    </item>
    <item>
      <title>Golang Duration类型转换成int64</title>
      <link>http://www.huasay.com/2021/11/17/golang-duration-to-int/</link>
      <pubDate>Wed, 17 Nov 2021 10:05:21 +0800</pubDate>
      <guid>http://www.huasay.com/2021/11/17/golang-duration-to-int/</guid>
      <description>我有个习惯，就是把一些比较固定的东西会写在常量里，比如一些key的过期时间，就会定义constant keyExpireDuration = 10*time.Second, 有一天，需要将这个过期时间戳返回给前端，然后我就没脑的使用了time.now.unix() + int64(xxx),然后就爆了
Duration类型是time包里定义的一个类型，实际上的类型是int64。 我们从time包定义的常量来分析
1 2 3 4 5 6 7 8 const ( Nanosecond Duration = 1 Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minute ) 可以发现duration最小的单位是ns, 我们代码里如果使用的是time.Second，实际上对应的duration的值是纳秒为单位的。 当我们如果进行运算的时候，就得注意了。比如简单的time.now.unix() + int64(xxx)相加，最后导致的前面一个是秒级的时间戳， 而后面一个是纳秒级的数字，这相加导致最终的结果爆掉了。
正确的做法就是需要相加的比如是10 * time.Second，我们需要先除以time.Second来保证这是秒数，而不是纳秒数
这就是小小的时间相加可能导致的问题。
1 2 expireDuration := 10 * time.Second expireTime := time.now.unix() + int64(expireTime/time.</description>
    </item>
    <item>
      <title>Redis 使用 lua</title>
      <link>http://www.huasay.com/2021/11/17/redis-lua/</link>
      <pubDate>Wed, 17 Nov 2021 09:57:01 +0800</pubDate>
      <guid>http://www.huasay.com/2021/11/17/redis-lua/</guid>
      <description>最近，业务代码上大量使用redis，每一次操作会对多个key进行操作，而有些key可能在别的操作中也会同一时刻被改动,所以为了保证中途不被别的修改，采用了lua脚本的方式
为什么不用redis事务 众所周知，redis自己也有一套事务机制，但redis的原子性实现是类似乐观锁的机制，如果在事务中的命令修改的key被其他事务或命令修改，则会执行失败回滚。 再加上redis本身事务并未很好的实现ACID，也导致redis的事务使用的场景一直不是很多。以后会有专门的文章书写redis的事务
与pipeline的区别 一般管道的使用场景是多个命令无依赖，或者批量操作一批key。使用pipeline就可以节省指令来回需要的rrt
redis lua脚本使用方式 lua脚本是能保证隔离性的，即在执行脚本的过程中，是没有其他指令可以执行的，而且还可以进行逻辑的判断，因此大多数情况下，我们会用lua脚本的方式替代事务。
参考文档 https://redis.io/topics/transactions
https://redis.io/topics/pipelining
https://redis.io/commands/eval</description>
    </item>
    <item>
      <title>Go 语言开发设计指北</title>
      <link>http://www.huasay.com/2021/11/01/go-develop-guide/</link>
      <pubDate>Mon, 01 Nov 2021 23:19:13 +0800</pubDate>
      <guid>http://www.huasay.com/2021/11/01/go-develop-guide/</guid>
      <description>本文转载：https://www.debuginn.cn/6832.html
Go 语言是一种强类型、编译型的语言，在开发过程中，代码规范是尤为重要的，一个小小的失误可能会带来严重的事故，拥有一个良好的 Go 语言开发习惯是尤为重要的，遵守开发规范便于维护、便于阅读理解和增加系统的健壮性。
以下是我们项目组开发规范加上自己开发遇到的问题及补充，希望对你有所帮助： 注：我们将以下约束分为三个等级，分别是：【强制】 、【推荐】 、【参考】 。
Go 编码相关 【强制】 代码风格规范遵循 go 官方标准：CodeReviewComments，请使用官方golint lint 进行风格静态分析；
【强制】 代码格式规范依照gofmt，请安装相关 IDE 插件，在保存代码或者编译时，自动将源码通过gofmt做格式化处理，保证团队代码格式一致（比如空格，递进等）
【强制】 业务处理代码中不能开goroutine，此举会导致goroutine数量不可控，容易引起系统雪崩，如果需要启用goroutine做异步处理，请在初始化时启用固定数量goroutine，通过channel和业务处理代码交互，初始化goroutine的函数，原则上应该从main函数入口处明确的调用：
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func crond() { defer func() { if err := recover(); err != nil { // dump stack &amp;amp; log } }() // do something } func main() { // init system go crond() go crond2() // handlers } 【强制】 异步开启goroutine的地方（如各种cronder)，需要在最顶层增加recover()，捕捉panic，避免个别cronder出错导致整体退出：</description>
    </item>
    <item>
      <title>Redis Zset 有序集合</title>
      <link>http://www.huasay.com/2021/10/31/redis-zset/</link>
      <pubDate>Sun, 31 Oct 2021 13:53:50 +0800</pubDate>
      <guid>http://www.huasay.com/2021/10/31/redis-zset/</guid>
      <description>zset是redis中常用的数据结构，一般使用场景是有序集合，排行榜等有序的需求我们会考虑使用。
背景： 最近也是做了相关的需求，用户发动态，将最新动态中的图片，视频或音频资源收集起来，列表中会展示用户最新4条动态的资源缩略图。因为动态还有个审核，所以 一般采集的时候会按审核的时间点采集，但展示却得按照创建时间展示。因此采用了zset的方案，score的值为创建时间，当审核完成时，会将该动态的资源信息以member存储至 zset中，取的时候，按照score(创建时间)由大到小读取
方案实施 存储，简单使用zadd命令，将动态资源信息(一个结构体，json格式化后以字符串形式)存储至zset中，createdAt为score 1 2 3 4 # ZADD KEY_NAME SCORE1 VALUE1.. SCOREN VALUEN # 将一个或多个成员元素及其分数值加入到有序集当中 # ZADD file fileInfo createdAt -&amp;gt; ZADD file &amp;#34;{url:&amp;#39;xxx.jpg&amp;#39;,type:1}&amp;#34; 1635661958 维持zset大小，因为只需要取最新4条动态的资源，因此，对于旧的资源信息，可以删除4名开外的动态信息 1 2 3 4 5 6 # ZREMRANGEBYRANK key start stop # 移除有序集中，指定排名(rank)区间内的所有成员。 -&amp;gt; ZRemRangeByRank file 0 -5 # 因为默认是按从小到大排序的，我们如果要取最新的4条动态，需要从排名最小的元素开始删除， # 0代表排名最旧的，排最前的，-5表示排名倒数第5的， # 当zset中的元素超过4时，-5其实就相当于0,所以整个语句相当于删除第4名之后的动态资源信息 获取从大到小顺序的最新4条动态 1 2 3 # ZREVRANGE key start stop [WITHSCORES] # 按分数值递减(从大到小)来排列 -&amp;gt; ZREVRANGE file 0 3 不足之处 因为member的值中有url，有类型等信息，zset的member的长度是过大的，这就导致了并不能用上quickList，只能使用上skipList</description>
    </item>
    <item>
      <title>奇怪的梦 - 考研</title>
      <link>http://www.huasay.com/2021/10/31/dream-postgraduate/</link>
      <pubDate>Sun, 31 Oct 2021 11:56:27 +0800</pubDate>
      <guid>http://www.huasay.com/2021/10/31/dream-postgraduate/</guid>
      <description>清晨时分，做了一个让人诡异的梦。梦的内容很简单，却似曾相识，竟然是曾经做过的一个梦的续集，连做梦都开始有自动续的功能的么。
说说上次的梦吧，时间久远，已无法从脑海中记起多少细节，只能大概的描述下梦境的内容。 随着考研大军的越来越壮大，我也不免俗地想要成为其中的一员，在经过努力的准备后， 也考上了一所大学，这所大学名字叫上海长吾大学，可能是因为没有其他更好选择吧， 因为这是所985大学，也没挣扎，就选了这个大学，就这么愉快的收到这个大学的录取通知书了。 也感叹自己的努力没有白费。
上次的梦境是我经过努力拿到了一所985高校的录取通知书。而今天的梦境却从这时接着开始，很神奇，这梦隔着至少也几个月了吧。 我拿到录取通知书后，兴奋不已，彻夜难眠，临近去学校的日子，问了一些朋友，问了他知道这所高校么？却无一听闻，我很紧张，想从互联网上 找寻到相关的信息，却有点失望，却找不到痕迹。偶尔在一份老报纸上看到标题为『我的母校，上海长吾大学，一所有点特别的学校』, 上海长吾大学，一所以上海为名，却不在上海的学校，在西安这个古老有历史的城市下创办的一所民办学校，在历史的长河中生存下来，是一所985，211高校，在历史人文专业上有一点的造诣。 而除了这些信息，我却无从考证，我也即将开始踏上鲜有人知晓的大学的求学之路。
梦醒了，我有些恍惚，我开始百度，事实上也确实找不到任何关于这所大学的信息。
梦是幻境，给我制造了假象，在假象里，在虚虚实实里，我又能知前途如何。长路漫漫，奋力前行，我却听到了梦碎了的声音。</description>
    </item>
    <item>
      <title>Mac OS下常备软件</title>
      <link>http://www.huasay.com/2021/10/31/mac-software/</link>
      <pubDate>Sun, 31 Oct 2021 01:50:58 +0800</pubDate>
      <guid>http://www.huasay.com/2021/10/31/mac-software/</guid>
      <description>基本软件 Homebrew chrome V2rayU,世界更精彩 iterm2,最好用的terminal ohmyzsh，最好用的shell zsh语法高亮插件，必备 zsh自动补全插件，必备 清理app git工具 Command Line Tools（需登录AppleID） Magnet alfred，听说是神器 工作软件 vscode，最好用的编辑器 golang postman 切换host ssh连接工具 最好用的redis工具 </description>
    </item>
    <item>
      <title>Golang 学习资料汇总，从入门到放弃</title>
      <link>http://www.huasay.com/2021/10/26/golang-learn-blog/</link>
      <pubDate>Tue, 26 Oct 2021 14:38:46 +0800</pubDate>
      <guid>http://www.huasay.com/2021/10/26/golang-learn-blog/</guid>
      <description>入门 go的一些使用小例子 无闻讲师的基础视频 go入门指南 go web基础 effective go 进阶 go内存模型 go程序诊断 标准库 标准库文档 标准库包的使用例子 go语言标准库 书籍或阅读清单 go开发者阅读清单 深入解析Go go语言编程之旅 go语法树入门 go语言设计-欧长坤 gopher博客推荐 draveness,go底层实现原理，讲得很详细 鸟窝，rpcx作者博客，go并发编程专栏 煎鱼大大，可以关注下公众号 李文周的博客 曹春晖的golang笔记 峰云golang专栏 大彬的blog gophers推荐清单 </description>
    </item>
    <item>
      <title>衰的人生，如何振奋</title>
      <link>http://www.huasay.com/2021/10/09/note-log/</link>
      <pubDate>Sat, 09 Oct 2021 21:39:45 +0800</pubDate>
      <guid>http://www.huasay.com/2021/10/09/note-log/</guid>
      <description>这些年，慢慢地开始抑郁。时常想走出困境，却又不那么容易走出。
曾经，有一个至好朋友，当他离开后，就觉得整个世界都索然无味；曾经，病倒在床住院半个多月，只有孤单陪伴；曾经，许多美好的事情都想努力做好，却永远也做不好。慢慢地，也许不再有自信，不再有朋友，不再有关心，然后开始抑郁。
抑郁这个词是被用烂了的，经常听人说他们抑郁，可是他们真得抑郁么？我也不清楚，我也经常说我抑郁，但我却从未想过自杀，即使有时候真得特别压抑，就是彻夜的未眠，就是毫无心情的自我漫游，做着一些毫无意义重复的事情。我觉得这是情感上的孤独造就的，让自己无所依靠，是一连串的失败一连串的所谓的衰导致自己的崩溃。
谈谈最近的衰，想离职，被上级知道，打了个C，对，就是绩效C，这个怎么说呢，其实不算是衰，但也是不太让人开心的事；找工作被放鸽子，一个半小时后，问我是否还在，可能这也不算衰，只是没想到对方是这种人罢了；脚上长了鸡眼，越来越疼，选择了药除，结果流程长到要几个月，长时间的脚不舒服；骑自行车因为路上消防栓开着导致滑胎，摔的四肢全破，两支手碗只能提起一杯茶的力量；打印学历证书，回家了发现学历证书原件店员并没有给我。有些谈不上衰，可能自己也不太注意，才会让人觉得倒霉。 但是，谁不想有点舒心的事呢，谁喜欢一个月要进10来次医院呢，这几个月可能是进医院次数最多的吧。有时候静静的抒发出来，可能会更好受点吧。因为这些太过负面，和朋友说多了，也都是负能量，可能他们也并不愿意听，而只能自己听吧。所有的衰意，希望能够随时间而淡没。我也想做个快乐的人，请给我个机会。
当有时候精神昂扬的苗头初起，请给我点掌声，让我也能激情澎湃一回。</description>
    </item>
    <item>
      <title>Interview_algorithm</title>
      <link>http://www.huasay.com/2021/03/05/interview_algorithm/</link>
      <pubDate>Fri, 05 Mar 2021 16:24:55 +0800</pubDate>
      <guid>http://www.huasay.com/2021/03/05/interview_algorithm/</guid>
      <description>排序算法 树 </description>
    </item>
    <item>
      <title>面试准备</title>
      <link>http://www.huasay.com/2021/03/04/interview-ready/</link>
      <pubDate>Thu, 04 Mar 2021 15:08:06 +0800</pubDate>
      <guid>http://www.huasay.com/2021/03/04/interview-ready/</guid>
      <description>语言 php 框架（laravel） socket编程，异步协程通信swoole php8 语言特性 php 底层实现原理（某个函数的实现，比如in_array; 某个语言结构，比如array） Golang Web框架 gin(目前使用的比较广泛的框架) 优点，与echo相比的优势 channel 通道 interface 接口 可看看B站泄漏的go代码结构 底层的一些实现原理及区别，比如array与slice 数据库及NoSql mysql的索引优化等 es相关可看看 redis相关使用场景 容器 docker相关 k8s相关 队列 rabbitMQ,目前公司消息队列使用 kafka，目前公司大数据存储使用 rocketMQ 阿里生态 计算机网络及网络协议 TCP的三次握手 socket相关 mqtt相关 wireshark抓包及tcpdump抓包 算法 letcode刷题 </description>
    </item>
    <item>
      <title>vim常用快捷键使用指南</title>
      <link>http://www.huasay.com/2020/12/22/vim-use-guide/</link>
      <pubDate>Tue, 22 Dec 2020 09:24:23 +0800</pubDate>
      <guid>http://www.huasay.com/2020/12/22/vim-use-guide/</guid>
      <description>自己在工作中经常使用的vim快捷键
快捷键 描述 0 跳至行首，不管有无缩进，就是跳到第0个字符 (常用) $ 跳至行尾 (常用) gg 跳至文首 (常用) G 调至文尾 (常用) dd 删除光标所在行 (常用) n+[Enter] n 为数字。光标向下移动 n 行(常用) :1,$s/word1/word2/g 从第一行到最后一行寻找 word1 字符串，并将该字符串取代为 word2 ！(常用) dw 删除一个字(word) yy 复制一行 p 粘贴 /pattern 向后搜索字符串pattern n 下一个匹配(如果是/搜索，则是向下的下一个，?搜索则是向上的下一个) N 上一个匹配(同上) :w 将缓冲区写入文件，即保存修改 :wq 保存修改并退出 :x 保存修改并退出 :q 退出，如果对缓冲区进行过修改，则会提示 :q! 强制退出，放弃修改 :set nu 显示行号 :set nonu 与 set nu 相反，为取消行号！ i 从目前光标所在处输入 [Esc] 退出编辑模式，回到一般模式中(常用) u 复原前一个动作。(常用) [Ctrl]+r 重做上一个动作。(常用) </description>
    </item>
    <item>
      <title>计算机网络 - tcp协议</title>
      <link>http://www.huasay.com/2020/08/21/computer-network-series-tcp/</link>
      <pubDate>Fri, 21 Aug 2020 00:54:04 +0800</pubDate>
      <guid>http://www.huasay.com/2020/08/21/computer-network-series-tcp/</guid>
      <description>定义 TCP提供一种面向连接的、可靠的字节流服务。所谓面向连接，即应用程序在使用TCP协议之前，必须先建立TCP连接，在传送数据完毕后，必须释放已经建立的连接。这个过程可以通俗的比喻成通话过程，在通话之前，必须先拨通号码，对方也必须接听，之后才可以通话。 所谓可靠的服务，即表示TCP连接传送的数据可以做到无差错，不丢失，不重复等。
握手 TCP的传输需要先建立连接，整个建立连接的过程一般称为三次握手
为什么是三次，不是两次，甚至更多 建立连接的过程是要保证双方可通信。比如邀请女神约会，我们都得先确定可以去，女神也得确定我可以去，不然谁先到约会地点就谁尴尬，容易被放鸽子。
我 &amp;ndash;&amp;gt; 明天晚上可以一起看电影么？ &amp;ndash;&amp;gt; 女神
女神 &amp;ndash;&amp;gt; 可以啊 &amp;ndash;&amp;gt; 我
如果两次握手是这样的，第一，女神这边确认是可以收到消息的了，我这边是确认可以发送消息的了。但女神那侧也并不确认自己是发送成功了，那怎么判断能发送成功，只能通过我这方再次发送通知过去才可以。
我 &amp;ndash;&amp;gt; 收到啦，一言为定 &amp;ndash;&amp;gt; 女神
当进行了第三次握手的时候，我们双方才能确定，前两次的话是生效了，三次握手的目标就是使双方心里都有底，确保双方最基本的发送与接收功能正常。女神可以确认自己的收发能力都OK，我也确认了自己的收发能力OK，才能最基本上的保证不被放鸽子，双方心里都有底。
为什么不是更多？
因为三次握手是确保双方通信条件都OK的最基本的方式，如果更多次，当然也可以，但是，会增加网络的消耗，4次，甚至5次&amp;hellip;N（N&amp;gt;5）次，也只能确保前N-1是正常的，也不能确保之后通信就是完全正常，所以3次是最好的握手判断。
三次握手的过程 TCP 报文 源端口与目的端口，各占2字节，16位 序号，4个字节，0~$$2^32$$ -1。起始序号在连接建立时设置，首部中的序号是指本报文段所发送的数据的第一个字节的序号。
例如，一个报文段第一个字节序号是301，最后一个字节序号是400，则下一个报文段的数据序号就得401. 确认序号，4个字节，期望收到对方下一个段文段的第一个字节的序号。
例如，收到了对方发来的报文段，序号字段是501，数据长度是200字节，则期望收到对方下一个数据序号为701，此时，就将发送给对方的确认序号设置成701. 首部长度，4位。首部长度最小为20个字节，但因为包含选项（不定长)，但最大长度只能是60个字节。因为该值长度为4位，4位最大值表示15，也代表整个首部最长为60字节，选项长度最大为40字节 保留位，6位，为今后所用，目前应置为0 紧急URG（URGent）当URG = 1时，表明紧急指针字段有效，与紧急指针字段配合使用，代表该报文段中有紧急数据，需加急处理 确认ACK（ACKnowledgment）当ACK = 1时确认号字段有有效，ACK = 0时，确认号无效，在连接建立后，所有传送的报文段都必须置ACK = 1 推送PSH（PuSH）两应用程序进行交互式通信时使用，当PSH = 1时，接收方应尽快的交付接收应用进程，不用等缓存满了再向上交付。该操作很少使用 复位RST (ReSeT) 当RST = 1时，表明TCP连接中出现严重差错（如主机崩溃），必须释放连接，然后再重新建立连接。RST = 1还用来拒绝非法报文段或拒绝打开一个连接 同步SYN（SYNchronization）在连接建立时用来同步序号。SYN = 1而ACK = 0时，说明这是一个连接请求报文段。对方若同意建立连接，则应在响应报文中设置SYN = 1 ，ACK = 1. 终止FIN （FINis）用来释放一个连接，当FIN = 1时，表明报文段的发送方数据已发送完毕，并要求释放连接 窗口 2字节，用于告诉对方，允许对方发送的数据量大小，自己的缓存空间还可接收多少数据量。 校验和 2字节，检验首部与数据 紧急指针 2字节。URG = 1时配合使用，本报文中紧急数据的末尾在报文中的位置 选项 最长40字节 挥手 为什么是4次，不是3次，甚至更少 4次挥手过程 如何实现可靠性 </description>
    </item>
    <item>
      <title>生活不易，且行且珍惜</title>
      <link>http://www.huasay.com/2020/08/18/live-is-not-easy/</link>
      <pubDate>Tue, 18 Aug 2020 00:05:26 +0800</pubDate>
      <guid>http://www.huasay.com/2020/08/18/live-is-not-easy/</guid>
      <description>深夜，蝉鸣，刚涂了药，旁边风扇呼呼大响，猫还在发呆。而我，思绪上头，压抑不住，还是决定写上一笔。
不知是我性格变了还是工作环境变了，现在开会，时常与产品经理吵闹。在大多数公司，产品经理与程序员是平级的，而在这公司，却不同，可能是产品驱导型的吧，产品经理像是小组里的老大，绩效评分，包括其他的一些决定，都由产品经理来主导。说说自己的想法吧，一个产品的好坏，固然产品经理重要，但也不能忽视程序员及测试的感受吧。现在开会大多数时候，产品就说几个字，我们这功能不管怎样，这个月底要上线，请你给我做出来，当然，我们的估时从来都是不听的，我说我东西这周这些时间肯定完成不了，他说肯定可以，当然你可以你来就是了。当然你又会说，你不是吃这门饭的，说到底，就是气势压人一等，话就可以放大声。这就是所谓的工作吧，其实有时候就在想，如果才能让团队有干劲，能够服从安排，能够心甘情愿的付出，其实很简单，能同甘共苦，能够自己做好表率，你一个产品，有时候给出的东西都是有缺陷的，你让人怎么按时完成，你一个产品，有时候别人工作的时候，你让人帮你查数据，一查就是一天，这部分估时算在谁身上呢。所以，你给功能定时的时候，想想有多少时间你把别人的给占用了。你是否考虑过别人，明明上周估的是两周，当然，周一请假，周二定时间，给你查数据一天，自己就两天的开发时间，你算5天，够牛逼的。有时候就算你说两周，但你也得看看你把人家消费的时间给弥补上去啊，难不成那些时间都得周末去补上? 其实人是该为自己争取权利的，我不再是以前的傻瓜了，完不成你想开掉我就开掉我，我自认为我也问心无愧。当然你认为我能力不行，我调岗，你招新人顶上就是。
我们都在为生活奔波，有时候这些委屈就只能自己承受着。成年人的崩溃，确实有时候就在那么一瞬间，你想要稳定，不一定别人愿意给你稳定。在三十岁之时，不再像年轻20来岁时那么意气用事，因为那时候不开心就是直接离职了，连吵都懒得吵，但生活的压力与能力的要求，这种年龄段就让人很纠结。只有自己强大，才有更多的选择权。
生活不易，且看山高水涨，却有心无力； 三十而立，纵使世间万般亏待，也应乘风破浪。</description>
    </item>
    <item>
      <title>计算机网络系列 - 笔记</title>
      <link>http://www.huasay.com/2020/08/15/computer-network-series/</link>
      <pubDate>Sat, 15 Aug 2020 23:02:52 +0800</pubDate>
      <guid>http://www.huasay.com/2020/08/15/computer-network-series/</guid>
      <description>此系列用于记录计算机网络相关的知识要点
一来，复习巩固这一块的知识，防止每次用到相关知识却各种的查找资料。
二来，加强这一块的学习，自己之前也有很多不懂的地方，需要记录与学习
目前分以下下节整理
物理层 数据链接层 传输层 3.1 传输层 - TCP 3.2 传输层 - UDP 网络层 应用层 常用协议 DHCP 常用协议 ICMP 常用协议 ARP DNS </description>
    </item>
    <item>
      <title>人生克星 - 皮肤病</title>
      <link>http://www.huasay.com/2020/08/10/get-ill/</link>
      <pubDate>Mon, 10 Aug 2020 21:46:41 +0800</pubDate>
      <guid>http://www.huasay.com/2020/08/10/get-ill/</guid>
      <description>想不起多少次得皮肤病了，印象中，学生时代，以前每个暑假开始，我就步入得皮肤病的节奏。这导致我每个暑假都过得很不舒心，有一半时间都在骚痒的时光中度过。
我一直都想不明白，一个粗糙的男生，皮肤会如此脆弱。动不动就来这一遭，毁了学生时代的美好暑假。心想，毕业工作了，不在外面浪了，总不会还频频得皮肤病吧。然而，工作后，依然还是逃不过老天所谓的‘眷顾’，对，它还是来了，虽会迟到，但从未缺席。想起那年夏天去找工作，本来信心满满的去苏州，住进旅馆才两天，好好的一个人，就先进了医院，人生地不熟的，满身的红疹子，在一家中西医馆中看了病蒸了桑拿，过了好一段时间才有好转，而找工作就暂时搁浅了。
旅馆是皮肤病容易引起的高发原因，自己因为住旅馆至少3次导致了发病，因为他们的有些床单并未清洗干净，还有各种螨虫在，因此很容易导致皮肤过敏。这次也不例外，而且越来越严重，从小颗粒状变成片状，从微红变成紫色。不得已还是去了医院，近些年来，去医院的频次也越来越高了，身体上的力不从心，这种感觉变得越发强烈，想想就感觉到绝望。
生活不容易，此时的我心力交悴。我心里多希望病痛离我远一点，而自己却感觉离他们越来越近。为什么我越排斥，它却越粘着我，恳请放过我。</description>
    </item>
    <item>
      <title>Manjaro 如何安装旧版本软件</title>
      <link>http://www.huasay.com/2020/08/05/manjaro-install-old-version/</link>
      <pubDate>Wed, 05 Aug 2020 17:51:03 +0800</pubDate>
      <guid>http://www.huasay.com/2020/08/05/manjaro-install-old-version/</guid>
      <description>manjaro的包更新机制导致其pacman包管理的下载的都是最新版软件。而往往有些时候我们并不需要最新的，如何解决呢？
我们可以两种方式解决
方式一 使用downgrade 使用downgrade命令的前提是你之前已经安装过该软件包。如没有安装过，则跳过看方式二。
首先需要安装downgrade包
1 ➜ sudo pacman -S downgrade downgrade的用法很简单
1 用法： downgrade [option...] &amp;lt;包&amp;gt; [包...] [-- pacman_option...] 比如我要降级goland
1 2 3 4 5 6 7 8 9 10 11 ➜ sudo downgrade goland Downgrading from A.L.A. is disabled on the stable branch. To override this behavior, set DOWNGRADE_FROM_ALA to 1 . See https://wiki.manjaro.org/index.php?title=Using_Downgrade for more details. 可选的包： - 1) goland 2019.2.5 1 x86_64 (本地) - 2) goland 2020.</description>
    </item>
    <item>
      <title>Leetcode 26 最长公共前缀</title>
      <link>http://www.huasay.com/2020/07/29/leetcode-14/</link>
      <pubDate>Wed, 29 Jul 2020 14:26:49 +0800</pubDate>
      <guid>http://www.huasay.com/2020/07/29/leetcode-14/</guid>
      <description>编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀，返回空字符串 &amp;ldquo;&amp;quot;。
示例 1:
1 2 输入: flower&amp;#34;,&amp;#34;flow&amp;#34;,&amp;#34;flight&amp;#34;] 输出: &amp;#34;fl&amp;#34; 示例 2:
1 2 3 输入: [&amp;#34;dog&amp;#34;,&amp;#34;racecar&amp;#34;,&amp;#34;car&amp;#34;] 输出: &amp;#34;&amp;#34; 解释: 输入不存在公共前缀。 说明:
所有输入只包含小写字母 a-z 。
解题思路:
leetcode官方提供了不少解决方案. 主要解决方案有: 横向扫描法, 纵向扫描法,分治法, 二分查找法, 字典树. 个人觉得纵向扫描法是最容易想到的,而且效率也不错.
纵向扫描法:
纵向扫描时即依次遍历所有字符串的每一列，比较相同列上的字符是否相同，如果相同则继续对下一列进行比较，如果不相同则当前列不再属于公共前缀，当前列之前的部分为最长公共前缀。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func longestCommonPrefix(strs []string) string { strsLen := len(strs) if strsLen == 0 { return &amp;#34;&amp;#34; } for i := 0; i &amp;lt; len(strs[0]); i++ { for j := 1; j &amp;lt; strsLen; j++ { if i == len(strs[j]) || strs[0][i] !</description>
    </item>
    <item>
      <title>Leetcode 350 两个数组的交集 II</title>
      <link>http://www.huasay.com/2020/07/28/leetcode-350/</link>
      <pubDate>Tue, 28 Jul 2020 23:19:42 +0800</pubDate>
      <guid>http://www.huasay.com/2020/07/28/leetcode-350/</guid>
      <description>给定两个数组，编写一个函数来计算它们的交集。
示例 1：
1 2 输入：nums1 = [1,2,2,1], nums2 = [2,2] 输出：[2,2] 示例 2:
1 2 输入：nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出：[4,9] 说明：
输出结果中每个元素出现的次数，应与元素在两个数组中出现次数的最小值一致。 我们可以不考虑输出结果的顺序。 进阶：
如果给定的数组已经排好序呢？你将如何优化你的算法？ 如果 nums1 的大小比 nums2 小很多，哪种方法更优？ 如果 nums2 的元素存储在磁盘上，磁盘内存是有限的，并且你不能一次加载所有的元素到内存中，你该怎么办？ 解题思路【哈希法】：
将其中一个数组转换成哈希Map的类型，key为数组的值，value为数组中该数出现的次数。
循环遍历另一个数组，通过Map中是否有该值来判断，如果有相同的值，则记录该值，同时将Map对应key的value值减1.
时间复杂度：O(max(n,m))
空间复杂度：O(min(n,m))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func intersect(nums1 []int, nums2 []int) []int { m := map[int]int{} ret := []int{} for _, v := range nums1 { m[v]++ } for _, v := range nums2 { if m[v] !</description>
    </item>
    <item>
      <title>Leetcode 26 删除排序数组中的重复项</title>
      <link>http://www.huasay.com/2020/07/27/leetcode-26/</link>
      <pubDate>Mon, 27 Jul 2020 15:18:01 +0800</pubDate>
      <guid>http://www.huasay.com/2020/07/27/leetcode-26/</guid>
      <description>给定一个排序数组，你需要在 原地 删除重复出现的元素，使得每个元素只出现一次，返回移除后数组的新长度。不要使用额外的数组空间，你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 1:
1 2 3 给定数组 nums = [1,1,2], 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 你不需要考虑数组中超出新长度后面的元素。 示例 2:
1 2 3 给定 nums = [0,0,1,1,1,2,2,3,3,4], 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 你不需要考虑数组中超出新长度后面的元素。 说明:
为什么返回数值是整数，但输出的答案是数组呢? 请注意，输入数组是以“引用”方式传递的，这意味着在函数里修改输入数组对于调用者是可见的。 你可以想象内部操作如下:
1 2 3 4 5 6 7 // nums 是以“引用”方式传递的。也就是说，不对实参做任何拷贝 int len = removeDuplicates(nums); // 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 for (int i = 0; i &amp;lt; len; i++) { print(nums[i]); } 思路:</description>
    </item>
    <item>
      <title>golang channel</title>
      <link>http://www.huasay.com/2020/07/25/golang-channel/</link>
      <pubDate>Sat, 25 Jul 2020 11:10:05 +0800</pubDate>
      <guid>http://www.huasay.com/2020/07/25/golang-channel/</guid>
      <description>channel是golang中重要的组成部分。也是协程通信间通信的方式
channel常见理论面试题 channel 什么情况下会出现panic 试图往已close的channel继续发送 试图关闭已关闭的channel 试图关闭一个nil的channel 向为nil的channel发送数据会怎样 给定一个 nil channel c:
&amp;lt;-c 从 c 接收将永远阻塞
c &amp;lt;- v 发送值到 c 会永远阻塞
channel close后读的问题 关闭后继续读数据，已在缓冲区内的可以读取到数据，而后得到的是零值(对于int，就是0)。
我们可以通过for循环遍历channel，来获取到已经写入的值
1 2 3 for _, v := range channel{ } 对于可能获取到零值，我们可以使用断言判断，ok为false代表channel已关闭后读取的
1 value, ok := &amp;lt;- channel 也可以在close channel之后有意将channel 置为 nil， 如此再使用，并不会读取到零值
对于不带缓冲的ch，和带缓冲的一样，channel close掉之后并不影响读，只影响写入
channel底层源码剖析 go的运行时源码在runtime/chan.go文件下，可以在该文件下查看具体的数据结构，send(channel &amp;lt;-),receive(-&amp;gt; channel)，close channel等操作
数据结构 1 2 3 4 5 6 7 8 9 10 11 12 type hchan struct { qcount uint // total data in the queue 代表 chan 中已经接收但还没被取走的元素的个数。内建函数 len 可以返回这个字段的值。 dataqsiz uint // size of the circular queue 循环队列的大小 buf unsafe.</description>
    </item>
    <item>
      <title>夜无眠 - 深夜</title>
      <link>http://www.huasay.com/2020/07/24/deep-night/</link>
      <pubDate>Fri, 24 Jul 2020 00:43:26 +0800</pubDate>
      <guid>http://www.huasay.com/2020/07/24/deep-night/</guid>
      <description>一：天气炎热 自从被骗后，夜里一两点睡觉已是家常便饭了，有时候并不是睡不着，而是心中压着的大石，总是让人在深夜想起来，这种感觉说不出来怎么形容。而天气的燥死，为自己深夜里无法入眠更加一筹。
二：淡忘过往 曾经相信世间所有的美好，无比想念以前的时光。有人说，那是因为现在过得不开心，生活不遂人意，才会怀念曾经。细想来这话也一点毛病也没有，如果现在过得好，肯定是沉醉于现在，又何必去想往事的美好呢。 深夜里，曾经多少次给自己打气加油，让自己能有勇气想起悲伤的事时，也不会难过的无以复加。但其实，不去想才是真正可以让人淡忘的。不去想这些，是不是生活会更舒心一点。但精神上的麻醉实在太难了，天天玩游戏，天天刷视频，其实也只是麻醉了短暂的时间而已。我向来是对这种状态嗤之以鼻的，而现在却只有这种状态才能把自己麻痹了，也真是讽刺与无奈。我渴望有朋友的关怀，渴望有朋友的记挂，但我不知道我还有没有这样的朋友。也许曾经有吧，现在已经没有了，不然，为什么有些人不会再来关心你了呢，我自己大抵上有时候会失望，大多数时候还是默认了其实他也不是我最好的朋友了。分开后，形同陌路，也好也罢，经历了这么多，也看开看淡了。
三：强大自己 我想我该怎样才能站起来，让自己着眼于现在，让现在更精彩一些，不至于魂不守舍，不至于时常崩溃。可能多学点技能让自己强点才能让自己摆脱现状吧。</description>
    </item>
    <item>
      <title>linux 常用命令</title>
      <link>http://www.huasay.com/2018/04/12/bash/</link>
      <pubDate>Thu, 12 Apr 2018 22:06:21 +0800</pubDate>
      <guid>http://www.huasay.com/2018/04/12/bash/</guid>
      <description> Tab 键：自动补全命令或文件名； 2. Ctrl + C：强制退出当前进程或程序，中断正在运行的命令； Ctrl + Z：挂起当前进程或程序，将其放到后台执行； Ctrl + D：退出 shell 终端； Ctrl + L：清屏，与 clear 命令相同； Ctrl + A：将光标移动至命令行的开头； Ctrl + E：将光标移动至命令行的结尾； Ctrl + U：删除已输入的命令行，回到光标所在行的开头； Ctrl + K：删除光标所在位置到行末的所有字符； Ctrl + W：删除光标所在位置的前一个单词； Ctrl + R：搜索之前执行过的命令； !!：调出上一次执行的命令。 Ctrl + Y：粘贴最后一次删除的内容 Alt + B：将光标向后移动一个单词 Alt + F：将光标向前移动一个单词 Ctrl + B：将光标向后移动一个字符 Ctrl + F：将光标向前移动一个字符 !command：调出上一次以command为首的命令。 </description>
    </item>
    <item>
      <title>似水年华 - 写在2015</title>
      <link>http://www.huasay.com/2015/12/31/write-in-2015/</link>
      <pubDate>Thu, 31 Dec 2015 23:46:10 +0800</pubDate>
      <guid>http://www.huasay.com/2015/12/31/write-in-2015/</guid>
      <description>此时的我，在2015的最后的1个小时里写着今年的总结。忽然想起今年的第一天，也写了篇，叫流年，然后已到年末，又体会了一把流年。
2015，经历颇多，在已职满两年的公司辞职，然后回家休养生息 ，继尔去各省流浪，回来再找新工作，直至到年尾，心中却也想着再次辞职，一年的心似乎从未安定平稳，一直在游离，我时常问自己，是喜欢安稳还是喜欢漂泊，我却给不出答案，到了这年纪，却把早些年大胆的想法与规划慢慢抛弃，变得更加现实，人啊，总是会向实现低头，曾经不以为然，现在却深信不疑。
2015，我依旧是一个人，一个人漂泊，一个人逛街，一个人干任何事，我常常自我安慰，我已经习惯了这种孤独，其实细想这是事实，而不仅仅是自我安慰，从小到大的孤独，我反而觉得一个人独处的时候是最自由的，那个时候的我才是真我，与别人相处着的我多少都带着伪装的面具，要问我2016是否还继续一个人，如果可以，我还真想就这么一个人过着。
2015，健康是一大问题，晚上不停的熬夜，那个黑眼圈我感觉一年都没消过，也是的，一年中，真正在12点之前睡的又有几天呢，恐怕估计可以数过来吧，在入职新公司的那些日子里，肚子时常痛，低血糖的毛病又犯了，只是有了上次的经验，自己也不会那么轻易让自己晕倒，公司体检出来的毛病很多，尽管大多数可能只是耸人听闻，但也已经给自己敲响警钟，对，健康永远那么重要，没有健康的身体，做什么都力不从心。
2015，曾经以为是挚友的，也可能因为某些原因而导致关系破裂，曾经以为不可能再联系的，也开始破冰，尽管感觉关系也不再如前，我时常在想，如果当初我不那么固执，不那么斤斤计较，是否友情会更长久，我始终为这些事而内疚而耿耿于怀。我想如果可以，能不能重来一次
2015，人生就这样过着， 那些平淡无奇过往的痕迹有迹可循，希望我能从这些痕迹里得到的感悟，能在新的一年里领悟。
2016，但愿曾经一起走过的朋友能继续一起走下去，也祝愿大家拥有健康快乐的2016。。。</description>
    </item>
    <item>
      <title>似水年华 - 雪，生日</title>
      <link>http://www.huasay.com/2015/12/05/snow-birthday/</link>
      <pubDate>Sat, 05 Dec 2015 22:20:10 +0800</pubDate>
      <guid>http://www.huasay.com/2015/12/05/snow-birthday/</guid>
      <description>杭城15年的第一场雪悄然而至，犹记得14年盼了整年也不见雪花飘零，未曾料及15年降临的如此之早。然而，等我发现的时候已是傍晚时分，多少有点懊悔自己一天躺床上，不闻窗外事，以至于外面发生了什么都不曾知晓。所幸一天三餐总不能都不吃，为了吃个晚饭我也得起床看看外面的世界。
雪花飘飘洒洒，地上由于积雨并未能积雪，而树上以及车背上，都铺上了薄薄的一层白雪，对于雪，我天生注定是有种厚爱的感情在的，南方不像北方，雪是常见的，在还小的时候，期盼下雪就像期盼过年一样，两两三三，嘻戏玩闹，别有一番气象，我喜欢穿着雨鞋踩在雪上的感觉，我喜欢在雪上印上脚印以及文字，我喜欢雪融化的声音。怀着满心的期待，撑着小破伞，有雪的日子天气总是较冷的，今天确实也挺冷的，冷风刺骨，由于今天是生日，在附近找了家面馆，点了份面，对于面，我平时都不喜欢吃，然而今天那份面不知道为何就感觉那么好吃，最后连汤都不剩，也许这与心情有关吧，也许是一天的饥饿的缘故吧，也许和天气也有些许关联。。。
吃完面出了店面，驻足了好一段时间，在那欣赏白雪飞扬，特别在路灯的映照下，光与景的融合，也是有特别的味道的，转身回家，只愿明天大地也已铺满积雪。
雪代表祥瑞，生日与今年的第一场雪同一天，是不是代表我这一年将是丰年
最后谢谢还记得今天是我生日的朋友，谢谢你们的祝福，也希望你们健康快乐</description>
    </item>
    <item>
      <title>暴雨过后 - 雨</title>
      <link>http://www.huasay.com/2015/02/25/rain/</link>
      <pubDate>Wed, 25 Feb 2015 22:14:55 +0800</pubDate>
      <guid>http://www.huasay.com/2015/02/25/rain/</guid>
      <description>已经许久没写日记，兴许是懒得整理思绪，抑或是早已丢掉了常写日记的习惯。在一场雨中，撑着破伞等公交，街道早已积水各处，而在夜晚行走在其中，有点压抑，那种压抑，像是想把伤心往事逼上脑海中不停地让你想，直到一件件的往里面堆积，然后爆发，然后脑海里也开始积满了那些伤感，那些由水积成的伤感，而这种现象就称之为脑子进水。
在一个路口，灯光有些黯淡，要乘的公交恰好转瞬而过，那意味着，在这雨天的夜晚，我又得静静地呆上那么十几分钟甚至几十分钟，走至站牌，脚的触觉告诉我鞋子已经进水了，雨还在嘀嘀嗒嗒作响，曾经，那一年，我离开家乡，去读大学的那天，就是在一个雨天;曾经我说过我喜欢雨，它能洗净的我眼泪与心灵的不纯洁;曾经，连续的半个月雨，我在病房中陪着病重的外公;曾经，外公去世我回家的那天雨下的格外大，在院子里撑起的小棚几次崩踏;曾经，就是在去年，也是上班的第一天，雨一直下，下了整整一个春天，敲醒了沉睡的大地，却敲碎了我的心。从此，我似乎不再喜欢雨了，它没有洗净我的心灵，却让我成为一个脏兮兮的男孩。所有的这些，就像那些无声的悲伤一样让人心情烦躁不安， 就像那些等待让人焦灼难耐，就像所有的心思涌上来止不住一样，才知道雨是另外一个世界的，我们隔着一层伞，谁也走不进谁的心，更是谁也理解不了谁。
车来了，放射出的红色二极管的光，有点刺眼&amp;hellip;</description>
    </item>
    <item>
      <title>似水年华 - 流年</title>
      <link>http://www.huasay.com/2015/01/01/flow-year/</link>
      <pubDate>Thu, 01 Jan 2015 00:07:24 +0800</pubDate>
      <guid>http://www.huasay.com/2015/01/01/flow-year/</guid>
      <description>染指流年，又只留下一年的回忆&amp;hellip;
曾听人说，本命年便会流年不利，我不以为意，甚至不以为然，直到某月某日，忽然细细回忆，平平淡淡的一年，无波无澜，思想与行动却被侵蚀得支离破碎。不禁心中一颤，人生，意义在哪里&amp;hellip;
所谓的意义，也曾经多少次质问自己， 那些轻描淡写的轨迹上竟然找不出让人欣喜或者让人激动的那么一瞬间。
我所期待的今年的爆发，我曾幻想着事业的前进与蒸蒸日上，直到年底，那些赶工，那些漏洞，那些问题依然还存在，忐忑不安甚至焦虑，与年初的拥有点小自信的自己，那么鲜明的反差，让自己无法面对，甚至指责自己。也许执行力真是差了点而让自己陷入了窘境。
我所期待的感情，就像云烟，最后散了&amp;hellip;那种落寞，让自己无所适从，依靠与依赖的太深，导致那一时的崩溃，在崩溃的边缘甚至找不回自己，那时我还是太年轻了，曾经标榜着自己成熟，直到那一刻开始，才知道自己还是太稚嫩&amp;hellip;然后渐行渐远，渐行渐远&amp;hellip;也许是不着边际的远，让人心寒。
我们总是事后诸葛亮，总结的时候写得很好，而却始终不能做到未雨绸缪。抛开那些不切实际的暇想，抛开那些矫情忧郁的情绪，是不是能够看见阳光能灿烂点&amp;hellip;
不想感概什么，只想在新的一年里愿自己能够开心的笑&amp;hellip;只有那种笑才能感染自己的生活&amp;hellip;一潭死水般的生活&amp;hellip; 也祝愿朋友们健康快乐&amp;hellip;</description>
    </item>
    <item>
      <title>异乡聚 - 思念</title>
      <link>http://www.huasay.com/2014/09/08/miss/</link>
      <pubDate>Mon, 08 Sep 2014 22:53:50 +0800</pubDate>
      <guid>http://www.huasay.com/2014/09/08/miss/</guid>
      <description>早已忘记了思念是什么感觉，就像一个人，在心中的位置慢慢地消淡，那么地模糊，有种感觉源于思念，毁于思念。
夜色渐晚，伴点秋风，偶尔零星小雨，我独自一个人行走在小道，黑暗带点落寞，打开手机，看着通讯录，想拨打，却在犹豫。终究还是在黯然灯光下，独自神伤，在灯光的映衬下，雨点有时变得如此明显，每滴落一次，就像击中心底的那些弦，有点神经突然抽搐的感觉。人不知道所以然，在那一条长长的小道上来来回回渡步，直至把心头的那些曾经的思念或者心头的那些烦恼或者那些压抑或者那些本来该做本来想做的想法踱得一干二净。或许空白的脑海才适合我。我终究还是转身离开把手机放回口袋，将那些思念原封不动存回至他们原来的地方。
抬头望天，寄希望于明月相思也能寄千里，无奈，天公不作美，那些浓厚的云层里伴着灯光，发出来的假假的光线，显得那么不自然，就像我心里的那份不自然一样。失望，确实有点失望&amp;hellip;低下头走回家，那个家，只有我一个人，当然也还能记起中午爸妈还在时的那副景象，那是仅存的一点慰藉了。我们都不容易，他乡异客，搁至往年， 你在彼乡，我在此乡，也许也只有过年才能团聚。
我把那份思念变成了文字，却无法带给你，那些我爱的人们&amp;hellip;这一次，我又失约了。</description>
    </item>
    <item>
      <title>行走 - 西湖行</title>
      <link>http://www.huasay.com/2014/09/07/the-west-lake/</link>
      <pubDate>Sun, 07 Sep 2014 16:48:10 +0800</pubDate>
      <guid>http://www.huasay.com/2014/09/07/the-west-lake/</guid>
      <description>来杭城已一年，却很少去西湖，一是没人陪，二是长在江南的人似乎对这些山山水水的景色并不感冒。上次游西湖已是去年了，而与西湖的渊源可以追溯至初二，那是我第一次也是来杭前的惟一一次，我记得那时与表弟，舅舅及外婆爸妈一起去的，这是那一次仅存的记忆了。
本着中秋三天不能全宅三天的想法，所以还是抽一天去外面走走，而西湖还算是个好的选择吧.久违的西湖，是否还能一见如故，沿着葛岭至断桥，远望，断桥上的行人络绎不绝，但没有想象之多，也许还假日第一天吧。从葛岭沿湖至断桥，旁边大亭俨然已被老年人所占，老年活动中心，当然也挺欣赏一群可爱的爷爷奶奶，在那里奉献一首又一首他们那个时代里经典的歌。行至断桥，各路摆拍人士已占领桥的各处，有时乱入镜头也尴尬的遭到摆拍者的白眼。桥侧一旁荷莲密集，遗憾的是错过了荷的花期，偶尔也有几朵含苞待放的，偶尔也能见到正盛开至美的，然而在一大片的荷莲深处，显得那么美丽却又如此的让人失望，让人不禁一叹，游西湖得等到荷开之时才别有一番韵味。站在断桥上，眼界还是很开阔的，两边湖水在微风下荡漾。远处的游船不一而行，不知道哪天游客爆棚的时候，又该是怎样的一番情形，游船占领着湖面也很壮观吧。断桥行毕，踏入的是白堤了，白堤两侧，放风筝的大叔们是一道亮丽的风景线，有时风筝飞至高得肉眼也看不见，而有时风筝飞至湖面上方，夺人眼球的莫过于雄鹰状的了，栩栩如生，像雄鹰在翱翔，甚是霸气。情侣与游客，还有小商贩们当然还有摄影爱好者，白堤上一路都有他们的身影。白堤两侧，有作为西湖十景的平湖秋月，当然白天去看不出任何秋月的味道，赏月之地中秋夜肯定是熙攘之地了。
走马观花般看完平湖秋月，右侧行至几十米，即为博物馆了，各种博物馆坐拥， 看惯了外面的山山水水，不妨进去看看里面的历史，当然这次我还是没有进去，下次有机会再进去吧。再走便是清行宫遗址了，是清代多位帝王出行西湖时的居住之地，坐落于孤山脚下。对于有历史底蕴的景点与还是历史知识缺乏的我，大概瞄了几眼便走了，当然行至此处，一对夫妻在那里揣测里面的树是什么树，是柿子还是杏子，我感觉是柿子，那上面结得果实实在太像柿子了。离开，便是著名的楼外楼，怎么个著名法，听路人说，有首诗是“山外青山楼外楼，西湖歌舞几时休”里的楼外楼就是指该楼，我听了听，好像似乎是有那么个道理在，但反应过来感觉当初的语文老师不是这么教的，然后在楼外便百度了一下，果不其然，我被路人误导了。再往前便是西冷印社了，是国家非物质文化遗产吧，第一任社长是吴昌硕，似乎还是听过这个名字的。行至西冷桥，右侧便是孤山入口，一旁便有秋瑾墓，而西冷桥的另一侧，便是钱塘苏小小之墓了，再过一个路口，便是武松之墓。不知是不是之后修建的，总感觉是为了景点而融合墓地。而孤山路与北山街的路口，便是苏堤的南面入口了&amp;hellip;相比白堤，苏堤两侧的树木更茂盛，像是在林荫大道中&amp;hellip;当然走完白堤已经累得不行的我，在苏堤并没有仔细看其周边景点，曲院风荷印象最深的却是一旁的小猫咪，真是猫咪泛滥，但小猫的可爱，真让人想抱只回家。而花港观鱼，却少了点雅致，没有多大吸引力。
而这一趟西湖行，走得却是很累的，像一个匆忙的过客，疲惫里带着倦意，多少其实有些失望，就像路上也听到有些失望的游客一样，名气太大而带来的失落感&amp;hellip;一度曾经让我迷失在一个问题，旅行的意义是什么，走马观花不如不走，以前在苏州也在想，现在在杭州也在想，无论怎么的天堂美景，却提不起多大雅兴，而藏在我心底的旅行梦，是否只是个空壳&amp;hellip;我在怀疑我的动机，从以前到现在，也许未来也一样。</description>
    </item>
    <item>
      <title>似水年华 - 9月</title>
      <link>http://www.huasay.com/2014/09/06/september/</link>
      <pubDate>Sat, 06 Sep 2014 00:44:33 +0800</pubDate>
      <guid>http://www.huasay.com/2014/09/06/september/</guid>
      <description>9月是特殊的一月，回忆在脑海里一长串的足迹，在那年9月，我认识了我最喜欢的人，在那年9月，我只身来到杭州，而在此时，细细想来，已来杭州一整年，也喜欢一个人将近2周年了，那些发生在9月的事情，总在脑海里挥之不去，无论是喜抑或是悲，所有的故事或者所有的心结我希望在9月能够告一段落。
繁忙的8月份，也不知道从何时用繁忙两字来形容，或者是工作带来的压力吧，或者是自己又找了个借口为8月份的逝去而掩饰自己内心的不安。以一次搬家作为8月与9月的过渡，那是一件让人很费心的事情，独身一人，因为性格的原因，在这样的一个城市我并没有什么朋友，什么事自己都得想办法，有时也会为自己的智商而买单，有人说那是为自己的智商交智商税，我听着似乎也是挺合理的。对于新家，谈不上多满意，也谈不上多失望，毕竟也算是栖身之所，我喜欢一个人坐在窗上默默的发呆&amp;hellip;
过两天就中秋了，爸妈他们说到杭州来工作一个月，刚好中秋他们也在杭州，以前你们是漂泊的人，我甚至一年只能见你们一两次，一直过着寄宿的生活，这一点我一直都耿耿于怀，也许就像我现在，也和你们当初一样在外面漂泊，才能更深的理解你们吧。希望中秋你们有空，我们可以在异地能团聚一次。不然可能又得到年底过年时分才能相见了。
现在的我，在如此安静的夜晚，心似乎还能平静下来想一些事情，一直对自己的人生的规划很不明朗表示很迷茫&amp;hellip; 我不知道我将来会怎样，就像那一连串的省略号，如此漫长却又只能一直走下去。我希望有一天我也能脑子突然开窍，想通一些事情，想通以后该怎么走，以至于不会做一个纠结体。
今年9月，明年9月，给自己一个9月之约&amp;hellip;</description>
    </item>
    <item>
      <title>七夕 - 属于他们的狂欢</title>
      <link>http://www.huasay.com/2014/08/02/their-happy/</link>
      <pubDate>Sat, 02 Aug 2014 22:34:44 +0800</pubDate>
      <guid>http://www.huasay.com/2014/08/02/their-happy/</guid>
      <description>每一个不属于我的节日来临之后，我总会矫情一番，或者眼光里伴着嫉妒，或者情绪里还夹带些不屑，总之，那天的心情是复杂的&amp;hellip;特别是那些团聚爱情之类的节日，对于漂泊在外的单身人士来说，那是一剂猛药，落寞感也随之袭来。七夕将末，此时鹊桥上的他们也度过了属于神话里的那一天&amp;hellip;而随即而来的又是一年的期待&amp;hellip;我曾被这凄美的爱情故事感动得潸然泪下，也感叹于他们的爱情之永恒，后来，我想，这到底只是神话里的故事吧&amp;hellip;故事终究是故事，带给你的是感动，留给你的是幻想。
今天的天气有些微凉，对于夏季来说，是再合适不过的天气了，而这样的天气，你即使抬头望天，也看不出漫天星辰，似乎在这样的晚上，鹊桥相会少了点光芒&amp;hellip; 白天，在凉风习习下，独身走至运河边，杨柳飞扬，带点惬意的遐想。两侧时而可以看到一对对的情侣相拥而坐而牵手而走，河上的油轮来来回回，游船也时而飘过&amp;hellip;远处的公交船也凑起了热闹，当然这些其实不是今天的专属，只是在特别的日子，总让人看出特别的氛围。杨柳依依，古时折柳送别，让人总感觉柳与送别悲伤之情相联系，多少有点让人心中有点离别之痛，当然，这只能怪我联想力太丰富，估计也是矫情多了的缘故&amp;hellip;
在外面看了风景，自然是回窝了，因为今天的风景实在太美，所以我感觉趁早的回窝睡觉比较实在&amp;hellip;然后在午后，大睡&amp;hellip;似乎窗外的一切门外的一切都不属于我一样&amp;hellip;世界宁静了&amp;hellip;今天就是个周六嘛&amp;hellip;</description>
    </item>
    <item>
      <title>似水年华 - 忆夏</title>
      <link>http://www.huasay.com/2014/07/23/remember-summer/</link>
      <pubDate>Wed, 23 Jul 2014 22:57:39 +0800</pubDate>
      <guid>http://www.huasay.com/2014/07/23/remember-summer/</guid>
      <description>此时，架着一台风扇，吹出来的风是微热的。当同事说你房间里没有空调，这个夏天该怎么熬过去的时候，我表现得很淡定。没有一个夏天，我是在空调房里睡的，真的，从小到大，尽管记忆已模糊不清，可夏天的记忆却是那么深刻，像是夏天会发生什么大事一样。
去年此时，我在上一家公司辞职，而我在辞职后接下公司的最后一个项目，在租的顶楼房间里，阳光直射，把整个房间烘得如开水房一般，那段时间，我工作到夜里4-5点，也只有夜里的温度才能保证工作效率，白天，我却用睡意抵挡炎热，而醒来后，第一件事就是将房间搞开一个水房，倒入一桶又一桶的水以抵制温度，在熬过20天之后，完成了项目，领了4000元我一直在问到底值不值&amp;hellip;随后我离开了那个城市&amp;hellip;在炎热中，工作还得找，为了养活自己，一个人去苏州，那是我第一次一个人出省，苏州，不知道因何原因去，也许是因为上有天堂，下有苏杭吧，在苏州，住进一家家庭旅馆，也只有家庭旅馆一天10多块或20来块的住宿费才能维持更长的找工作历程，然而，住进的第二天就长了皮肤病，第三天全身蔓延，当时真得很沮丧，失望，甚至不知道接下来怎么办&amp;hellip;思左想右，还是去了趟医院，而后，就花了这里的第一笔钱500，说实话，当时挺心疼的，毕竟我还算是个钱奴。在炎热中奔波，在苏州待了20天，失意怅然，卷了行李走向杭州，苏杭，以苏为起点，以杭为终点，然而我累了，在杭州仅仅待了一星期，就定下了工作，一直到现在，想想也将近在这公司工作了一年了，且不论好坏，毕竟我们同甘共苦走过，我们必须还要前进。
且不忆了，忆昨惜今。仅当作今晚心情烦躁时的一番回忆吧&amp;hellip;</description>
    </item>
    <item>
      <title>蝉想 - 捕蝉记</title>
      <link>http://www.huasay.com/2014/07/14/catch-cicadas/</link>
      <pubDate>Mon, 14 Jul 2014 22:28:54 +0800</pubDate>
      <guid>http://www.huasay.com/2014/07/14/catch-cicadas/</guid>
      <description>时值夏日，群蝉萌动，其声不绝于耳。清晨天还未通透，只闻蝉声已凌驾于天，声声催人起，睡眼惺松之际，叨叨几句，便再次闭眼。而在夜晚之时，夏蝉与蛙声缠绕一起，往往都伴着此声作为催眠曲，才能入眠。
今日 ，因口渴而入一小卖部，结付款之时，忽一人惊讶问收银员，你听，此声为何叫吵不停？甚是感觉好奇，那人见收银员不语，便一阵追问，为何它能不间断叫，中间不停顿&amp;hellip;收银员答，这大概是知了在叫，那人还是一脸疑惑，我猜大概是外来人吧，江南夏季时节，蝉是必会按时来到的，至于北方或者西部，便不了解了。
付款毕匆匆回家，途中便遇一中年男人携其妇其女其子拿一类似鱼竿物捕蝉，我也顿感好奇，昔日捕蝉，必是亲自用手去捉，然成功率极其低下，蝉其反应，说其反应慢，其反应其实也快，说其反应快，有时发觉其反应也就一般如此罢了。再定眼看其儿子之手，执一网袋，袋里已裹近20来只蝉，蝉入袋，则安详得多，便不见其叫了。男人每听见蝉在树上呼叫，就前往树底仔细察观蝉之所在，然拿其手上长竿慢慢挪至蝉侧，蝉不觉，便突然将长竿往蝉处方向移，此时，蝉已挣扎不了，看长竿顶部似裹了大块粘胶物，将蝉翼牢牢粘住，蝉在挣扎却也无济于事。男人说，回家吧，烤蝉，其一大家子便兴奋往远处奔走，顷刻背影尽失。
蝉其一身，皆是药物，油炸金蝉更是被人津津乐道，几多人觊觎着你的身躯，夏蝉，我只想道一声，保重&amp;hellip;既然如此，为何还高调吟唱&amp;hellip;抑或是在为自己逝去而谱写悲壮之歌</description>
    </item>
    <item>
      <title>似水年华 - 此去经年</title>
      <link>http://www.huasay.com/2014/07/05/roll-around-of-days/</link>
      <pubDate>Sat, 05 Jul 2014 21:32:55 +0800</pubDate>
      <guid>http://www.huasay.com/2014/07/05/roll-around-of-days/</guid>
      <description>已不知从何说起,只是蓦然的想起,发现许久未曾写日记了,记忆里的那些本该深记的也悄悄地泛白,再回首,已是那些残缺的记忆碎片,拼接出来的那些不完整不完美的点滴.我开始想念,想念那时的自己,也开始谴责,谴责着现在的自己.我甚至不知道自己将来又该怎么走.那些迷茫时的惊惶失措,还在记忆里泛起涟漪&amp;hellip;迷茫带来的那种气息,使自己丧失了动力,开始安于现状,不求上进.
两年了,毕业已两年了&amp;hellip;再往前推的那个时刻是6年,那时带着的憧憬离开了家,去上大学,还记得那是第一次离开家,我依然记得,坐上车那时的忐忑不安,在老师的洗脑下,我们都以为大学是天堂,也许确实是天堂吧&amp;hellip;只是我与天堂隔了一层膜,融入不了&amp;hellip;在茫然中过了一年又一年,现在回首,大学里我到底做了什么,却无法想起一件让自己引以为傲的事情,忽然有种莫名的悲伤感袭来&amp;hellip;我似乎落后了,落后于他人一截又一截&amp;hellip;我甚至有点自抱自弃地在那里悔恨,这到抵是一个失败者吧&amp;hellip;从大学毕业后,我在想我学到了什么,是我不够努力么,还是我真得缺乏智慧,只是到头来想想,只是感觉这一切都是命运,似乎冥冥中命运注定的,人总不相信命运这东西的存在,可总喜欢拿命运来慰藉自己.但我相信所谓的命运,而我的命运,从以前到现在,似乎被性格决定了,性格决定命运,命运决定成败,有时想想也不无道理.也许只有这样想我心里才会好受点吧&amp;hellip;说到底,我是一个善于骗自己的人,正如有人说,连自己都骗,真狠,如果我真有那种狠劲,也许现在我的生活会比我想象的更美好些吧&amp;hellip;
我还是还是当初的自己么,我想我还是的,我还是很好强很较真的,我感觉自己做得不好自己我感觉自己比同学混得差,我心里不是滋味,我拒绝了所有的同学会,如果有一天,我也可以自信满满的,如果有一天,我也能让自己去参加同学会,如果有一天&amp;hellip;我希望那不是如果&amp;hellip;
想想这两三年,自己的心态得改变,不改变我依旧会是个小丑,有些事,本不该至于此,心却收不回来了,失魂落魄的,感觉我就这样让我的灵魂飘荡了两三年,两三年的青春啊,两三年的时光啊,我还在寻找灵魂的时候,别人却都在努力,我又何时把那刻游荡的心找回来呢,我又何时能安心的过着自己的生活呢&amp;hellip;有些事,有些人,过去的都让他过去吧&amp;hellip;
此去经年,应是良辰美景虚设,还记得那首词么&amp;hellip;此去经年,有良辰有美景,且过且珍惜吧&amp;hellip;</description>
    </item>
    <item>
      <title>雨中思绪</title>
      <link>http://www.huasay.com/2009/07/26/thinking-in-rain/</link>
      <pubDate>Sun, 26 Jul 2009 16:05:26 +0800</pubDate>
      <guid>http://www.huasay.com/2009/07/26/thinking-in-rain/</guid>
      <description>雨加快了步伐
而我却停住了脚步
看着行人紧张的神情
自己却有丝丝地喜悦
也许是久违的笑容
让我变得如此轻松
雨拍着我的肩
萌生出前所未有的鼓励
这是我多年的期盼
雨抚过我的心
那种无可言状的激情
复活了那曾经枯萎的心
雨轻吻着我的脸
一种莫名的快感
给了我多少勇气
也许时光没有风化掉的那段记忆
雨水可以冲淡
我在雨中徘徊
任凭风吹雨打
任凭痛消愁灭
雨滋润了我的心
我驻足在雨中
从未有过的舒适</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/shift-window/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/shift-window/</guid>
      <description></description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/ddd/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/ddd/</guid>
      <description>一些概念 领域（核心域，子域） 实体 仓库responsity 聚合根 限定上下文 防腐层 为什么要使用ddd https://www.infoq.cn/article/alibaba-freshhema-ddd-practice https://tech.meituan.com/2017/12/22/ddd-in-practice.html https://insights.thoughtworks.cn/architecture-from-sandwich-to-hexagon/</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/flow/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/flow/</guid>
      <description>我以 K8s 极简实战模块的示例应用为例，看看如何配置自动构建示例应用的前后端镜像工作流。在这个例子中，我们创建的工作流将实现以下这些步骤。
当 main 分支有新的提交时，触发工作流。 克隆代码。 初始化 Docker 构建工具链。 登录 Docker Hub。 构建前后端应用镜像，并使用 commit id 作为镜像的 tag。 推送到 Docker Hub 镜像仓库。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/es-principle/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/es-principle/</guid>
      <description>https://mp.weixin.qq.com/s/YhpxoPbJNMGPhUfj9PCTZg
es基于什么建立的？ es是基于开源的Lucene库写的一个搜索引擎，Elasticsearch 把操作都封装成了 HTTP 的 API，我们可以通过api快速操作es
概念 索引 用于存放数据的地方，对应mysql的库
类型 用于定义数据结构的，对应mysql的表
keyword类型与text类型的区别 Keyword 类型是不会分词的，直接根据字符串内容建立反向索引，Text 类型在存入 Elasticsearch 的时候，会先分词， 然后根据分词后的内容建立反向索引。
文档 最终的数据，相当于mysql表里的一条记录
分布式原理 Elasticsearch 会对数据进行切分，同时每一个分片会保存多个副本，为了保证分布式环境下的高可用。
倒排索引的原理 正排索引：通过id查找一条记录，通过某个字段查找一条记录，mysql的索引都属于正排索引，与倒排索引正好相反 倒排索引：一般用于全文搜索，首先会将我们的内容进行分词处理，拆分成单独的词(一般会去掉助词这些，我们称为词条或term)，然后每个分词，我们都可以直接索引到对应的文档，这就叫倒排索引
词条（term） 索引里最小的存储与查询单元，英文一般来说是一个单词，中文一般是内容用分词后的词
词典 （term dictionary） 是词条的集合，单词词典是指由文档集合中出现过的所有单词构成的字符串集合。单词词典内每条索引项记载单词本身的一些信息以及指向倒排列表的指针 ES 为了能快速查找到 term，将所有的 term 排了一个序，二分法查找。
倒排表（posting list） 一个文档通常是由多个词组成，倒排表记录的是某个词在哪些文档里出现过以及出现的位置。倒排表记录的不仅是文档编号，还存储了词频等信息。
postings list 如果不进行压缩，会非常占用磁盘空间。 联合查询下，如何快速求交并集（intersections and unions）。
①压缩
Frame of Reference：在 lucene 中，要求 postings lists 都要是有序的整形数组。
这样就带来了一个很好的好处，可以通过 增量编码（delta-encode）这种方式进行压缩。
比如现在有 id 列表 [73, 300, 302, 332, 343, 372]，转化成每一个 id 相对于前一个 id 的增量值（第一个 id 的前一个 id 默认是 0，增量就是它自己）列表是 [73, 227, 2, 30, 11, 29]。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/es/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/es/</guid>
      <description>logstash 的问题 Logstash 致命的问题是它的性能以及资源消耗(默认的堆大小是 1GB)。 尽管它的性能在近几年已经有很大提升，与它的替代者们相比还是要慢很多的。
因为 Logstash 自身的灵活性以及网络上丰富的资料，Logstash 适用于原型验证阶段使用，或者解析非常的复杂的时候。在不考虑服务器资源的情况下，如果服务器的性能足够好，我们也可以为每台服务器安装 Logstash 。我们也不需要使用缓冲，因为文件自身就有缓冲的行为，而 Logstash 也会记住上次处理的位置。
如果服务器性能较差，并不推荐为每个服务器安装 Logstash ，这样就需要一个轻量的日志传输工具，将数据从服务器端经由一个或多个 Logstash 中心服务器传输到 Elasticsearch：
filebeat 在版本 5.x 中，Elasticsearch 具有解析的能力(像 Logstash 过滤器)— Ingest。这也就意味着可以将数据直接用 Filebeat 推送到 Elasticsearch，并让 Elasticsearch 既做解析的事情，又做存储的事情。
Filebeat 也会和 Logstash 一样记住上次读取的偏移，如果需要缓冲(例如，不希望将日志服务器的文件系统填满)，可以使用 Redis/Kafka，因为 Filebeat 可以与它们进行通信。
Filebeat 只是一个二进制文件没有任何依赖。它占用资源极少，尽管它还十分年轻，正式因为它简单，所以几乎没有什么可以出错的地方，所以它的可靠性还是很高的。
Fluentd Fluentd 创建的初衷主要是尽可能的使用 JSON 作为日志输出，所以传输工具及其下游的传输线不需要猜测子字符串里面各个字段的类型。 这样，它为几乎所有的语言都提供库，这也意味着，我们可以将它插入到我们自定义的程序中。 因为在多数应用场景下，我们会通过 Fluentd 得到结构化的数据。 它的灵活性并不好。但是我们仍然可以通过正则表达式，来解析非结构化的数据。
三者区别 可以看出 Filebeats 功能比较单一，它仅仅只能收集本地的 log，但并不能对收集到的 Log 做什么处理， 所以通常 Filebeats 通常需要将收集到的 log 发送到 Logstash 做进一步的处理。 Logstash 和 Fluentd 都具有收集并处理 log 的能力，网上有很多关于二者的对比，提供一个写得比较好的文章链接如下。 功能上二者旗鼓相当，但 Logstash 消耗更多的 memory，对此 Logstash 的解决方案是使用 Filebeats 从各个叶子节点上收集 log，当然 Fluentd 也有对应的 Fluent Bit.</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/go-printNumAndLetter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/go-printNumAndLetter/</guid>
      <description></description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/struct_compare/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/struct_compare/</guid>
      <description>go struct 能不能比较 需要具体情况具体分析，如果struct中含有不能被比较的字段类型，就不能被比较，如果struct中所有的字段类型都支持比较，那么就可以被比较。
不可被比较的类型: ① slice，因为slice是引用类型，除非是和nil比较 ② map，和slice同理，如果要比较两个map只能通过循环遍历实现 ③ 函数类型
其他的类型都可以比较。
还有两点值得注意：
结构体之间只能比较它们是否相等，而不能比较它们的大小。 只有所有属性都相等而属性顺序都一致的结构体才能进行比较。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/iam/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/iam/</guid>
      <description></description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/command/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/command/</guid>
      <description></description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/kafka/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/kafka/</guid>
      <description>https://www.itzhai.com/articles/deep-understanding-of-kafka.html
基本概念 Kafka基本概念：
Broker：Kafka以Broker集群的方式运行，一个Kafka节点就是一个Broker。理论上可以跨越多个数据中心。Broker负责数据复制，管理主题、分区、消费偏移量等。如果要跨越多个数据中心，数据中心之间的网络延迟需要非常低，因为Kafka Broker之间以及Broker和Zookeeper服务器之间有大量的通信。 在上图中，Kafka集群中包含3个Broker。 Topic：即主题，与RocketMQ的Topic类似，使用Topic对消息进行分类，Kafka接收到的每条消息都会放入到一个Topic中。 Topic代表发布和消费记录的端点。生产者向主题发布消息，消费者订阅主题进行消费消息； 每条记录有一个键，一个值，一个时间戳和一些元数据组成； 在未指定分区的情况下发布消息时，将使用键的散列选择分区。 Producer：消息生产者，负责向Broker发送消息； Consumer：消息消费者，从负责Broker读取并消费消息； ConsumerGroup：消费分组，对于同一个主题，可以被多个消费分组分别消费，每个消费分组有自己的消费偏移量，互不影响； Partition：分区，对Topic的数据进行分布式存储的最小单位。
存储架构 Kafka是以分区为维度进行存储的 每个Partition分区下面是由多个Segment(段)组成的，Segment是逻辑概念，实际上会对应到上面的三个文件 log：数据文件，存储实际的消息数据； index：索引文件，存储消息数据的索引； timeindex：索引文件，提供时间维度的检索。
Segment文件的命名规则：Partition的第一个Segment文件从0开始，后续每生成一个新的Segment文件的时候，文件名以当前Partition的最大offset为基准，文件名长度为64位long类型。 Segment生成相关配置：
log.segment.bytes: 每个segment的大小，达到这个大小后会创建一个新的segment，默认是1G； log.segment.ms: 配置每隔多少毫秒产生一个新的segment,默认是7天。
kafka 集群特性 每个Topic可以配置为多个分区，每个分区可以有多个副本，副本称为Replica，在副本集合中会存在一个Leader副本， Leader负责所有的读写请求，其余副本只负责从Leader同步备份数据。
Isr(In-Sync Replica)：是Replicas的一个子集，列出当前还存活着，并且已经同步备份了该分区的节点。
Isr中包括Leader副本，以及与Leader副本保持同步的Follower副本。
Rebalance机制 Rebalance机制是Kafka消费机制的核心。
当消费组消费者数量发生变化、或者消费组消费主题数量变化、主题分区数量变化等的时候，Kafka会重新分配消费者和分区的关系，也就是做一次Rebalance。
**Kafka保证一个Topic分区只会配给一个组内的消费者，**而一个消费者可以消费多个分区。
Rebalance策略主要有三种：Range、RoundRobin、StickyAssignor(粘性分配器)
Range:分区数除于消费者总数 RangeAssignor有何缺点？ 消费组中的消费者数量多于主题的分区数量,并没有尽可能地使用到所有的消费者
轮循： RoundRobin有何缺点？ 虽然RoundRobin尽可能的利用所有的消费者，但是一旦消费者数量发生变化触发Rebalance时，会导致更多的分区重分配。
StickyAssignor：分区尽可能保证分布均匀，分区分配尽可能保持不变更
Kafka是如何保证数据的可靠性？ 生产者：acks=all，并且使用同步阻塞的方式发送消息； Topic：replication.factor &amp;gt;= 3，min.insync.replicas &amp;gt;= 2; Broker：unclean.leader.election.enable=false，确保ISR集合中没有可用的在线副本时，不会去选举ISR之外的副本作为新的Leader。
消费端:为了避免丢失未处理完的消息，需要设置为手动提交
Kafka为啥性能这么高？ 大家知道RocketMQ是基于Kafka改造而来的，因此Kafka的高性能原因与RocketMQ类似，以下是Kafka高性能的原因：
磁盘顺序读写：Kafka写消息都是直接追加到文件末尾的，不会有随机写的情况，另外，不会随机删除日志，只会按照删除策略删除一整段的历史消息。 与RocketMQ不同的是，kafka不会像RocketMQ那样预分配一个很大的文件来存储消息，Kafka的顺序写可以理解为分段顺序写的，一般一台服务器只部署Kafka就更接近与完全顺序； 批量读写数据，以及压缩传输： Rocket发送消息底层是分批发送的，提高了传输和存储的效率； 数据零拷贝技术：通过mmap内存映射，以及sendfile，减少了数据拷贝次数，提高了数据发送效率。
消息顺序性如何保证 发送端设置同步发送，避免异步发送导致乱序； 消费端消息统一发到同一个分区，通过一个消费者去消费消息。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/rabbitmq/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/rabbitmq/</guid>
      <description>https://juejin.cn/post/6844903805453074446
一些概念 ConnectionFactory（连接管理器）：应用程序与Rabbit之间建立连接的管理器，程序代码中使用。
Channel（信道）：消息推送使用的通道，在客户端的每个连接里，可建立多个channel。
Exchange（交换器）：消息交换机，指定消息按什么规则，路由到哪个队列。
Queue（队列）：消息的载体，每个消息都会被投到一个或多个队列。
RoutingKey（路由键）：exchange根据这个关键字进行消息投递。
Binding（绑定键）：把exchange和queue按照路由规则绑定起来
Consumer:消息消费者，接受消息的程序
Producer:消息生产者，投递消息的程序
exchange direct exchange:直接匹配，通过exchange名称 + routingKey来发送与接收消息 fanout exchange:广播订阅，向所有的消费者发布消息，但是只有消费者将队列绑定到该路由器才能收到消息 topic exchange：主题匹配订阅，这里的主题指的是routingKey,routingKey可以采用通配符 默认的exchange:如果使用空字符串去声明一个exchange，系统就会使用amq.direct这个exchange，我们创建一个queue时，默认的都会有一个和新建queue同名的routingKey绑定到这个默认的exchange上去
rabbitmq 中 vhost 的作用是什么？ vhost 可以理解为虚拟 broker ，即 mini-RabbitMQ server。 其内部均含有独立的 queue、exchange 和 binding 等，但最最重要的是，其拥有独立的权限系统，可以做到 vhost 范围的用户控制。 当然，从 RabbitMQ 的全局角度，vhost 可以作为不同权限隔离的手段（一个典型的例子就是不同的应用可以跑在不同的 vhost 中）。
rabbitmq 怎么实现延迟消息队列？ 通过消息过期后进入死信交换器，再由交换器转发到延迟消费队列，实现延迟功能； 使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。
使用插件rabbitmq_delayed_message_exchange 该插件需要手动下载并安装到RabbitMQ中，安装方法可以参考官方文档。安装完成后，需要在RabbitMQ管理界面中创建一个新的Exchange，并将Exchange的类型设置为“x-delayed-message”。然后在发送消息时，需要将消息的header中添加一个“x-delay”属性，该属性的值表示消息需要延迟的时间（单位为毫秒）。例如，如果要将消息延迟10秒发送，则需要将“x-delay”属性设置为10000。这样，消息就会被发送到延迟队列中，并在指定的延迟时间后再被重新路由到目标队列中。
使用TTL和死信队列 在RabbitMQ中，可以为队列设置TTL（Time To Live）属性，来控制消息在队列中的存活时间。当消息的TTL过期时，消息会被自动从队列中删除，并发送到一个死信队列中。因此，可以通过设置队列的TTL属性和死信队列来实现延迟消息的功能。具体来说，需要创建一个专门用于接收延迟消息的队列，并设置该队列的TTL属性。然后，当需要发送延迟消息时，将消息发送到该队列中。当消息的TTL过期时，消息就会被路由到死信队列中，然后从死信队列中重新路由到目标队列中。 需要注意的是，在使用TTL和死信队列的方式时，需要确保队列中的消息TTL比死信队列中的TTL大，以确保消息能够被正确地路由到目标队列中。同时，由于死信队列可能会被多个队列共享，因此需要在消息的header中添加一个“x-death”属性，以便识别该消息的原始队列和原始路由键。
消息确认 消息确认 消费者应用（Consumer applications） - 用来接受和处理消息的应用 - 在处理消息的时候偶尔会失败或者有时会直接崩溃掉。而且网络原因也有可能引起各种问题。这就给我们出了个难题，AMQP代理在什么时候删除消息才是正确的？AMQP 0-9-1 规范给我们两种建议：
当消息代理（broker）将消息发送给应用后立即删除。（使用AMQP方法：basic.deliver或basic.get-ok） 待应用（application）发送一个确认回执（acknowledgement）后再删除消息。（使用AMQP方法：basic.ack） 前者被称作自动确认模式（automatic acknowledgement model），后者被称作显式确认模式（explicit acknowledgement model）。在显式模式下，由消费者应用来选择什么时候发送确认回执（acknowledgement）。应用可以在收到消息后立即发送，或将未处理的消息存储后发送，或等到消息被处理完毕后再发送确认回执（例如，成功获取一个网页内容并将其存储之后）。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/tcp/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/tcp/</guid>
      <description>time_wait过多的危害 第一是内存资源占用，这个目前看来不是太严重，基本可以忽略。 第二是对端口资源的占用，一个 TCP 连接至少消耗一个本地端口。要知道，端口资源也是 有限的，一般可以开启的端口为 32768～61000 ，也可以通过net.ipv4.ip_local_po rt_range指定，如果 TIME_WAIT 状态过多，会导致无法创建新连接。这个也是我们在一 开始讲到的那个例子
怎么避免time_wait过多 net.ipv4.tcp_max_tw_buckets 一个暴力的方法是通过 sysctl 命令，将系统值调小。这个值默认为 18000，当系统中处于 TIME_WAIT 的连接一旦超过这个值时，系统就会将所有的 TIME_WAIT 连接状态重置，并 且只打印出警告信息。这个方法过于暴力，而且治标不治本，带来的问题远比解决的问题 多，不推荐使用 调低 TCP_TIMEWAIT_LEN，重新编译系统 这个方法是一个不错的方法，缺点是需要“一点”内核方面的知识，能够重新编译内核。我 想这个不是大多数人能接受的方式。 SO_LINGER 的设置
1 2 int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 1 2 3 4 struct linger { int l_onoff; /* 0=off, nonzero=on */ int l_linger; /* linger time, POSIX specifies units as seconds */ } 如果l_onoff为非 0， 且l_linger值也为 0，那么调用 close 后，会立该发送一个 RST 标志给对端，该 TCP 连接将跳过四次挥手，也就跳过了 TIME_WAIT 状态，直接关 闭。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/resume/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/resume/</guid>
      <description>自我介绍： 你好，我叫蒋贻华，毕业于浙江师范大学计算机专业。此前有7年的php开发经验， 后来由于公司技术栈的变更，转到golang方向，目前有3年的Golang开发经验。 下面介绍一下我在过往的工作经历里充当的角色与主要的职责。
在广州趣丸科技有限公司，我主要负责匿名社交产品uki的新功能的方案设计及开发与老功能的迭代优化。 在功能模块的迭代上，负责了会员等级模块，匹配模块，其他老服务代码的迁移。 在性能优化上，从业务上寻找存在瓶颈或者影响系统稳定性的问题，并进行改造，比如包括缓存的优化、 Redis/MySQL慢查询的优化和对敏感操作的分布式事务重写，在中间件上添加限流熔断。
在商米科技有限公司，这是一家智能硬件设备的公司，正在探索软件生态上的一些机会， 我主导从0到1开发一套远程设备管理系统。这套系统是一个基于mqtt协议的长链接， 通过网页端下发指令控制设备的一些操作，包括对设备的关机、重启、传输文件、上传日志等指令。 我负责技术选型、压测上线，以及预算成本控制等工作， 最终我们的集群是由7台4核8G的机器组成，目前能够维持百万以上设备同时在线。 此外，针对此套长链接还为整个公司提供了推送基础服务， 在19年度成为该公司的年度最佳员工之一。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/cache/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/cache/</guid>
      <description>缓存改造 增加singlefight，防止缓存穿透，但也不能直接用，如果并发量大，而请求的数据太慢，可能会导致整个系统的请求都超时 singleFight 直接用可能存在的问题 出现上述问题的根本原因是以下两点： 阻塞读：缺少超时控制，难以快速失败； 单并发：虽然达到了控制并发的效果，但是牺牲了成功率；
超时控制 ，用DoChan替代Do，DoChan() 通过 channel 返回结果。因此可以使用 select 语句实现超时控制
降低请求数量： 在一些对可用性要求极高的场景下，往往需要一定的请求饱和度来保证业务的最终成功率。 一次请求还是多次请求，对于下游服务而言并没有太大区别，此时使用 singleflight 只是为了降低请求的数量级，那么使用 Forget() 提高下游请求的并发
多级缓存 在redis之前再加一层内存缓存。之前也是直接用了公司那边自己写的缓存框架，就是没有多map分片，如果整个内存的缓存数据的key多的话， 我们都知道，map是不能并发读写的。 根据调研，也是选择了性能相对高的缓存框架，因为之前选择了groupCache这种的，但实际上有很多小对象的缓存，导致gc频繁， 后面也是选择了freecache，来保证性能的平衡
支持http协议
支持 10K RPS (5k 写，5k 读)
cache对象至少保持10分钟
相应时间平均 5ms, p99.9 10毫秒， p99.999 400毫秒
其它HTTP的一些需求
为了满足这些需求,要求开发的cache库要保证：
即使有百万的缓存对象也要非常快
支持大并发访问
一定时间后支持剔除
https://colobu.com/2019/11/18/how-is-the-bigcache-is-fast/</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/feed/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/feed/</guid>
      <description>feed流的优化 关注feed流 - 读扩散 原理 读扩散需要先读取关注列表中的用户，然后分别按时间线去读取关注列表用户的动态列表，
关注feed流 - 写扩散 读写比例是100:1，也就是说大部分情况都是刷Feed流看别人发的朋友圈和微博，只有很少情况是自己亲自发一条朋友圈或微博给别人看。 因此，读扩散那种很重的读逻辑并不适合大多数场景。 每次发表帖子，都会扩散为M次写操作（M等于自己的粉丝数） 读写混合模式 |方案	|优点	|缺点	|适用场景| |读扩散	|节约存储空间，发帖操作简单	|读帖操作复杂，关注人数多时是灾难	用户不活跃，很少读帖；有大V粉丝量多，但每个粉丝关注的人少| |写扩散	|读帖操作简单	发帖操作复杂，浪费存储空间；大V粉丝量多时是灾难	用户非常活跃，经常刷帖；无大V，用户粉丝量都比较少|
粉丝量大的主播发送动态，写扩展给其活跃用户，粉丝量小的，直接写扩展给其所有的粉丝。 活跃的用户上线，直接读其feed流 非活跃的用户突然登录刷Feed流时，我们一方面需要读他的feed流，另一方面需要遍历他所关注的大主播的动态列表，做一下聚合展示。在展示完后，系统还需要有个任务来判断是否有必要将该用户升级为活跃用户。 因为有读扩散的场景存在，因此即使是混合模式，
读写混合模式下，系统需要做两个判断。一个是哪些用户属于大V，我们可以将粉丝量作为一个判断指标。另一个是哪些用户属于活跃粉丝，这个判断标准可以是最近一次登录时间等。这两处判断标准就需要在系统发展过程中动态地识别和调整，没有固定公式了。
https://www.6aiq.com/article/1628640265887 https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&amp;amp;mid=2247486929&amp;amp;idx=4&amp;amp;sn=e0937dc99cfe853e416a930633dd7db3&amp;amp;chksm=fbb2842fccc50d393183ea602d6c2a7954530dd8a0a33583f007b7cefb458566a4ff4587889a&amp;amp;scene=27</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/introduce/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/introduce/</guid>
      <description></description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/mysql/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/mysql/</guid>
      <description></description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/redis/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/redis/</guid>
      <description>1. 对用户大key的拆分 将最常用的几个值拆分出来，之前是全部的一条用户信息直接压缩存到redis中，但是有一个很严重的问题，就是随着业务越来越复杂，读取的 会越来越频繁，那么对整个大key的读取将会变慢，有一次就是要显示一个千人千面的用户推荐列表，然后就频繁的读取这种用户信息，直接网络的 读写io占满，后面是把这种key拆分成小key处理
2. Redis其实只适合作为缓存，而不是数据库或是存储。 之前太多的业务使用redis存储，但好多不设置过期时间，导致最后redis的内存迟迟不放，所以得所有的key最好都设置过期时间。 哪怕设置成一年这么长，也比没设置好，长时间的不释放，会导致生成rdb这些，内存占用这些都有影响
3. 客户端连接池占满 开启查询自旋模式，容易占用连接池</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/welcome/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/welcome/</guid>
      <description>你好，我叫蒋贻华，目前在寻找新的工作机会，目前想找的方向是golang后端开发。 对贵司的golang开发岗位感兴趣，我认为我过往的工作经验与贵公司有一定的匹配度，希望有机会更深入的了解下。
主要主要从事的行业领域主要社交app与智能硬件方向
跟您详细聊完后，对岗位还是挺有意向的，可以安排一场面试吗？</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/autodyne/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/autodyne/</guid>
      <description>尼康d750可以有三种方式来自拍，一是使用间隔拍摄，可以设置拍摄时间与间隔，然后再拍摄。
第二种就是相机的第二个轮盘(调整ASPM的轮盘下方)设置到有个指针的那个，会自动延时10秒拍摄。
第三种就是连接手机app，进行遥控。个人更喜欢第一种吧，时间可以调。</description>
    </item>
    <item>
      <title></title>
      <link>http://www.huasay.com/1/01/01/focus/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://www.huasay.com/1/01/01/focus/</guid>
      <description>针对对焦方式，一般拍静物时，使用单点对焦，就是AFS。如果拍运动中的，使用AFC 3d模式。
拍人像，优先对焦眼部，没眼部对焦脸部
调节对焦方式。相机里AF/MF中里面有个按钮可以快速调整</description>
    </item>
  </channel>
</rss>
