1.多详解万星Restful框架原理与实现
2.SRS(simple-rtmp-server)流媒体服务器源码分析--启动
3.Kafka源码分析(五) - Server端 - 基于时间轮的源码延时组件
4.2024年度Linux6.9内核最新源码解读-网络篇-server端-第一步创建--socket
5.vscode server源码解析(三) - code server
多详解万星Restful框架原理与实现
rest框架概览
我们先通过go-zero自带的命令行工具goctl来生成一个apiservice,其main函数如下:
funcmain(){ flag.Parse()varcconfig.Configconf.MustLoad(*configFile,结构&c)ctx:=svc.NewServiceContext(c)server:=rest.MustNewServer(c.RestConf)deferserver.Stop()handler.RegisterHandlers(server,ctx)fmt.Printf("Startingserverat%s:%d...\n",c.Host,c.Port)server.Start()}解析配置文件
将配置文件传入,初始化serviceContext
初始化restserver
将context注入server中:
注册路由
将context中的源码启动的endpoint同时注入到router当中
启动server
接下来我们来一步步讲解其设计原理!Let'sGo!
web框架从日常开发经验来说,结构一个好的源码web框架大致需要满足以下特性:
路由匹配/多路由支持
支持自定义中间件
框架和业务开发完全解耦,方便开发者快速开发
参数校验/匹配
监控/日志/指标等服务自查功能
服务自保护(熔断/限流)
go-zerorest设计/api-grammar.html中的结构lnmp环境源码安装tag修饰符
Tips学习源码推荐fork出来边看边写注释和心得,可以加深理解,源码以后用到这块功能的结构时候也可以回头翻阅。
项目地址/zeromicro/go-zero
欢迎使用go-zero并star支持我们!源码
微信交流群关注『微服务实践』公众号并点击交流群获取社区群二维码。结构
SRS(simple-rtmp-server)流媒体服务器源码分析--启动
小卒最近探索了SRS源码,源码并撰写博客以整理思路,结构方便日后查阅。源码SRS源码具备以下优势:
1、结构轻量化设计,源码代码结构清晰,SRS3.0版本代码量约为8万行,功能却足以支撑直播业务。
2、采用State Threads架构,实现高性能、高并发。
3、支持rtmp和hls,满足PC和移动直播的需求。
4、gee 源码支持集群部署,适应不同规模的部署需求。
代码分析分为两个阶段:一、梳理代码框架,理解流程;二、深入细节,熟悉SRS工作原理。
SRS源码框架包括系统启动、RTMP消息处理、RTMP信息发布、HLS切片等功能模块。系统启动时,初始化类,监听端口,对每个访问请求创建线程,专门处理连接操作。
系统监听包含不同类型的请求,如RTMP连接、HTTP API等,通过创建线程处理。
RTMP连接处理中,SRS采用协程而非线程,实现高效并发。创建协程后,进入协程循环处理。moya 源码
HTTP API连接监听机制与RTMP类似,仅参数不同。
HTTP API回调接口在run_master函数中注册,允许访问服务器参数。
SRS对拉流处理独特,通过ffmpeg工具实现,SRS代码负责简单的系统调用。
系统启动代码结构清晰,从初始化、监听到线程处理,再到回调注册、拉流处理、自服务,各环节紧密衔接。
总结SRS源码分析,不仅展现了代码的高效性和扩展性,还提供了灵活的部署方案,适用于多种直播场景。
Kafka源码分析(五) - Server端 - 基于时间轮的延时组件
Kafka内部处理大量的延时操作,例如,在接收到PRODUCE请求后,副本可以等待一个timeout的时间再响应客户端。下面我们来探讨一个问题:为什么Kafka要自己实现一个延时任务组件,而不是直接使用Java的java.util.concurrent.DelayQueue呢?我们可以从以下两个方面来分析这个问题。
1.1 DelayQueue的scheme 源码能力
DelayQueue相关的接口/类如下所示:
相应地,DelayQueue提供的能力如下:
1.2 Kafka的业务场景
Kafka的业务背景具有以下特点:
相应地,Kafka对延时任务组件有以下两点要求:
这两点要求都无法通过直接应用DelayQueue的方式得到满足。
二. 组件接口
让我们来看看Kafka的延时任务组件对外提供的接口,从而了解其提供的能力和使用方式。
如下所示:
左边的两个类定义了"延时操作",右边的DelayedOperationPurgatory类定义了一个维护DelayOperaton的容器,其核心操作如下:
三. 实现
以下是关于"延时"实现方式的介绍。
3.1 业务模型
时间轮延时组件的思路如下:
接下来,通过一个具体的例子来说明这种映射逻辑:
首先关注上图中①号时间轮。圆环中的每一个单元格表示一个TimerTaskList。单元格有其关联的时间跨度;下方的"1s x "表示时间轮上共有个单元格,每个单元格的时间跨度为1秒。有一个指针指向了"当前时间"所对应的单元格。顺时针方向为时间流动方向。
当收到一个延迟时间在0-1s的TimerTask时,会将其追加到①号时间轮的橙色单元格中。当收到一个延迟时间在3-4s的TimerTask时,会将其追加到①号时间轮的**单元格中。以此类推。
现在有一个问题:①号时间轮能表示的最大延迟时间是秒,那如果收到了延迟秒的任务该怎么办?这时该用到②号时间轮了,我们称②号为①号的"溢出时间轮"。②号时间轮的特点如下:
如此,延迟时间在-s的TimerTask会被追加到②号的紫色单元格,延迟时间在-s的源码营养TimerTask会被追加到②号的绿色单元格中。③号时间轮同理。
刚刚是按①->②->③的顺序来分析时间轮的逻辑,反过来也可以得到有用的想象手里有一个"放大镜",其实③号时间轮的蓝色单元格"放大"后是②号时间轮;②号时间轮的蓝色单元格"放大"后是①号时间轮;蓝色单元格并不实际存储TimerTask。
3.2 数据结构
DelayedOperationPurgatory有一个Timer类型的timeoutTimer属性,用于维护延时任务。实际使用的是Timer的实现类:SystemTimer。该类用于维护延时任务的核心属性有两个:delayQueue和timingWheel。TimingWheel表示单个时间轮,接下来我们来看看其类图:
各属性含义如下:
3.3 算法
3.3.1 添加任务
添加任务的入口是DelayedOperationPurgatory.tryCompleteElseWatch,其核心逻辑分为如下两步:
SystemTimer.add直接调用了addTimerTaskEntry方法,后者逻辑如下:
TimingWheel.add的逻辑也很清晰,分如下4种场景处理:
3.3.2 尝试提前触发任务
入口是DelayedOperationPurgatory.checkAndComplete:
接下来看Watchers.tryCompleteWatched方法的内容:
DelayedOperation.maybeTryComplete方法最终调用了DelayedOperation.tryComplete;
DelayedOperation的子类需要在后者中实现自己的"触发条件"检查逻辑;若满足了提前触发的条件,则调用forceComplete方法执行事件触发场景下的业务逻辑。
3.3.3 任务到期自动执行
DelayedOperationPurgatory中维护了一个expirationReaper线程,其职责就是循环调用kafka.utils.timer.SystemTimer#advanceClock来从时间轮中获取已超时的任务,并更新时间轮的"当前时间"指针。
四. 总结
才疏学浅,未能窥其十之一二,随时欢迎各位交流补充。若文章质量还算及格,可以点赞收藏加以鼓励,后续我继续更新。
另外,也可以在目录中找到同系列的其他文章:
感谢阅读。
年度Linux6.9内核最新源码解读-网络篇-server端-第一步创建--socket
深入解析年Linux 6.9内核的网络篇,从服务端的第一步:创建socket开始。理解用户空间与内核空间的交互至关重要。当我们在用户程序中调用socket(AF_INET, SOCK_STREAM, 0),实际上是触发了从用户空间到内核空间的系统调用sys_socket(),这是创建网络连接的关键步骤。 首先,让我们关注sys_socket函数。这个函数在net/socket.c文件的位置,无论内核版本如何,都会调用__sys_socket_create函数来实际创建套接字,它接受地址族、类型、协议和结果指针。创建失败时,会返回错误指针。 在socket创建过程中,参数解析至关重要:网络命名空间(net):隔离网络环境,每个空间有自己的配置,如IP地址和路由。
协议族(family):如IPv4(AF_INET)或IPv6(AF_INET6)。
套接字类型(type):如流式(SOCK_STREAM)或数据报(SOCK_DGRAM)。
协议(protocol):如TCP(IPPROTO_TCP)或UDP(IPPROTO_UDP),默认值自动选择。
结果指针(res):指向新创建的socket结构体。
内核标志(kern):区分用户空间和内核空间的socket。
__sock_create函数处理创建逻辑,调用sock_map_fd映射文件描述符,支持O_CLOEXEC和O_NONBLOCK选项。每个网络协议族有其特有的create函数,如inet_create处理IPv4 TCP创建。 在内核中,安全模块如LSM会通过security_socket_create进行安全检查。sock_alloc负责内存分配和socket结构初始化,协议族注册和动态加载在必要时进行。RCU机制保护数据一致性,确保在多线程环境中操作的正确性。 理解socket_wq结构体对于异步IO至关重要,它协助socket管理等待队列和通知。例如,在TCP协议族的inet_create函数中,会根据用户请求找到匹配的协议,并设置相关的操作集和数据结构。 通过源码,我们可以看到socket和sock结构体的关系,前者是用户空间操作的抽象,后者是内核处理网络连接的实体。理解这些细节有助于我们更好地编写C++网络程序。 此外,原始套接字(如TCP、UDP和CMP)的应用示例,以及对不同协议的深入理解,如常用的IP协议、专用协议和实验性协议,是进一步学习和实践的重要部分。vscode server源码解析(三) - code server
初次接触code server,可参考介绍文章。整体架构不清晰时,建议阅读架构分析。
在深入分析code server代码之前,先理解code server在远程开发中的作用。code server作为服务器的核心功能,提供远程IDE访问,基于express框架和nodejs平台构建,实现了轻量级服务器的基础。此外,它提供用户登录功能,确保安全访问,并在登录后加载vscode server内核代码。
code server还具备升级、代理和心跳检测等功能,但这些细节在此不作深入探讨。
本文将重点解析code server的启动机制、提供服务的实现方式、中间件和路由设计,以及如何启动vscode内核。
code server的启动通过src/node/entry.ts文件实现,启动命令为`code-server`。实际上,这只是一个shell脚本,通过`node`命令启动程序。在package.json中定义了启动逻辑。
程序启动时,会检查当前进程是否为子进程,进而决定执行的启动方式。父进程负责管理整个软件,启动子进程并控制其生命周期,以及与子进程通信,比如接收日志输出。子进程则作为真正的express框架服务器,加载vscode server内核代码。
运行代码通过`runCodeServer`方法启动,首先通过`createApp`创建服务器,监听指定的主机和端口。`handleUpgrade`方法处理websocket连接,这是vscode server前后端通信的关键。详细说明将单独撰写。
路由和中间件是code server的核心部分。路由定义了服务器提供的接口,如GET和POST,供前端调用。中间件则负责处理请求前后的预处理和后处理工作,如鉴权,注册到express框架中。
code server中的`register`方法处理路由和中间件逻辑,将请求分发到不同的路由,如`/login`和`/health`,每个路由包含各自的中间件处理请求。
关于vscode server内核的启动,主要通过`src/node/routes/vscode.ts`文件实现。在经过鉴权等路由处理后,请求到达特定路由。`ensureCodeServerLoaded`中间件负责加载vscode代码。`loadAMDModule`执行原生vscode启动过程,引入模块。加载完成后,可以获得`createVSServer`方法,用于真正启动vscode内核。
至此,code server的基本功能实现完毕。接下来将深入探讨vscode server内核和websocket协议。