在 Golang 中依赖注入是 解药 还是 毒药?
前言看到标题,有人可能会疑惑,其实原因是当我在网络上搜索有关 golang 依赖注入、 wire 这些关键词的时候,有一些评论是下面这样的:
有人认为 依赖注入 不应该出现在 golang 中,是毒药
而也有人认为 依赖注入 是非常好的设计思路,是依赖管理的解药
在经过不少项目的磨砺,笔者也终于对依赖注入有了新的认识,但这几个月一直在折腾和纠结,到底要不要写本文。网络上早就已经有了各种讨论有关于 Golang 是否需要 依赖注入 的呼声。今天,我还是觉得将它换一个角度,作为一个个人的小总结和感悟将它记录下来。
故,本文建议推荐给下述人群:
还在纠结 golang 要不要使用依赖注入的人
对 依赖注入 理解还有所疑惑的人
为了简述,下文有以下简称依赖注入 简称为:DI面向对象 简称为:OOP
个人观点我不喜欢浪费时间,也避免标题党嫌疑,所以为了节约时间,对于已经知道 DI 概念的朋友,直接先给出我自己的观点:
如果你现在做的项目不大,或是个人项目,并且还在尝试阶段。完全的面向过程编程,在 go 中是可行的。
但如果你的项目比较大,又是多人协作,我真心 ...
使用 Rust 快速体验 eBPF
前言可能你听过 eBPF 这个听上去非常高大上的技术,但实际并没有使用过。今天让我们来用 rust 快速体验一下 eBPF 的能力。
之所以使用 Rust 是因为 aya 框架确实很容易上手,当然如果使用 golang 也有 https://github.com/cilium/ebpf 的帮助也非常容易的。
因为只是体验,你可以几乎没有语言本身的使用经验,就能直接运行并感受到 eBPF 的能力。当然整体几乎也不需要写代码。
环境准备
开发环境,如果直接在 Linux 环境上开发自然最好,博主使用的是 M 系列的 MacOS 环境,然后交叉编译到 Linux 上运行
运行环境,当然你需要一个 Linux 环境能运行,并且内核版本要足够,前提就是需要支持 eBPF 和 XDP 才可以
前置知识点由于只是体验,我也不过多深入其中的原理和内容,就简单快速让你了解什么是 eBPF 和 XDP。详细原理可参考各种文档。
eBPF
在不更改内核源代码的情况下,向操作系统添加额外的功能
简单的来说就是通过一些钩子在运行一些调用方法的前后添加一些处理逻辑,以便实现一些功能。有点像 Java 的 AO ...
《一起读 kubernetes 源码》Service 创建之后发生了什么?
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言在了解了基础的 pod 再到常用的 deployment,我们对于应用常用的 k8s 中对象应该已经了一个比较清晰的认识。对内没有问题之后,让我们来看看对外。要想让你部署的服务能被外部访问到,那么离不开的就是 service,也是我们最常见到的第一个有关与外部访问的对象了。所以在这一章的第一节我们先来看看 Service 是如何实现的。
在看源码之前问自己一个问题,为什么需要 service 呢?其实能想到的重要原因有两个:一个是默认情况下,容器没办法直接被外部访问到,就像我们使用 docker 一样,如果不绑定宿主机的端口是没办法为外部服务的;另一个就是负载均衡,因为我们的 pod 常常是有多个的,并且关键的是 pod 还会可能分在不同的机器上,如果没有一个合理的策略去将外部的流量转到对应的服务上就如同没有了导航方向标。
前置知识
Service 的基本使用
Service 的类型
心路历程这里看源码很容易被陷入进去,由于 Service 功能并没有那么的直接涉及的细节和点(技术方案)很多,如果直接搜索,然后 ...
The little dict 一个非常好用的欧陆词典扩展
前言最近发现一个很不错的欧陆词典扩展,叫做 The little dict,给出的解释的同时还有一些使用频率以及各种解释,非常适合英语学习者使用。忍不住分享一下。
下载地址
网上找的,你也可以自己找找看
https://pan.baidu.com/s/1OblabSK7M7jxGd_bSQaZzg#list/path=%2F
提取码:s5z8
安装其实安装非常简单,下载之后解压,然后在管理-已安装词库的界面,将文件夹拖到里面即可。注意原始文件夹不要删掉。
预览
新手上路 Rust 的字符串
前言相比与 Golang 或者是其他语言的字符串的设计 Rust 对于字符串的设计就要复杂不少,新手第一坑可能就容易掉进去,并且觉得很难用。不过其实掌握其中的几个基本概念,就会发现也就这么回事。今天我们来唠唠让人头疼的字符串。
两个问题一般来说,很少有人第一个语言上手就是 rust ,当带着其他语言的影子来使用 rust 的时候势必会遇到下面两个问题。
问题 1: 直接写的不是字符串如下面的代码,就会报错
12345678fn main() { let s = "我是一个字符串"; check(s);}fn check(s: String) { println!("不,{},你不是个字符串!", s);}
新手遇到的第一个问题就是直接写字符串 “xxx” ,发现不好用。
那么第一个误区就来了,”xxx” 这样的表示通常用字面量来称呼,而在 rust 里面,直接这样写,s 就是一个 &str 类型,可以理解为
1let s: &str = "x ...
《一起读 kubernetes 源码》简单的 DaemonSet
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言相比较于 deployment 和 StatefulSet,DaemonSet 是更简单的一个,也是最不常用的一个对象了。对于应用开发的同学来说可能几乎见不到它,而对于运维或者 SRE 的同学可能会熟悉一些。DaemonSet 用于确保集群中的每个节点运行有且仅有一个 pod 实例的场景。两个最常见的场景是:日志收集和监控。日志收集是为了收集每个节点上的日志,而监控则是为了监控每个节点的一些数据指标。通常来说以全局平台或者节点为场景的情况下才会想到它。那么 DaemonSet 的如何保证每个节点 pod 的数量呢?这一节让我从源码的角度看看它是如何实现的。
前置知识
DaemonSet 的基本使用
码前讨论首先代码位置就不多说了,有前面的经验。
1kubernetes/pkg/controller/daemon
由于前面我们已经看过了 deployment、rs、StatefulSet,那么其实对于 DaemonSet,我们也是一样几乎大致的形态结构都已经可以八九不离十了,而且它只有 daemon_contr ...
OrbStack 配置国内镜像加速
前言使用 docker 我们知道可以通过配置 /etc/docker/daemon.json 的 registry-mirrors 来实现,但是由于 docker 桌面版本在 macOS 上实在不好玩,还是 orbstack 好用,占用资源更少。那么使用 OrbStack 如何配置国内镜像加速器呢?其实很简单。
配置创建并编辑 ~/.orbstack/config/docker.json
1234567{ "registry-mirrors": [ "https://dockerproxy.com", "https://docker.mirrors.ustc.edu.cn", "https://docker.nju.edu.cn" ]}
目前可用的镜像:https://gist.github.com/y0ngb1n/7e8f16af3242c7815e7ca2f0833d3ea6
验证重启 orbstack,之后命令行执行 dock ...
《一起读 kubernetes 源码》statefulset 的更新有何不同
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言在前面我们已经看过了 deployment 和 replicaset 的实现,其实对于 k8s 中的对象已经有了一个基本的认识,其他的对象也都是在这个的基础之上有了不同的能力。而这一节我们来看看另一个常用的对象 statefulset。相对与 deployment 来说 statefulset 用的会更少,因为大部分应用都是无状态的,而有状态的数据类型的应用可能上 k8s 又少,要不就是接云厂商,要不就是独立部署。但是对于一些需要持久化配置或者数据的应用来说,配合 StorageClass 能让 StatefulSet 很好的帮助我们来部署这样类型的应用。
前置知识
statefulset 的基本使用
statefulset 的更新过程
statefulset 的 partition 的作用
心路历程我们知道滚动更新的时候 statefulset 是一个一个的这里的实现与 deployment 有什么不一样的地方呢?这部分是今天的主角我们需要弄明白。而另一部分是有关于 persistentVolumeClaim ...
MacOS 下如何安装 gnu 版本的 sed
前言在 MacOS 下使用 sed -i 就会出现类似下面的错误
12sed: 1: "...": command c expects \ followed by textsed: 1: "...": command i expects \ followed by text
原因是由于 MacOS 下默认的 sed 和 Linux 下是不一样的,导致 -i 无法正确识别,通常的做法是安装一个 gnu-sed 已替换原本的 sed 命令
安装步骤123456789101112131415161718192021222324252627# 查询一下which sed# 安装brew install gnu-sed# 查看brew info gnu-sed==> gnu-sed: stable 4.9 (bottled)GNU implementation of the famous stream editorhttps://www.gnu.org/software/sed/Conflicts with: ssed (because both ...
浅析 Rust 所有权设计
前言市面上的 Rust 书已经把基础说的足够好了,我没必要再搬砖,而是尝试从一些个人的角度来重新审视其中的一些设计。Rust 我认为最为关键的设计:所有权和借用。我们都知道 Rust 和 Go、Java 相比最大的不同就是没有 GC,那么没有 GC 的设计需要付出一定的代价,这个代价一部分就体现在今天要说的这两个设计中。
代价 1: 所有权三规
每一个值都被一个变量所拥有 Each value in Rust has a variable that’s called its owner
一个值同时只能被一个变量所拥有 There can only be one owner at a time
当所有者离开作用域时,这个值将被丢弃 When the owner goes out of scope, the value will be dropped
很多基础都会提到这三个规定,非常重要。理解它就能理解所有权。而反过来,当我看完之后,反过来,其实可以从中推导它的设计。
问答推导
我还是习惯称呼为对象,所以我下面以对象称呼。
提问:GC 的目标是什么?回答:垃圾对象,无用的对象
提问 ...
《一起读 kubernetes 源码》replicaset 到底有何不同
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言前一节我们看到了 deployment 的滚动更新实现,如果你对它已经有一个比较清晰的认识,那么这一节的 replicaset 就非常容易理解了,因为基本实现都是差不多的。为了方便描述后面文中提及的 replicaset 统一简写为 RS。
在一开始学习 k8s 的时候其实我们不一定能碰到这个对象,如果只是日常的使用通常来说的都是 deployment 或者是 statefulset 这样。渐渐深入才会发现它。好像默默无闻的它是做什么的呢?
前置知识
RS 是什么?
心路历程在不知道 RS 之前我一直都以为是 deployment 直接去控制的 pod。而在一开始了解之后,我会好奇为什么要设计一个 RS,直接控制不行吗?渐渐的深入,就会发现,其实它有着自己的设计在里面。
码前提问
RS 和 Deployment 关系是什么?
有何特别的设计?
源码分析寻码过程有了 deployment 的经验其实 RS 寻码的过程就非常简单了。关键都是在 控制器 上。于是在相同的包下面我们就容易找到它。
12kubernet ...
Go 应用容器下优雅停止坑点
前言之前我有写过 go 应用在 k8s 中如何优雅停止 的博客,理论上在配置好对应的参数之后就能 优雅停止 了,但是最近接触到了两个场景,会导致配置的优雅停止失效,为了避免踩坑,对于之前的博客进一步进行补充。
场景说明有了之前的经验,Golang 应用本身没有问题,它已经接受并处理 SIGTERM 和 SIGINT 信号,但是实际场景出现的情况,在 k8s 或者 docker 停止的时候 有一些缓慢 ,但是由于最终容器还是会被关闭,于是这个问题就没有关注,这个现象也很容易被忽略。
1234567891011121314151617181920212223package mainimport ( "fmt" "os" "os/signal" "syscall")func main() { fmt.Println("启动") ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT ...
程序员减肥记
最近很长一段时间没有写文章了,因为这一段时间在做个“大事”,减肥。运动本身还是挺花时间的,所以确实就没时间更新那种非常干货的博客了。
起因原因是体检发现 BMI 超标,到了接近 25,由于本人之前还没有到达过这样的体重,确实是有大肚子了。于是毅然开始了减肥之路。整个过程我发现,其实对于我这样小基数的情况来说,其实减肥并不难,科学减肥也没有那么多的痛苦。
结果先说结果,一共是 3 个月(4,5,6)时间,减掉了 10 kg,从 74kg 减到了 64kg。基本上是每个月减 3kg 左右。
从结果来看我自己是非常满意的,下面分享一下整个过程中的一些心得,希望对你有所帮助。之前大学的时候也有过减肥的经历,不过没有这次那么多。
我先说一些情况:
我是小基数,对于大基数的减肥来说估计是不适用的
我是程序员,时间其实对于我来说并不宽裕,如何有效利用时间是我最大的问题
我仅仅只是想让我的体重回到一个正常的水平上,不是追求肌肉或者身材
所以在这样的条件下,如何做到 理科(理性+科学) 减肥呢?
理科减肥这里说明一下我的理念和方法,再说说心得,方法不一定对任何人有效,但心得希望能帮助到你。
科 ...
Docker 容器如何访问宿主机服务
前言今天先水一篇,记录一个常见的问题,Docker 容器如何访问宿主机服务。我们知道在一个 docker 容器内部,如果,你直接访问 127.0.0.1 是无法访问到宿主机的,那么怎么办呢?
最直接的方法如果你是自己在用,就是这个机器上也没有其他服务,那我倒是建议直接使用 host 网络,简单直接,一把梭。
1docker run -it --network host ubuntu:latest
优雅的解决然后我反找到了一个非常非常长的 issue 中间有个评论是 https://github.com/docker/for-linux/issues/264#issuecomment-964620100 (github也是醉了中间隐藏的部分需要你点好几次才会全部展开)
如果你不想使用 host 网络,可以使用 host.docker.internal 来访问宿主机的服务。
docker 下可以使用
1docker run --add-host host.docker.internal:host-gateway
docker-compose 下可以使用
1234services: m ...
《一起读 kubernetes 源码》deployment 滚动更新是如何实现的
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言这一节终于来到了我们最为熟悉的一个对象 deployment,通常这可能是我们学习 k8s 接触的第一个大对象了,我们一般的应用也是以 deployment 来进行部署的,那么对于熟悉的它来说,我们应该从源码里面去找什么目标来看呢?对于我来说,deployment 的更新是我最好奇的,在我重新修改镜像版本之后,deployment 是如何一步步控制已有的 pod 进行更新的呢?这一节我们就从源码中揭秘这个过程。
前置知识
deployment 的基础使用
滚动更新
心路历程在我看来其他的属性与 pod 类似,而 deployment 作为一个 pod 的集合。那,为什么 deployment 要让 pod 的有多个副本呢?从最初的角度角度来说肯定是高可用了,所以 deployment 中最为关键的就是对 pod 的控制,也就是当 pod 的数量变化的时候,它是如何操作的。
码前提问
deployment 是由哪个对象控制的?
应用更新的时候 deployment 是如何控制更新过程的?
源码分析寻码过程像 d ...
《一起读 kubernetes 源码》揭秘 k8s 关键机制 informer
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言在第二章我们会去看 k8s 中常用对象的源码,不过在看这些对象之前,我们需要聊一聊 informer 机制。这个机制可以说是 k8s 设计之中的一个重点了。这个机制的设计不仅仅让代码本身变得清晰,更让整个系统的结构更容易扩展。所以这个机制需要放到第二章的第一节来说。
前置知识
控制循环
informer 的使用
心路历程我第一接触 informer 是在使用 client-go 的时候。相信有很多同学和我一样,学习 k8s 的路径通常是,从基本的使用开始,然后慢慢的有一些自定义的需求需要使用 client-go 进行开发。使用 client-go 开发真的很方便,能力很强大。而在其中我第一次碰到了 informer。从了解了这个机制之后,才逐渐明白 k8s 本身是如何去控制里面的资源的。
还是一样的,本文不涉及具体这个机制的详细原理,更专注在源码本身。当然,我先通过两个小点帮助你回忆起来 informer 机制。
控制循环首先是控制循环,这个我认为是 k8s 的精髓,它通过一个循环来让整个系统趋向与我们申明的一 ...
《一起读 kubernetes 源码》pause 你在哪里?
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言你有没有在 k8s 的 node 上敲过 docker ps 这个命令,我就干过。而出现的结果大概会是这样的:
1234root@10.0.10.102:~# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES5aa88e8d16ac xxxx "/entrypoint.sh" 3 days ago Up 3 days k8s_xxx-04e40566baa09 google_containers/pause:3.4.1 "/pause" 3 days ago Up 3 days k8s_POD_xxxx
你有没有好 ...
假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如何将它们全部找出来?
这个问题本身不难,但网上的教程答案让我很不理解,所以单独拿来吐槽一下
来源与网络的答案
我特意用了截图而不是贴链接。其中“如何”还打成了如果…
有什么问题?如果我是面试官,问了这个问题,如果你第一回答是 keys,那么恭喜你可以回去等通知了(言重了,说白了就不往下问了)
1 亿个,你知道什么概念吗?如果直接 keys 一下线上的数据不知道要阻塞多久,你下面的回答明明就知道答案偏偏把人家往沟里带…
但如果就只是如此,我也不用写这篇博客了,我想说的是 SCAN 也不是最优解
SCAN 有什么问题不卡,但是慢,下面是来源与网络的一个测试结果,Redis 性能问题诊断以及 scan 命令耗时分析
12345678910111213141516171819202122232425262728293031测试命令:./redis-benchmark -a xxxx -r 10000 -n 100 -c 8000 scan 0 match zhaobsh* count 1000010000个随机key, 测试100次, 使用 80000个client进行测试验证.被测试的命令为: scan ...
不定期刊
点我跳转查看 Notion Paper写在前面之前在博客装修的时候就提到过,对于之前的设计专栏确实不太适合我,写了一段时间之后发现太难了,所以就一直没有更新。但是我还是想要有一个专门的地方来记录一些自己的想法,所以就有了这个 Notion Paper。
这里会记录我日常看到的一些设计、产品、技术等等的一些想法。因为本身还是一个程序员,所以大多还是会有一些技术相关的内容,各种技术的使用用法也会在里面。
我特别喜欢报纸的展示形式,因为报纸有时候可以最大限度的展示信息,于是我就参考了报纸的形式和版式来设计这个 Notion Paper 的样子。希望你也会喜欢它。
尝试 Google Gemma 模型 MacOS 本地部署
前言最近 Google 发布了 Gemma,是 Gemini 的低配版本,既然是 Google 出品那我一定要来吃螃蟹的。所以我本地部署了一个 7b 的版本来尝试使用一下看看效果。同时也来说明一些有关大模型本地部署使用的一些个人体会,比如,你可能会有以下问题:
怎么本地部署使用?
我本地的电脑能不能跑?
本地跑的效果到底怎么样?
首先,我想敲醒你沉睡的脑子。对于本地部署模型,你先要问清楚自己想要的是什么?也就是为什么需要本地部署,如果仅仅是想跑着玩,那没问题。如果只是平常使用,并且你已经能用 GPT 了,本地其实对于你来说毫无意义,因为你指望你的小电脑哪怕是大显卡能和别人成吨的 A100 相比吗?(夸张的修辞) 如果,醒了还是想玩,那么可以往下看了,最后我会总结本地去跑有哪些优势。
如何部署这里我推荐两个:
https://ollama.com/
https://jan.ai/
这二者基本都已经做到了开箱即用的地步了,其中我会更喜欢 ollama 一点。所以我就简单列一下它的步骤(其实官网已经描述的非常详细了,也很简单 https://github.com/ollama/oll ...
什么是索引下推?
前言今天来水一篇 MySQL 的问题。什么是索引下推?其实很多概念都是被中文名字唬住了,这个概念并不复杂。如果看得懂英文,建议直接跳转 Index Condition Pushdown Optimization
回表这是一个前置知识点。当我们通过索引找到某条数据时,其实只是找到了它对应的 id,需要根据 id 回到原来的表里面把数据捞出来,这个过程就是回表。
索引下推直接用官方的例子说明:有一个索引 INDEX (zipcode, lastname, firstname) 有一个查询如下:
1234SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%etrunia%' AND address LIKE '%Main Street%';
本来是不能命中全部索引的,因为后面两个条件是左 % LIKE,当然最左匹配原则可以先利用 zipcode 定位到数据。下面就是关键了:
如果,没有索引下推,那么当找到这条数据时,需要回表找到原数据来判断是否满足条件 ...
《一起读 kubernetes 源码》原来 k8s 也有 GC
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言作为 k8s 的使用者而非维护者来说,对于 k8s 的 GC 其实是很难接触到的(几乎是无感的)。这也就是为什么标题写的惊讶 “原来 k8s 也有 GC”。GC 这个概念在很多语言中都有的,比如 Java 和 Golang,它就是帮助我们来回收垃圾的。在编程语言中,GC 主要是回收那些垃圾对象;那么相对于的 k8s 中,GC 需要回收哪些资源呢?今天的内容不复杂,源码里面都是那种很符合直觉的实现。
心路历程其实,我一开始最好奇的就是镜像,由于 docker 镜像的大小我们是可想而知的。就算是我们常常使用的本地电脑,磁盘都有可能被占用很多,更别提是服务器这种动不动就更新镜像的情况了。
码前提问
K8S 的 GC 回收哪些资源?
K8S 的 GC 什么时候运行?
K8S 的 GC 是谁运行的?
源码分析今天的入口还是比较好找的,因为很明确的命名 GarbageCollection 找到它,肯定就是了。首先,我们依旧先来看接口
1234567// pkg/kubelet/kubelet.go:231// Bootst ...
博客装修(2024年3月)
却忆携诗花底看,回头又是一年春。不知不觉又一年过去了,每年 3 月都是博客装修的季节,但这次就不大折腾了。
butterfly 主题升级
更新主题版本至 4.13.0 https://github.com/jerryc127/hexo-theme-butterfly
其中我一个比较喜欢的优化是对于搜索的能力,现在感受比原来好用了很多。不过每次升级都是对于合并代码的一次巨大考验,这次我学乖了,直接把更新的配置文件内容全部拷贝进去改,这样就不会出现冲突了。这也让我对于配置一些软件配置文件的设计有了更好的认识,它们会加自定义的配置单独放在一个文件里,这样就不会影响到主配置文件的合并了,然后自定义的配置会覆盖默认的配置。xxxx.custom.yaml -> xxxx.yaml
评论系统去年评论组件换成了自建的 twikoo 很喜欢,配置简单。
修改评论回复邮件之前我看到了 Twikoo评论回复邮件模板 我一直没来的及修改,这次我终于修改了,总的样子没变,细节调整了一点点。 修改之后大概是这样的:
需要注意的是:MAIL_TEMPLATE 和 MAIL_TEMPLATE_ADMI ...
Vditor 如何离线使用?
前言Vditor 是一款所见即所得的浏览器端 Markdown 编辑器。
GitHub:https://github.com/Vanessa219/vditor
官网:https://b3log.org/vditor/
个人使用它有两个原因:
相比于同类型的,确实很好看,之前用过一段时间 Typora ,收费之后就没用了,效果上很类似(所见即所得)
Markdown 引擎是开源的 lute ,当我需要一个前后端相同渲染效果的引擎时,它就很不错了
基本使用就不多说了,文档很详细,功能也很全面,看看就知道了,本文是由于再离线环境下使用的过程中发现 Vditor 需要依赖外部 CDN 资源,所以踩了一些坑。
基本步骤网络上有 Vditor 的 CDN 但无法直接拿来用,除非你是原生 HTML。如果你直接配置网络的地址到 CDN 的配置会发现路径多了一个 dist。当然,官方也支持自建 CDN,将源码放到 nginx 里面去也可以,但这样单独部署很麻烦。我还是希望打包到一起去。其实作者在 issue 里面已经说了,挺容易理解的,过程也就基本是这样。
修改配置12345678910111 ...
密码还在用 MD5 加盐?不如试试 Bcrypt
很长一段时间我也是用 MD5 + 盐 来解决绝大多数密码的问题的,因为确实很方便。不过,从安全的角度来说,还是有风险,那就干脆直接上 Bcrypt 吧。
MD5 + salt其实,在大多场景够用了,毕竟 hash 和 salt 同时被黑的概率太低了,不过其实 MD5 最大的问题不是到不是这个,而是算的太快了,随着计算能力的发展总会是有概率被破解的。
1password_hash = md5(password+salt)
Bcrypt 的特点
hash 不可逆
随机 salt
可调整的计算 cost
上代码不多说,直接上代码,看怎么用,然后再分析。
123456789101112131415161718192021222324252627282930package mainimport ( "fmt" "golang.org/x/crypto/bcrypt")func main() { password := "123456" fmt.Printf("第一次加密后的密码: %s\n", en ...
折腾你的输入法
想不到有一天我居然会折腾我的输入法… 作为一个折腾的孩子,折腾各种硬件软件是常有的事情,但最近发现了一个输入法,然后掉进了另一个圈子。这个输入法就是:中州韵输入法引擎 RIME,在 mac 上名字叫鼠须管。今天简单记录在 MacOS 下安装和使用的配置过程。
优点
隐私:这个引擎开源的,不可能出现上传你输入的内容到云上的情况
快速:不联网一定比你联网输入要快,但也不联想(所以这个快速因人而异)
高度自定义:想怎么定义都行,可以用自己的词库
缺点
安装和配置有大门槛,当然难不倒我们搬砖的
安装 RIME我直接用 brew 安装就完事了,当然你也可以官网下载
1brew install --cask squirrel
安装完成之后,第一个坑就出现了,输入法并不会直接显示出来,你需要主动添加。
我一开始找了半天,一直以为没有安装成功😢
安装 plumplum(東風破) 是 RIME 的配置管理工具
1curl -fsSL https://raw.githubusercontent.com/rime/plum/master/rime-install | bash
安装 雾凇拼音雾凇 ...
2023 读书总结
2023 年度读书总结
读书列表
仅罗列,顺序是随机。怕链接会过期,失效的建议直接搜书名。
《高并发系统实战派:集群、Redis缓存、海量存储、Elasticsearch、RocketMQ、微服务、持续集成等》
《性能之巅》
《呼啸山庄》
《Go语言设计模式》
《程序员的底层思维》
《浪潮之巅》
《System Design Interview》
《消失的13级台阶》
《深入理解Linux网络: 修炼底层内功,掌握高性能原理》
《图解HTTP》
《手机大脑》
《小米创业思考》
《BPF之巅》
《英语自学手册》
《聚沙成塔:Go语言构建高性能、分布式爬虫项目》
《深入架构原理与实践》
《现代 Web 布局》
《写给大家看的设计书》
《高并发的哲学原理》
《心流管理魔方》
2023 最佳
并不是说其他的书不好,而是它对我的影响最大,印象最深刻
《深入理解Linux网络: 修炼底层内功,掌握高性能原理》
今年最佳颁给它,一方面是它对我技术提高是最大的,另一方面是读的过程中真的有深入浅出的感觉。十分推荐。
打卡日历
使用 DailyCards 确实 push 了自己很多。Prese ...
2023 re:Invent 利用 PartyRock 10 分钟构建你的 AI 应用
前言一年一度的亚马逊云科技的 re:Invent 可谓是全球云计算、科技圈的狂欢,每次都能带来一些最前沿的方向标,这次也不例外。在看完一些 keynote 和介绍之后,我也去亲自体验了一些最近发布的内容。其中让我感受最深刻的无疑是 PartyRock 了。PartyRock 真的算是做到了:能让任何人快速的构建一个属于自己的 AI 应用。当然,本文最后也分享我对于其他在 re:Invent 上提到的一些看法和思考。
那么,不多说,先来看看今天的主角 PartyRock。
PartyRock 简介
Everyone can build AI apps.
这句话是 PartyRock 首页的一句话,它就是 PartyRock 的最好的功能概括了。
去年到今年 AI 相关的应用层出不穷,GEN AI 已经太多了。到目前为止,其实我本人已经有点审美疲劳了,因为该看的都看的差不多了,所以说实话体验之前,我并没有对 PartyRock 带有很大期望,最多是体验完了之后厚脸皮来一句 “不过如此”。结果体验完成之后发现我说的是:
使用体验下面我就用我自己制做的两个应用和一个官方的应用来说明一下它的 ...
看腾讯 CodeReview 有感
前言之前,我看了腾讯发布的两篇有关代码规范以及 Code Review 相关的文章,作者是 林强 大佬。
《鹅厂练习13年Coding后,我悟了》
《腾讯工作13年之所思所想,那些优秀程序员的共性特征》
里面提到了很多有关代码相关的思考,以及一些价值观的传递,从中我也学到了很多(算是大厂内部一瞥吧)。非常推荐没看过的同学看看鹅厂是如何做 CR 的。文中的 CR 也是对 go 的,所以我看起来比较亲切。故,在这里总结一下其中对我来说意义比较大的。
之前,我看了《重构》之后也写了一下读后感,所以相同的部分我就不在本文中列举了。
《鹅厂练习13年Coding后,我悟了》
01 细节即是架构:在这里更多的体现在代码的组织结构和也是一种架构。
02 代码和文档在一起:有两个好处,不容易丢失,可以同时被维护。
05 全局变量的危害并不仅仅是造成了耦合,在大项目中,你完全不知道以后是否会有人去修改这个变量。
07 可逆性原则:我的总结是,永远不要相信产品经理跟你说 ”这个以后不会改了,现在写死就好“,回头半夜加班的还是你。
11 尽早崩溃:并不是说你遇到问题就 panic,也并不是说你不能写 ...
针对小项目 docker 镜像自动更新部署的方案
对于一些个人的小项目来说,没必要也没能力上一些大型 devops 工具(如 jenkins,argocd) 时, 有一些小工具往往非常好用
当我们 ci 打包完成 docker 镜像之后需要 cd (部署)时,如果没有工具,有时候特别麻烦,而一些大型的重工具往往对于小项目来说并不合适。今天要说的一个小工具就是 watchtower。
地址: https://github.com/containrrr/watchtower/
介绍功能
定时对比当前机器上的启动着的容器,如果发现新版本的镜像则停止、拉取、重启以更新容器
支持 cron 指定对比时间
支持指定容器
支持更新后进行通知
适用场景
单机小项目
启停间隔无所谓
docker 镜像 latest 一把梭
使用使用部署非常简单,一个 docker-compose 就能说清楚所有基础能力
12345678910111213version: "3"services: watchtower: image: containrrr/watchtower environment: - TZ=A ...
《一起读 kubernetes 源码》pod 的资源限制和驱逐
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言资源在 k8s 中是一个非常重要的关键因素,一些运维事故往往也就是因为一些资源限制设置的不合理而导致的。而合理的设置资源也是一门学问和经验,最近不停地被提及的 “降本增效” 通常也伴随着资源设置的优化。对于一个应用应该设置多少内存和 CPU,我觉得这不是我们在这里应该学习的(这都是实战经验积累的)。而我们需要知道的是,这些限制条件何时会被检查,会被谁检查,超过限制条件会引发什么问题。 这对于我们来说很重要,一方面实际出现问题,我们可以迅速知道原因;另一方面,这些限制条件还会和之后的调度、自动扩容/缩容有关系。所以本章节我们来看看它。
前置知识
cgroup
resources 的配置:limits、requests
epoll
码前提问
pod 的资源限制条件何时会被检查?
pod 何时会被驱逐?
pod 驱逐的策略是什么?
源码分析寻码过程这次的寻码就有点艰难了。我的第一个落脚点是 pkg/kubelet/eviction/eviction_manager.go 我没有直接去找 limit 和 r ...
《一起读 kubernetes 源码》probe 监控 pod 状态
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言当我们知道了 pod 的生命周期,那么 k8s 如何知道一个 pod 的健康状态呢?就是通过今天要说的 Probe 也就是探针来检查 pod 的状态。一方面可以监控 pod 的健康状态,重启不健康的 pod;另一方面还可以监控 pod 的服务状态,当 pod 能提供服务时才会将流量打进来。
前置知识
livenessProbe
readinessProbe
startupProbe
要知道这三种探针的能力 https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/#types-of-probe
心路历程探针这个东西就和 request limit 一样,你不配置的话,绝大多数适合,使用起来也问题不大。甚至在一开始的时候我都没注意到这个配置,但是当你的服务非常注重 SLA(承诺服务可用性) 或者你的容器出现了异常,无法服务又没有正确退出的时候,这个配置就显得非常有用了。而在实际中,不合适的探针配置也可能会导致奇怪的问题。
所以,针 ...
《一起读 kubernetes 源码》kubelet 如何创建 pod?
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
前言pod 是 k8s 调度的最小单位,也就是整个 k8s 的基础之一,那么如何创建 pod 就是我们今天的关键了。这也是为什么我将它放在第一章的原因。
前置知识
什么是 pod?
什么是 kubelet?
pod 的生命周期?
心路历程想看 k8s 源码,我不知如何下手,肯定是挑最熟悉最基础的部分,pod 肯定就是其中之一。而且日常的使用也让我们更熟悉 pod 的生命周期,所以我准备从 pod 入手。那么我知道 kubelet 作为操作 pod 的关键,那肯定就是代码的重点。于是我直接在代码中搜 kubelet,找到对应文件名称为 kubelet 的文件,应该就是我们今天的目标了。
1pkg/kubelet/kubelet.go
然后开始聚焦,由于源码很多,不可能面面俱到,所以一开始我们就要设定范围,看什么,不看什么。而我们今天的目标就是 pod 的创建 其他都和我们没有关系。所以,kubelet 本身的初始化等其他细节我们看到就略过。
码前提问看源码之前都自己先提出一些问题,这些问题能帮助我们更快的进入状态, ...
《一起读 kubernetes 源码》序
📢 注意,该文本非最终版本,正在更新中,版权所有,请勿转载!!
这个系列准备带领大家一起读 kubernetes 源码,推荐给下面的人群:
不敢读源码
读不懂源码
不清楚 kubernetes 内部具体实现
其实,我最大目标是通过这个系列让你明白,读源码的方法和技巧以及为什么要读源码。
其实我写 kubernetes 源码分析的文章已经 3 个版本了,这是 3 个。第一次是刚学,写了 3-4 篇,没发布,就流产了。第 2 次是写了很多发现写的不好,切入点还是太诡异了,太难理解,所以也放弃了。现在,我终于发现一个可以切入的点,并且基于这么长一段时间的积累,希望能把这个系列最好的版本写出来。
需要准备
看代码的工具:我用的是 Goland。代码我都贴了位置信息(例如: pkg/kubelet/kubelet.go:2387),在 Goland 中可以直接双击 Shift,贴入代码位置直接跳转。
kubernetes release-1.28 版本的代码(希望你看到文章的时候这个版本相对新一点吧~)
你需要有 kubernetes 实际使用经验以及基本概念
注意事项
该系列不会包 ...
Nginx 是如何解决惊群效应的?
前置知识
linux 网络处理的基本方法:bind listen accept
epoll 的基本方法:epoll_create epoll_ctl epoll_wait
什么是惊群效应?第一次听到的这个名词的时候觉得很是有趣,不知道是个什么意思,总觉得又是奇怪的中文翻译导致的。
复杂的说(来源于网络)TLDR;
惊群效应(thundering herd)是指多进程(多线程)在同时阻塞等待同一个事件的时候(休眠状态),如果等待的这个事件发生,那么他就会唤醒等待的所有进程(或者线程),但是最终却只能有一个进程(线程)获得这个时间的“控制权”,对该事件进行处理,而其他进程(线程)获取“控制权”失败,只能重新进入休眠状态,这种现象和性能浪费就叫做惊群效应。
简单的讲(我的大白话)
有一道雷打下来,把很多人都吵醒了,但只有其中一个人去收衣服了。也就是:有一个请求过来了,把很多进程都唤醒了,但只有其中一个能最终处理。
原因&问题说起来其实也简单,多数时候为了提高应用的请求处理能力,会使用多进程(多线程)去监听请求,当请求来时,因为都有能力处理,所以就都被唤醒了。
而问题就是,最 ...
Docker 构建多架构镜像并推送仓库
前言原本多架构其实我还遇到的不算多,但自从苹果的 M1 出来之后 arm64 版本支持就变成了一个常态,所以会常遇到需要多架构镜像都构建的情况。以前的 docker 版本需要你去编写 manifest 很麻烦,而今天就说说如何使用 docker buildx 来同时构建多架构的镜像,其实现在已经非常方便了。
目标:构建出 amd64 和 arm64 的 docker 镜像
创建 builder默认你在 docker build 的时候直接指定 --platform linux/arm64,linux/amd64 就会报错,告诉你需要使用 docker buildx 而前提是你需要有一个 builder
12$ docker buildx create --name mybuilder --driver docker-container$ docker buildx use mybuilder
Linux 非 arm 下可能需要你先安装 https://github.com/tonistiigi/binfmt#installing-emulators 以支持 arm 平台的打包
...
Redis List 设计与实现
前言之前我们已经讨论过 Sorted Set 在 Redis 的实现,学习到了 Redis 在不同数据量的时候使用了不同的结构来优化存储和性能,并且使用两种不同的数据结构的组合来进一步优化。而今天要讨论的 List 也如出一辙。
ListList 就是我们常见的列表,在很多语言中都有实现,无论是数组还是链表,它最终的表现形式都差不多,都是一个“长长的数据”,而对于不同的底层实现,所对应的操作带来的性能也不同。比如在 java 中就有 LinkedList 和 ArrayList。而 Redis 是如何做的呢?
如果你对 Redis 的 List 使用并不是很熟悉,建议下查看一下它所有支持的命令 https://redis.io/commands/?group=list
老版本在 Redis 的老版本中 list 的实现和 Sorted Set 策略类似,对于不同数据量的情况下实现是不一样的。在数据量小的时候,使用的也是 ziplist 也就是压缩列表(可以看做数组),而当数据量变大触发条件时,就变成了 linkedlist 也就是双向链表。
ziplist 就是通过数据的长度来定 ...
Redis Sorted Set 实现与应用
前言
在没有真正认识 Redis 之前,你可能都低估了它
一开始对于 Redis 我们的认识都是一个 key:value 的缓存,当然用的最多的也就是这个作用。但随着 Redis 的不断发展,慢慢的我就发现它有的功能越来越多,它可能在一定程度上帮我们快速简化一些高并发场景下的开发。我觉得它其中最重要的设计是它的 数据结构 。通过几个基础的数据结构的组合,就能实现一些高性能的结构。比如我们今天要讨论的 Sorted Set 就是这样一个结构。由于 Redis 中称为 zset 所以后文中为了简化直接也叫 zset。
什么是 Sorted Set我觉得可能很多同学还没有用过,其实非常容易理解,就是一个有序的集合,无论你以什么顺序添加元素,最终都会根据分数排成一个有序的集合。通过它我们可以快速获得一个组数据的最高的几个值。
猜测实现堆?没错,我的第一反应也是这个,要实现一个这样的结构最先想到的就是堆或者说是优先队列的实现,完美匹配。
但,不对,我们知道,对于堆,我们只能快速得到最大或最小值。而对于 zset 其中有一个方法是 ZRANGE key start stop 也就是可以获取一个范 ...
快速上手 K8S Operator
前言如果你想要对 K8S 做二次开发或者说在原有的基础上封装一些功能让开发者更加好用,那么 Operator 的用法你可必须掌握。
什么是 Operator我觉得 Operator 真的是 K8S 扩展设计的非常巧妙的一点,它好像一个插件系统,你有了它就好像有了 k8s 的一个扩展操作权,能扩展出各种各样的用法。那什么是 Operator 呢?这需要从 CRD 说起。
CRD首先我们需要知道第一个概念就是 CRD(Custom Resource Define),自定义资源定义,顾名思义就是使用者可以通过 CRD 来创建自定义的资源。我们知道在 K8S 中有各种各样的资源 Pod、Deployment、StatefulSet… 在编写 yaml 文件的时候会指定对应的资源类型。
官方文档:Create a CustomResourceDefinition 其中有一个实际的 CustomResourceDefinition 案例
123456789101112131415161718192021222324252627282930313233343536373839404142434445 ...
Golang 中 能否将 slice 作为 map 的 key?
前言最近好忙,也好久没水 Golang 的文章了,最近来水一些。说回今天的问题,这个问题非常简单,也能被快速验证。
Golang 中 能否将 slice 作为 map 的 key?
如果你现实中使用过,那么这个问题对于你来说其实意义不大,因为不行就是不行,可以就是可以。
如果你完全没这样使用过 map,那么这个问题对于你来说可能就有意义了。
思路
首先这个问题的思路在于能否作为 key 的条件是什么?
key 在 map 中的作用是标记一个 kv,我们需要用 key 去查找对应的 value
那么我怎么知道,一个输入的 key 是否在这个 map 中呢?答案是比较
所以只要这个 key 能比较,说白了就是能使用 “==” 进行比较,大概率就没有问题
所以其实,这个问题的本质是:“slice 能否进行比较?”
答案答案显然是不能的,因为 slice 是不能使用 “==” 进行比较的,所以是不能做为 map 的 key 的。而官方文档中也说明了 https://go.dev/blog/maps
As mentioned earlier, ma ...