2023 年度总结:成长、探索与沟通
起笔写这篇文章时,距离我校招提前实习已经过去一个月。早在秋招结束时,我就计划着撰写一篇类似的总结文章,但由于一时懒散,最终只是写了一些零散的片段,凑不成一篇完整的文章。因此,在这篇年度总结中,我想稍微记录一下我对秋招的感受。
回顾 2023 年,许多在 2022 年设定的目标都未能实现,包括深入学习 Kubernetes 和掌握 Rust 等。在五月、六月以及秋招后至实习入职期间,感觉自己有些散漫,代码能力也没有显著提升。
幸运的是,我在三月份成功找到了实习机会,度过了五个月的杭漂生活。尽管在后续的秋招中遇到了一些波折,但也有不少收获。整个一年中,我经历了许多事情,走过了许多未曾到过的地方,还有幸与许多素未谋面但一直保持联系的网友线下见面。总体来说,过得还算不错。
我在去年十一月初踏上了求职的征程,第一场面试虽以失败告终,但至少迈出了第一步。到了十二月份,陆续参加了几轮其他小公司的面试,然而最终都未能通过终面。反思的过程中,我逐渐找出了问题所在。在面试中,我发现之前自己琢磨的源码设计难以清晰地表达出来,这引起了我对自身一贯弱点的认识:输出能力较差。在去年的年度总结中,我也提到总结是我的 ...
Hello 算法之十大排序
写在前面
本文复习自用,因为近期的几次面试都考察了比较基础的排序算法,所以记录一下。内容均来自Hello 算法 - 排序,这本书中详细描述了算法基础、各种数据结构以及各种算法类型,对我的帮助很大。再次感谢作者和各位贡献者的分享。
冒泡排序
通过连续比较与交换相邻元素实现排序。即使是经过优化,最差和最优的平均复杂度也为O(n^2),但是在输入数组完全有序的情况下,可以达到最佳的时间复杂度 O(n),属于稳定排序,在冒泡中遇到的相等元素不交换。
数组从最左端向右遍历,依次比较相邻元素大小,如果左元素>右元素就交换它俩,遍历完成后,最大的元素会被移到数组最右端。比较次数:n-1, n-2, …, 2, 1 总和为 (n - 1)n/2
1234567nums = [5, 3, 1, 2, 4]n = len(nums)for i in range(n - 1, 0, -1): # 外循环,未排序区间[0, i] for j in range(i): # 内层循环将[0, i]的最大元素交换至区间最右端 if nums[j] > nums[j + 1]: ...
一文了解 Go 语言 Context 标准库
笔者所用 Go 版本为:go1.20.5 linux/amd64
context 意为上下文,用于管理子 goroutine 的生命周期,或维护一条调用链路中的上下文,广泛用于微服务、以及各类标准包如 http、sql 中。context 的源代码非常的少且简洁,接下来笔者直接对 context 的源代码进行分析,并对 context 的应用场景做简单的介绍。
一个接口、四种实现、六个函数
Context 定义是一个接口,具体的实现有四种:emptyCtx、cancelCtx、timerCtx 以及 valueCtx。context 包对外暴露的方法主要有六个(实际上更多一点):Background()、TODO()、WithValue()、WithCancel()、WithDeadline() 与 WithTimeout()。
可以简单看出,Context 四个方法决定了 Context 的几个用途:设置 deadline、设置取消信号,以及携带一些值。
12345678910// A Context carries a deadline, a cancellation signal ...
一文了解权限访问控制模型
笔者实习过程中,主要负责权限模块,也趁机输出一下相关的知识。
ACL
访问控制列表(ACL,即 Access-control list),将一系列的权限与一个系统资源相关联。ACL 专注于个别许可的列表,想象一下你家门口的门禁系统,门禁系统上有一个名单,上面列出了允许进入你家的人的姓名。这个名单就像是一个 ACL,里面记录了具体的人名和他们被授予的进入权限,比如进入、离开、访问特定房间等。只有名单上的人才能够进入你家,其他人则不能。
一般的表结构设计如:ACL 表(对象标识,主体标识,权限标识),对象指需要访问的对象,比如门禁系统中特定的门口,主体代表进入你家的人,权限则标识进入、离开等。
一些变种包括:
ACL with superuser
普通用户的权限管理与之前一致,但引入了一个超级用户,不受权限管理控制,拥有所有权限。有了超级用户,排查些问题会比较方便。
ACL without users
适用于没有身份验证或用户登录的系统,比如文件共享系统,希望进行访问控制,但又不想为每个用户分配权限,就可以通过定义文件属性(如文件类型、标签、内容等)来管理文件的访问权限,从而更灵活 ...
初探容器网络
演变历史
容器网络的初期阶段,容器是一种封装技术,将应用和其依赖的环境打包在一起,方便快速部署和运行。对外暴露的方式相对简单:每个容器通过对应的端口暴露,外部程序可以通过不同的端口来区分不同的容器实例和应用实例。这种方案比较直接,没有引入任何网络堆栈,因此被广大开发者采纳。但是管理起来存在一些问题,因为每个容器都至少占用宿主机的一个端口。
为了解决容器规模化部署管理方面的问题,引入了 Overlay 网络方案。在这种方案下,两台主机之间构建一个默认私有的虚拟网络,支持容器与容器之间的通信,每个容器在虚拟网络中都有一个独立的 IP 地址。当容器需要对外暴露时,通过虚拟网络连接主机端口,主机端口对外暴露,外部数据包可以通过主机端口进入虚拟网络,然后路由转发给特定的容器。这也就是 Overlay 网络方案的工作原理。显而易见,Overlay 的优势在于允许无限制地部署容器,并提供虚拟网络中的独立 IP 地址,但通信数据仍然需要通过真实物理网络基础设施传输。然而,企业较少使用 Overlay,因为一些传统的应用程序可能依赖于特定网络拓扑配置和直接的主机间通信方式,而 Overlay 网络方案 ...
一文了解 LDAP
LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol),是一个开放的、中立的、工业标准的应用协议,经常用于身份验证以及存储关于用户、群组和应用程序的信息。LDAP Directory Server 是一个相对通用的数据存储,可在各种应用程序中使用。
为什么选择 LDAP
众所周知,数据存储有诸多类型,包括但不限于 NoSQL 类如 Redis、MongoDB 等,RDBMS 类如 MySQL、PostgreSQL 等,那么为什么要选择 LDAP 呢?
如果选择 NoSQL,基本上就将自己限定在了某种类型的数据库中,因为每种 NoSQL 数据库都有自己的协议。在 NoSQL 数据库中,包括多个种类,例如键值存储、文档数据库、列存储和图形数据库等。而每种类型的数据库都有自己独特的工作方式和协议。选择其中一种数据库意味着你将与这种数据库的特定协议绑定在一起,不同类型的 NoSQL 数据库之间的协议可能不兼容。
以 Redis 和 MongoDB 为例,Redis 使用一种简单而高效的文本协议与客户端进行通信,这个协议被称为 Redis 协议 ...
关于我的三个月杭漂
来杭州差不多三个月了,简单写一写杭漂三个月以来的感悟。
对杭州的第一印象
记得刚来杭州的时候很冷,刚下绿皮就哆嗦着穿多一件卫衣,现在杭州却热得有点受不了了,感觉和广州不分高下。杭州给笔者的第一印象是干净,到杭州那一天的下午,笔者去办杭州银行的银行卡,一路上发现和广州的最大区别是杭州非常干净,没有看到广州街道上随处可见的垃圾,但是沿路上都没见到垃圾桶(
打破第一次
打破了很多人生第一次
第一次一个人来到完全陌生的城市
第一次独立生活
第一次参与全职工作
第一次正式参与开源
。。。
工作方面,笔者是第一次实习。虽然是几百人的小公司,但是实习体验还是 OK 的。脱离学校后,真正地接触到生产环境,对各种利弊权衡有了更深的把握,对互联网公司的工作流程也有了真实的体验。
社交方面
虽说职场上不得与同事交心,但是组里的人都挺好的,一起工作也很快乐,至少在前两个月没什么压力。只可惜五月初 Leader 和导师都调去带新组了,其实还是挺想念他们的。
笔者早在一个玩具开源项目 GoFound 的微信交流群中认识了一个在杭州工作的群友,在来到杭州后也成功线下面基了,一起搓了好几顿。此 ...
一文了解 WebSocket 协议
为什么需要 WebSocket
短轮训->长轮训->基于流->WebSocket
TCP 长连接就是 WebSocket 的基础,但是如果是 HTTP 的长连接,本质上还是 Request/Response 消息对,仍然会造成资源的浪费、实时性不强等问题
特点
建立在 TCP 之上
与 HTTP 有良好兼容性
没有同源限制,客户端可以与任意服务器通信
标识符是ws/wss,服务器地址是URL
可以发送文本和二进制数据
数据格式轻量,性能开销小,通信高效。连接创建后,ws 客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有 2~10 字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的 4 字节的掩码。而 HTTP 协议每次通信都需要携带完整的头部;
建立连接
WebSocket 的目的是取代 HTTP 在双向通信的场景下使用,所以有些实现方式也是基于 HTTP 的(比如默认端口为 80/443),有向下兼容的意思。
客户端发起协议升级
123456789GET / HTTP/1 ...
Linux 笔记
数据结构
链表
相比普遍的链表实现方式,Linux 内核的实现比较独树一帜。普通的实现是数据通过在内部添加一个指向数据的 next 或 prev 节点指针,才能串联在链表中,存储这个结构到链表里的通常方法是在数据结构中嵌入一个链表指针,如 next 或 prev。而 Linux 内核中,是将链表节点塞入数据结构。
1234567891011struct list_head{ struct list_head *next; struct list_head *prev;};struct fox { unsigned long tail_length; unsigned long weight; bool is_fantastic; struct list_head list; // 所有fox结构体形成链表}
内核还提供了一组链表操作接口,比如 list_add() 加入一个新节点到链表中,他们都有一个统一的特点,就是只接受 list_head 结构作为参数。通过使用宏 container_of()我们可以很方便 ...
Raft 论文研读笔记
摘要
Raft 是用于管理复制日志的一致性协议,与 Multi-Paxos 作用相同,效率相当,但是架构更简单,更容易实现。Raft 将共识算法的关键因素分为几个部分:
Leader election 领导者选举
Log replication 日志复制
Safety 安全性
且 Raft 用了一种更强的共识性来减少要考虑的状态 state 的数量。
Raft 对比于现有的共识算法有几个新特性:
Strong leader(强领导性):相比于其他算法,Raft 使用了更强的领导形式。比如,日志条目只能从 leader 流向 follower(集群中除 leader 外其他的服务器)。这在使 Raft 更易懂的同时简化了日志复制的管理流程。
Leader election(领导选举):Raft 使用随机计时器来进行领导选举。任何共识算法都需要心跳机制(heartbeats),Raft 只需要在这个基础上,添加少量机制,就可以简单快速地解决冲突。
Membership changes(成员变更):Raft 在更改集群中服务器集的机制中使用了一个 联合共识(joint consensu ...