『OSPP2023』我与 OSPP 的故事 —— 项目经验分享
书接上文 『OSPP2023』我与 OSPP 的故事 —— 从听闻到中选 ,本文注重于描写项目开发的经历
项目基本信息
项目名称:为 Envoy Go 扩展建设插件市场
项目导师:纪卓志
项目描述:
Envoy 是当前最流行的网络代理之一,Go 扩展是 MOSN 社区为 Envoy 增加的 Go 生态基础,也是 MOSN 社区 MoE 框架的基础。
受益于Golang生态系统,研发可以轻松在 Envoy 实现插件用于更多的长尾场景,其中很多场景都是通用的。
本项目是为Envoy Go 扩展构建插件市场。在插件市场中,人们可以在插件市场中分享插件,选用已经存在的插件。通过插件市场,可以让 Envoy、MoE 生态变得更加开放、共享、丰富。
项目链接:
https://summer-ospp.ac.cn/org/prodetail/23f080259?lang=zh&list=pro
项目迭代经历
首先我想说这个项目的架构设计经历了多次变动,发现最后做出来的和最开始想的根本不是一个东西(笑)
一开始 OSPP 上简短的描述并不能让我了解太多,于是我开始翻 MOSN 的文档,并且和导师在 Issue 下交流更为详细的需求
需要实现的是一个插件市场,也就是类似于 VSCode Marketplace 或者 GitHub Marketplace 的效果,含插件提交、审核、版本管理和二进制构建分发等
我的构想是分为三个部分,GitHub、后端本体还有镜像仓库
开发者在自己的仓库里开发,如果要上架的话需要移交仓库权限到官方组织里,发布新版本就正常 Releas ...
你还惦记着你那二面呢|Allow Everything to Happen
「你还惦记着你那二面呢」
我真的好累,今天还吐了,感觉病了
我消失了很长一段时间,本来我想写一篇长文,记录我从 8 月 22 号返校到现在发生的所有事情
但是我真的好累,简单地说,就是诸事不顺,面试、亚运、学业…我不想写
我总是想在最后来一波升华,但是我其实并没有走出来,架构不出,我写不出来
我太想成功了,但这正是我没法成功的原因
就像你找东西,你越找就越找不到,经常是后面不经意的时候突然就冒出来了
就我现在这个状态,我想留一句话,与君共勉吧
Allow everything to happen|允许所有事情发生
最后,我还想说
爸爸妈妈,我永远爱你们❤️
浅析 JWT Refresh Token
最近逛 V 站又看见有人在讨论 JWT,感觉很多人讲的很乱,我想简单记录下我印象中的理解
Session
最开始应该是 session 方案,就是用户登陆后服务器返回客户端一个存根(token)来标识当前的会话
服务器在缓存中保存这个 token,用户请求时需要传递这个 token(不管你是使用 cookie header 还是 query)
每次请求服务器都在缓存中查找这个 token,并且找到当前会话的相关信息(比如说是哪个用户)
使用这种方案的优点:
强控制性:可以手动过期,如果想让某个用户下线就直接在缓存删除对应的键值对就行
可观察性:可以很清楚地看见当前的在线用户数量
使用这种方案的缺点:
性能需求高:因为每次请求都要查缓存,如果用户规模越大的问题越明显
对分布式不友好:他是有状态的,你必须共用一个缓存空间来存储数据
原始 JWT
为了克服上面的缺点, JWT 出现了
JWT (JSON Web Token ) 使用的是一种很巧妙的方法,他本身也是一个 string token,分为三部分
Header.Payload.Signature
Header,标识加密算法
Payload,你要存储的数据,比如说用户 ID 、权限 Level 与过期时间等,请注意这是外部可读的
Signature,加密算法签名
你需要注意的是,Payload 是前后端都可读的,但是可以使用 Signature 保证这个 Payload 是未更改的
工作流程是这样的:
用户登陆后服务器通过本地密钥计算并返回 JWT 给用户,用户请求时需要传递这个 JWT(不管你是使用 cookie ...
字节二面挂,还是人太菜了
字节一面
自我介绍
简单介绍字节青训营项目
是组队的吗
项目耗时
项目收获的点
ELK 是你们搭建的吗
ELK 的软件安装
数据流大概是怎样的
是通过什么写到 Logstash 里的
Logstash 的功能
你们用的的 fail2ban 是什么
traceID 介绍
微服务框架用的什么
traceID 在框架中是怎么传递的
对于异步的请求怎么处理的
这个项目的挑战和难点
Golang 的 Panic 关键字
Panic 怎么恢复
不加 defer 会怎样
为什么不能恢复
go 的方法的传值,传递切片,是怎么传的,在里面改变切片,外部能感受到吗
你说的副本是什么概念
在函数中 map 改变 kv,外部能感受吗
传递结构体,一般传值还是传指针
GMP 模型
在一个程序中不断起 goroutine,它的队列最终是个什么状态
一个 G 在一个 M 上执行的时间过长,会怎样调度
是通过什么策略控制的呢
刚才说的太长时间你有个时间上的概念吗,什么时间算太长
协程和线程的区别
其他的优势,怎么时候选择协程,什么时候不应该选协程
线程和协程,IO 密集型和 CPU 密集型哪个更适合
他节省的时间是怎么体现的
如果我找其他的线程呢?有什么区别
你比较擅长什么
MySQL 为什么使用 B+ 树
分裂与结合,这个是 B 树与 B+ 树的区别吗
放在叶子结点上导致了什么呢
还有其他的吗
了解过跳表吗
时间复杂度一样吗,跳表和 B+
为什么 Redis 的 zest 使用了跳表,为什么不用 B+
MySQL 和 Redis 这两种的本质区别
有没有可能这两种分别适用于内存和磁盘
你有什么想问的
简单 ...
阿里云OSS被刷,我交了1000RMB学费
大致经过
垂死病中惊坐起😱
事情发生在 8 月 8 日凌晨,凌晨三点我突然看见手机上的消息
我一开始是疑惑的,我的 OSS 是用来当做图床的,一个月也用不了几个钱
账号里记得还有 20 多块钱,怎么会这么快用完
然后我进阿里云一看,哇,我被人刷了?
最后发现被刷了 3.57 TB,请求了 138 万次
哇,我从没想到过这种事情会发生在我的身上
而且我停机之后他还一直在刷,根本不带停的(
我想,算了,300 块交学费得了,以后得好好重视
然后我下午就看见了——
1000 软妹币的账单😭
1000 RMB!这下真的被上课了😱
由于账单会有几小时的延迟,很多人说为什么欠费了不自动停,其实等你欠费的时候,人家已经刷完了
这次在我发现的时候,就已经结束了
真的太可怕了,直接大出血
花了好久才缓过来劲
可能的原因
我感觉最可能的原因,是我前段时间我写的一个玩具被人发到 Twitter 上了(属于是间接出圈
然后就别人盯上了🥹
当时还挺高兴的,这属于是出名的代价吗
寻求客服
最后我想看看找一手客服,其实我是不报希望的,看了一堆案例都是自己承担的
结果的确如此,真的是交了 1000 RMB 学费了
解决方案
事已至此,接下来的事情就是寻找解决方案了
在与群友交流和不断 Google 后,我总结了几种比较好的图床解决方案:
国内云 OSS + 国内云 CDN(如果你很在意国内的访问速度)
国内云 OSS + Cloudflare(比较推荐的方案,但是国内访问不会很快)
Cloudflare R2(如果你有信用卡)
某些奇技淫巧
国内云 OSS + ...
『Golang』并发编程之通道(Channel)
通道(Channel)
通道是什么,为什么使用通道
「不要通过共享内存来通信,而应该通过通信来共享内存」
通道可以在多个 goroutine 之间传递数据
一个通道相当于一个先进先出(FIFO)的队列。也就是说,通道中的各个元素值都是严格地按照发送的顺序排列的,先被发送通道的元素值一定会先被接收。元素值的发送和接收都需要用到操作符 <-。我们也可以叫它接送操作符。一个左尖括号紧接着一个减号形象地代表了元素值的传输方向
如何初始化通道
12345678func main() { ch1 := make(chan int, 3) ch1 <- 2 ch1 <- 1 ch1 <- 3 elem1 := <-ch1 fmt.Printf("The first element received from channel ch1: %v\n",elem1)}
使用 make 函数声明并初始化通道
通道的容量是 int 类型,但是不能小于 0 (缓冲通道和非缓冲通道)
通道的发送和接收操作都有哪些基本的特性
对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的
发送操作和接收操作中,对元素值的处理都是不可分割的
发送操作在完全完成之前会被阻塞,接收操作也是如此
元素值从外界进入通道时会被复制
非缓冲通道的数据是直接从发送方复制到接收方
大多数情况下缓冲通道都会中转数据,如果发送时正好有人在等着接收,则会直接复制过去
什么时候会阻塞
正常情况下
缓冲 ...
『OSPP2023』我与 OSPP 的故事 —— 从听闻到中选
6月26日下午3点,OSPP2023 中选结果正式发布,全球共有 1486 人成功申请,最终中选人数为 504 人
鄙人非常荣幸地成为了这 504 个幸运儿的一份子,特撰此文,记录 我与 OSPP 的故事 —— 从听闻到中选
当然,我也希望这篇博客能够吸引更多人参与开源,为开源项目做出自己的贡献
给「杭电助手」打点小广告
本次开源之夏活动,杭州电子科技大学共中选 13 人,其中 8 人来自杭电助手
杭助本次共参与 11 人,中选率高达 8/11
(另外今年另有 1 人中选 GSoC,1 人 LFX Mentorship )
欢迎热爱技术的同学们填报杭州电子科技大学,欢迎同学们选择杭电助手技术部! 查看推文
写在前面
这里是对不了解开源活动的同学进行一点飞速的补充,简短地谈一下我的理解
其实已经有很多文章讲的很好了,这里我推荐一篇杭助成员「爱飞的鸟」的 Before Good First Issue
开源活动是什么
开源活动通常是由开源社区、组织或公司组织的活动,目的在于吸引更多的人(特别是学生)参与开源,帮助构建开源项目,增加开源社区热度,推广开源文化与价值观,为开源事业作出贡献
比较有名的比如 LFX Mentorship、谷歌的 GSoC、国内的 OSPP、GLCC 等
一般的形式是这样的:由活动主办方提供平台与资金,吸引各路开源社区/组织入驻,社区挑选目前要做的一些活作为若干子项目(写清楚具体要做什么事情,最终达成什么目的),并且分配至少一个导师专门负责这个项目(大多数是一个)
学生呢需要给导师写 Proposal(申请书),阐述自己对这个项目的想法(如何 ...
『算法拾遗』重学主流排序算法
衡量排序算法的好坏时间复杂度
包含最好情况、最坏情况和平均情况
数据有序度不同的影响
空间复杂度
是否是原地排序
稳定性
排序后,相同元素之间的顺序是否会改变
O( n^2 )
冒泡排序(Bubble Sort)
依次比较相邻的元素,如果顺序错误,则交换它们。每轮排序将最大(或最小)的元素“冒泡”到正确的位置
简单易懂,但效率较低,不适用于大规模数据排序
过程
初始化待排序数组,设为 arr ,数组长度为 n
外层循环:重复 n-1 次(即 i 从 0 到 n-2 ) 思考:为什么外层是n-1次
内层循环:重复 n-i-1 次(即 j 从 0 到 n-i-2 ) 思考:为什么内层是n-i-1次
比较 arr[j] 和 arr[j+1] ,如果 arr[j] 大于 arr[j+1] ,执行下一步,否则继续内层循环
交换 arr[j] 和 arr[j+1] 的位置
判断是否在本轮内层循环中进行了交换操作:
如果没有进行交换,说明数组已经有序,提前结束排序
冒泡排序结束,数组 arr 已经按升序排列
性质
在排序没有完成之前,小的数会逐步往前移,大的数会逐步往后移动
每轮排序至少会让一个最大元素放置在正确位置,重复 n−1n-1n−1 次,就完成了 nnn 个元素的排序
是稳定的排序算法
空间复杂度:冒泡排序的空间复杂度为 O(1)O(1)O(1),它在原地进行排序,不需要额外的内存空间。
最优情况:冒泡排序的最优情况是输入数组已经有序。在这种情况下,只需要进行一次遍历,没有元素交换,时间复杂度为 O(n)O(n)O(n)
最坏 ...
『算法拾遗』链表(Linked List)
这两天在复习链表,我一想,这链表这么简单的东西还有什么复习的,简单过一遍不就行了
然而马上打脸,有些题目我居然还写不出来(乐
理论基础
先来点你肯定知道的东西,简单过一遍
是什么
如图所示,链表是一种链式结构,以最简单的单链表为例:
1234type ListNode struct { Val int Next *ListNode}
也就是头节点指向下一个节点,然后下一个节点再指向下一个节点,如果是尾节点就指向 NULL (或者说是 Golang 里的 nil )
基本操作
删除节点
让前面节点认为它的后面是后面的节点
删除的节点让 GC 自动回收掉即可
添加节点
让新节点指向后面节点,让前面节点指向新节点
链表的几种变体
有头链表
减少对头节点的特殊处理
双向链表
可以方便地找到前驱节点
对于一个有序链表,双向链表的按值查询效率要比单链表高一些。因为我们可以记录上次查找的位置p,每一次查询时,根据要查找的值与p的大小关系,决定是往前还是往后查找,所以平均只需要查找一半的数据。
循环链表
能解决约瑟夫问题
有头双向循环链表
buff 叠满,请见 【有头双向循环链表之美,这个数据结构简单又优雅,学会了不亏】
链表 vs 数组
插入删除
随机访问
数组
O(n)O(n)O(n)
O(1)O(1)O(1)
链表
O(1)O(1)O(1)
O(n)O(n)O(n)
必知必会的题目
707. 设计链表
实现一个链表,这里就以带头单链表为例
1234567891011121314151617181920212223 ...
2023五一总结:近况与将来
事情有点多,就简单说几句吧~
Your browser does not support the audio tag.
最近的事情
杭电助手团建
[{"url":"https://image.nickxu.me/202305042227317.png","alt":"image-20230504222737293"},{"url":"https://image.nickxu.me/202305042228416.png","alt":"image-20230504222810383"},{"url":"https://image.nickxu.me/202305042228652.png","alt":"image-20230504222817629"},{"url":"https://image.nickxu.me/202305042228681.png","alt":"image-20230504222822653"},{"url":"https://image.nickxu.me/202305042228729.png","alt":"image-20230504222830701"},{"url":"https://image.nickxu.me/202305042228227.png","alt":"image-20230504222846195"},{"url":"https://image.nickxu.me/202305042229391.png","alt":"image-20230504222910356"},{"url":"ht ...
关于软删除的讨论
别急,先挂着
别问我为什么空着就发上来了,我本来是想每一篇都写完再发的,但是后面本地坑挖了很多不想填就直接删了
然后发上来至少别人看着我还有动力去填🤣
7 月 11 日更:
卧槽居然过了这么久了才有空填
过了两个月了基本忘光了,翻了翻聊天记录,记起来了一点点
其实有个大佬的博客 软删除之痛 已经将前情提要概括了一下,下面就简单补充一下
文中写的唯一索引的例子在我们的开发中也遇到了,但是我们有不一样的解决方法
就是在删除的时候改个名,这样就能规避问题了
目前来说感觉这种方法没有还引发新的问题
在 Mac 的 VSC 中使用 g++ 编译器
本人最近开始复习算法刷题了,然后用的是 macOS 上 VSCode 的默认配置,也就是 clang/clang++ 编译器,但是高中的时候用惯了 gcc/g++ 了,很多 g++ 的方言 clang 并不支持,例如 #include <bits/stdc++.h> 之类的
可能你会说,这有什么的,直接把编译指令里面的编译器替换一下不就行了
如果真的这么简单的话就没有这篇博客了(bushi
首先我换了之后并不能解决问题, 接着我发现了一个很恐怖的事情(
我的 gcc 怎么被 clang 夺舍了???
我的第一个反应是卸载 clang ,毕竟我也不想用这玩意,然后我看这东西是哪里安装的
12whereis clangclang: /usr/bin/clang /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/share/man/man1/clang.1
啊,原来是 Xcode 哇,这东西我平时也用不上,还占着这么大的空间,我这就把你卸了
Xcode 是我刚开始上手 macOS 的时候学长建议我安装的,但是这东西快15个G,我平时又用不上
卸完之后我发现 clang 还是在,我就继续看
12whereis clangclang: /usr/bin/clang /Library/Developer/CommandLineTools/usr/share/man/man1/clang.1
原来是 CommandLineTools ,我又搜了一下这个 ...
GORM 的 GEN 模式初上手
最近准备上手一个新项目,然后在选择底层的 ORM 框架
我之前一直用的 GORM ,其实感觉还挺好用的,但是毕竟用多了,这次也想了解下其他的解决方案
之前在和群友讨论 GORM 的时候,我听见有人对它有一些负面的看法,比如说认为 GORM 不算真正的 ORM,因为它很多时候只是在帮你手动拼凑 SQL 语句,只是没有写原生 SQL 那么痛苦而已,我听了之后感觉其实也有点道理
比如说我最近项目里的一句查询
12345l.svcCtx.DBList.Mysql. Where("from_id = ? and to_user_id = ?", in.UserAId, in.UserBId). Or("from_id = ? and to_user_id = ?", in.UserBId, in.UserAId). Order("created_at desc"). First(&result)
其中还是要手打 from_id 和 to_user_id 这些字段名,就像原生 SQL 一样,而真正的 ORM 不应当是这样的,应当走如同 ent 这种代码生成的路子
甚至我也听过有人认为不应该使用 ORM 框架:为什么要旗帜鲜明地反对 orm 和 sql builder
也就是说你的 ORM 虽然方便,但是不方便进行 SQL 语句的审查,也就是说你不能预测线上环境会生成哪些 SQL,会有不确定性
但是其实我觉得吧,他说的场景我现在都还遇不到,我的项目也就是一些简单的 CURD ,而且数据量也不大
那么现在的情况就是说,我可 ...
Hexo 首页添加 Gitcalendar 提交日历
折腾了一上午算是搞定了,先来看看效果
感觉颜色还是不够好看?算了就这样吧
自建后端 Api
首先这个组件是来源于 Akilar 大佬的,然后后端是冰老师写的
Gitcalendar | Akilarの糖果屋https://akilar.top/posts/1f9c68c9/
但是默认的 api 是失效的,必须自建 api ,因为之前 GitHub 接口改了,所以原来的正则不能用,有大佬提了 PR ,但是一直没和进去
所以你自建后端 api 的时候应该是 fork 这个仓库
PS:2023 年 11 月 16 日 更新
今天这个规则又改了,我喂给 GPT 他帮我修好了,我也发起了 PR
不过最新的 commit 还在我的仓库
然后你就跟着教程一路走下去即可
经典域名问题
等你建好了就遇到了经典的 Vercel 被墙问题:在国内没法使用,这时候你就需要给你的 project 添加一个自己的域名
就如我在 『Twikoo』解决 Vercel.app 在国内被墙导致无法使用的问题 中的那样操作
然后你就可以测试一下能否正常访问,例如我的是 https://git-calendar.nickxu.top ,然后加个你 GitHub 用户名的参数试一下
1https://git-calendar.nickxu.top/api?NX-Official
好了,现在后端搭建完毕,其实如果你后端实在搭建不起来也可以用我的后端
搞定颜色
默认的配置文件里面的颜色我感觉和我的暗黑主题不太搭,我就想用 GitHub 上面的那一套配色
但是有个问题就是 GitHub 上面只有 1 种 ...
go-cqhttp QQ 机器人初上手
之前看见过很多 qq 机器人的例子,比如把 ChatGPT 接进群里之类的,然后最近有点空闲,并且感觉宿舍群里也缺少一些自动化的建设,就打算上手做一个
功能上的设计先别搞那么复杂,就先接个 ChatGPT 算了
我就去问关于qq 机器人的最佳实践,然后就知道了 go-cqhttp
大致流程
去官网逛了一下,第一次还没怎么看懂,群友给了一个 demo ,我看懂了
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374package mainimport ( "github.com/gin-gonic/gin" gogpt "github.com/sashabaranov/go-openai" "golang.org/x/net/context" "io/ioutil" "net/http" "net/url")import "github.com/tidwall/gjson"func main() { r := gin.Default() r.POST("/", func(c *gin.Context) { dataReader := c.Request.Body rawDate ...
轻量级日志收集系统 Grafana Loki 初上手
关于日志收集,鄙人最早接触到的是 ELK 那一套(Elasticsearch、Logstash 和 Kibana),最近我青训营的项目也是差不多的架构,但是这一套下来资源占用也太可怕了(特别是 Elasticsearch ,太重了)
go-zero 官方也说了,这一套不建议在小规模的服务上使用,而我一般的实际项目也没多大规模,根本用不上这么重的解决方案,所以我需要找一套更轻量的解决方案
翻了一圈,感觉推荐 Grafana + Loki 的不少
然后我就跑去 Loki官方文档了
这是官方文档中的快速上手的架构图,为了让你感受它的可扩展性,就把内部的读写部分拆出来运行,其实不用这么复杂,直接一个单体也可以
折腾了一圈,大概是这么个逻辑:首先是要有一个 Client(例如图中的 Promtail )去拉取运行日志喂给 Loki ,然后 Loki 去读写 Storage(例如图中的 Minio ),那日志要怎么方便地查看呢?用 Grafana ,这东西界面做的真的很好看
为了让你快速理解与上手,我简化了一下官方 Demo,docker-compose 中只包含四个服务:
产生日志的程序:和官方一样使用了 flog 来不停地向标准输出中放入假日志
Loki:用于打包日志、打标签等
Client:用于拉取日志交给 Loki,Loki 支持多种客户端,你可以在 Grafana Loki clients 中查看支持的所有客户端
我知道有一个 Docker Driver ,但是这东西要给 Docker 装插件,感觉有点麻烦,还是和官方例子一样使用了 Promtail
...