- 博客(129)
- 收藏
- 关注
原创 基于C语言实现的KV存储引擎(一)
本文主要是基于 C 语言来实现一个简单的 KV 存储架构,目的就是将网络模块跟实际开发结合起来。首先我们知道对于数据的存储可以分为两种方式,一种是在内存中进行存储,像 Redis 这种,是一种内存型数据库,主要也是以 KV 的形式进行存储,提升了对应的数据的访问效率;另一种就是在磁盘中进行存储,像 MySQL 这种,是一种关系型数据库,更多的是以一种表的形式去组织的数据库,也是一种主流的数据库,但是访问的速度就稍微慢一点儿。
2025-07-30 20:46:39
725
原创 探秘 Nginx 的工作原理
Nginx 是一个高性能的HTTP和反向代理 Web 服务器,处理高并发能力十分强大,能经受高负载的考验。首先我们理解 Web 服务器是互联网基础设施的核心组件,负责通过 HTTP/HTTPS 协议接收、处理和响应客户端(如浏览器)的请求,向用户提供网页、图像、视频等资源。
2025-07-27 19:13:47
911
原创 MySQL详解四
MySQL 连接池所指的就是在服务端创建多个与数据库的连接,其实也就是多线程的方式,这样就可以并发的去访问数据库,他使用的是 select 和阻塞 IO 的方式进行操作的,这是一种不会阻塞工作线程的一种方式,主线程负责接收将客户端连接,然后调用 select 函数为其分配一个 fd,为其分配一个线程,fd 会被监听,主线程此时返回去干其他的事情,只有当 fd 就绪以后,就会触发回调函数通知客户端,进行数据的读取操作,极大提高了 MySQL 的处理效率。
2025-07-23 00:53:07
966
原创 MySQL详解三
操作如果没有进程加锁或者是他不是一个原子变量,就会出现线程安全的问题,最终就会导致数据的错乱,而 MySQL 中的事务也是如此,多条 SQL 语句执行的过程中,如果某一条语句执行错误,就需要回滚到事务最开始的状态,也就是说,我们要么看到的是事务没有被执行的状态,要么就是看到事务已经被执行以后的状态,并不会去看到对应的中间态,这就是事务。事务的回滚操作是通过 undolog 来进行实现的, undolog 是事务的回滚日志,它记录的是事务每步具体操作,当回滚时,回放事务具体操作的逆运算。
2025-07-20 22:39:25
973
1
原创 MySQL详解二
Buffer pool 中使用的是 LRU (最近未被使用)的淘汰策略,通过上图我们可以看出来,在 MySQL 中数据的插入的方式是选择中间的位置进行插入的,原因就在于,我们并不认为最新被插入的数据就是热点数据,所以并不会选择在开头位置进行插入,只有当我们多次对该数据进行访问以后,他就会被挪到前面的位置,而一个数据如果长时间不被访问到,就会被移动到后面的位置,最终通过 LRU 策略把这些数据输入到磁盘当中。索引的价值在于提高海量数据的检索速度,只要执行了正确的创建索引的操作,查询速度就可能提高成百上千倍。
2025-07-19 21:51:48
818
原创 MySQL详解一
首先我们需要找到 ‘谢小二老师’ 的课的 tid 与对应的 course 表形成一张新的表B,表示对应的 cid,形成一张新的表B以后,用新的表B与 course 表A使用联表查询找到没有报这个课程 id 的那一部分然后又形成一张表 C,此时的表 C 代表的就是没有报该门课的 student_id,在与 student 表进行比对,最终返回对应的学号和姓名。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结,要想设计一个结构合理的关系型数据库,必须满足一定的范式。
2025-07-17 22:28:32
707
原创 Redis详解
Redis 是 Remote Dictionary Service 的简称,也是远程字典服务,它是是内存数据库,KV 数据库,数据结构数据库。对于 Redis 来说,他不同于 Mysql , Mysql 是将数据存储在磁盘中,而 Redis 是将数据存储在内存当中的,他们之间的效率是存在很大差异的,他的存储方式是以的方式进行存储的,以 key 的方式去操作 value,同时他又是一种数据结构数据库,在 Redis 的内部实现了5中数据结构,分别是,后续会依次为大家介绍这5种数据结构。
2025-07-15 22:13:57
929
原创 分布式锁的实现
pthread_mutex_lock 就是我们的加锁操作,他就是在用户层比较 lock 这个标记位是不是 0,不如说当前有一个线程需要申请这个锁资源,如果 lock 为0,就证明没有线程占用锁,此时可以申请到这个锁并且将标志位设置为 1,如果是1,证明当前锁资源被占用,调用 FUTEX_WAIT 操作,标志位设置为 2,如果是 2,继续 FUTEX_WAIT ,当前标志位是 2,就证明是存在锁竞争的情况发生的。可用性所指的就是在合理的时间内得到合理的回应,比如当前存在S1,S2,S3…
2025-07-06 12:34:13
851
原创 定时器的设计
所以也就有了定时器的出现,在添加任务到触发任务之间肯定是会存在大量任务的,我们就需要将当前的大量任务组织起来,然后触发最近将要超时的任务,这样,就保证了当前线程并不是一味地在这儿阻塞进行等待,对于将要超时的任务他就会去进行处理。对于我们的定时器来说,是处理定时任务的,他其实本质上也是一个事件,如果时间到了,就去执行,其实跟 IO 多路复用的这种思想是很相似的,我们都是需要去异步处理它,所以在这儿我们会使用 IO 多路复用的最后一个参数。libev,libevent 里面的定时器是基于最小堆实现的。
2025-07-01 23:17:47
907
原创 网络缓冲区
对于用户态来说,从内核的接收缓冲区当中读取到的数据是不确定的,我们不能保证他就是一个完整的包,他可能是半个包,也可能是一个半的包,如果是半个包,我们就需要先将这个数据包保存下来,等到读取到一个完整包数据以后在进行处理,如果是一个半包的数据,就需要优先去处理一个完整包的数据,将剩下半个包的数据暂存下来,基于这种考虑,就需要用到我们的用户态接收缓冲区。函数来说,都是有返回值的,返回值就代表我们实际上拷贝的数量,也就是我当前需要写入到内核缓冲区当中的数量,而参数之一的。
2025-06-28 23:23:04
1305
原创 无锁队列的实现
无锁队列通过原子操作来实现队列的线程安全,是一种非阻塞的队列结构。线程阻塞,会造成上下文切换,也是一种开销;使用不慎,就会存在死锁的风险;性能有瓶颈,高并发的场景下,锁竞争就会加剧,系统的吞吐量就变低了。而使用无锁队列,就可以有效的去降低这些问题发生的概率,这就是无锁队列出现的原因。无锁和无等待的区别在多线程编程中,“lock-free”(无锁)和"wait-free"(无等待)是-两个相关但不完全相同的概念。
2025-06-28 14:41:37
1047
原创 池式结构之内存池
内存池就是一种池式结构,就像我们之前所学习的线程池一样,他会先启动若干数量的线程,当需要进行任务处理时,此时就会唤醒线程池当中的一个线程,进行任务处理,任务处理完毕以后线程继续休眠,等待被唤醒。而内存池也是如此,只不过是预先申请一个一个的内存块,然后当我们需要使用内存时,就从当前内存池当中去进行申请,使用完毕以后,将内存块释放继续保存在内存池当中,等待下一次被使用,当退出时,在销毁我们的内存池。
2025-06-22 12:24:04
790
原创 io_uring的异步IO机制
提交队列的作用就是提交 IO 请求,完成队列的作用就是内核通知完成的 I/O 操作,假设当前有 100 个客户端发起读的请求,在 io_uring 的工作方式中,会将这 100 个 IO 请求先 push 到提交队列当中,然后进行处理,然后处理完成的在 push 到完成队列当中,返回结果,他也是由不同线程去完成的。但是本质上最后还是调用到。两者的差距在 2ms 左右,其实对比下来 io_uring 还是有一个提升的,对于更多的连接的时候,io_uring 的效率还是会优于 epoll 的。
2025-06-12 22:44:19
1249
原创 如何理解协程
正如在 uncontext 中所提到的 resume 和 yeild 一样,resume 其实就是恢复协程的上下文信息,继续调用该协程完成未完成的任务,yeild 就是让出,当前任务在等待,就切换到其他协程处理,保存当前协程的上下文信息,让出的本质其实还是让协程调度器来进行切换,将其他协程的上下文信息加载出来,调度其他协程处理任务。或者是我们经常使用的 epoll 来说,我们一次可以发送大量的请求,并不用等某一事件完成以后在进行下一事件,他的结果最终是在回调中去执行的,看着就像是并行去做的,这就是异步。
2025-06-08 00:48:54
773
原创 DPDK与网络协议栈
DPDK 是是 Intel 提供的数据平面开发工具集,为(IA)处理器架构下用户高效的数据包处理提供函数以及驱动支持,不同于 Linux 下是以通用性为目的,他主要就是为了网络数据包的高效处理,DPDK 应用程序是运行在用户空间上利用自身提供的数据平面库来收发数据包,绕过了 Linux 内核协议栈对数据包处理过程。通过下图我们更好的理解一下这个概念:网卡(NIC):是一块被设计用来允许计算机在计算机网络上进行通讯的计算机硬件。
2025-06-03 23:04:21
825
原创 Posix API
整个网络之间的通信贯穿起来都离不开网络协议栈这个东西,网络协议栈主要负责主要负责网络间数据的通信,自顶向下可分为五层:应用层,传输层,网络层,数据链路层和物理层。客户端与服务端之间的交互,遍布整个网络协议栈,接下来我们来介绍一些相关的接口。
2025-06-02 09:45:41
852
原创 recator与百万并发的实现
在 epoll 中,每一个文件描述符都会对应的一个事件,那么每一个事件理应都有自己的缓冲区,我们需要做到每个文件描述符对应的就绪事件之间是相互不会影响的,同时,因为在 epoll ET工作模式下,只有数据从无到有,从有到多的时候才会通知服务器进行处理,也就意味着对应的事件一次性处理不完,就会出现事件丢失的现象,每个文件描述符拥有自己独立的缓冲区,也会有效的解决掉这个问题。我们从代码的角度来理解其实就是在一个死循环中,一直来识别当前的事件,一旦就绪,就调用对应的回调函数处理即可。
2025-05-31 14:50:14
918
原创 C++线程池实现
我们试想,如果某类任务的处理时间特别长,但是当前线程需要执行的任务也很多,那么就会导致没有执行完当前任务就无法执行其他任务的现象,极大的降低了工作效率,此时,使用线程池就可以解决掉这个问题,我们可以让其他线程来异步执行这个任务,这样也就极大地提高了效率。当需要执行任务时,从线程池中获取一个空闲的线程,将任务分配给该线程执行。而且,大量的线程的创建跟销毁会影响系统的性能与资源利用率的,程池的设计思想是为了避免频繁地创建和销毁线程的开销,以及控制并发执行的线程数量,从而提高系统的性能和资源利用率。
2025-05-21 23:25:07
1052
原创 mmap详解
在32位系统下,一个物理页面所占的大小是 4KB,也就是 4096 字节,如果 mmap 需要将这5000字节的数据映射到虚拟内存当中,就需要映射 8KB 大小,也就是 8192 字节大小,也就是说,在 mmap 函数执行以后,实际上映射到虚拟内存当中大小为 8192 字节大小,对于第5000 ~ 8191字节的数据是以0来进行填充的。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用。),子进程与父进程共享一个。
2025-04-26 21:20:48
943
原创 函数栈帧的创建与销毁
我们在编程的过程中经常会听见函数栈帧这个词汇,那到底什么是函数栈帧呢?接下来就为大家解答一下,我们都知道,一个函数的创建是需要去开辟空间的,而且是在栈区上面开辟的空间(静态函数除外),而这个开辟空间的行为,我们就可以去称之为函数栈帧的创建,当然,他也不仅仅只是单纯的去开辟空间,还伴随着一些其他的行为,后面我们会介绍到。当我们调用完一个函数完毕以后,就会去释放掉申请的空间,这个过程也就称之为函数栈帧的销毁。函数开辟空间是用来干什么呢?
2025-04-04 23:27:21
1117
原创 C++之设计模式
设计模式是前辈们对代码开发经验的总结,是解决特定问题的⼀系列套路它不是语法规定,而是⼀套⽤来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决⽅案。设计模式的六大原则单⼀职责原则(Single Responsibility Principle)(1)类的职责应该单一,一个⽅法只做⼀件事。职责划分清晰明了,每次改动到最小单位的方法或类。(2)使用建议:两个完全不⼀样的功能不应该放⼀个类中,⼀个类中应该是⼀组相关性很高的函数、数据的封装。
2024-12-31 00:22:55
790
原创 C/C++不定参数
在C++中,我们就可以使用template来定义一个可变模版参数,最终通过可变模版参数来解决问题,其实他也是运用的递归的原理,递归的去对每一个参数进行调用,我们在这儿定义一个空的xprintf的作用就在于最后递归调用过去为空时就会发生一些问题,所以我们在这儿就定义一个空的调用,调用到最后打印一个换行符就可以了。当然,上面这一段代码是针对于某个特定的类型来说的,如果我们需要打印的是字符串的话,就需要使用到我们的vasprintf函数。它的作用是初始化一个。类型的变量和可变参数的最后一个固定参数的地址。
2024-12-28 15:16:09
1321
1
原创 自主HTTP服务器实现
HTTP(Hyper Text Transfer Protocol)协议又叫做超文本传输协议,是一个简单的请求-响应协议,HTTP通常运行在TCP之上。CGI(Common Gateway Interface,通用网关接口)是一种重要的互联网技术,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI描述了服务器和请求处理程序之间传输数据的一种标准。
2024-02-28 14:30:51
1013
原创 高并发内存池项目
目录项目简介什么是内存池池化技术内存池内存池主要解决的问题定长内存池的设计高并发内存池的整体框架设计thread cachethread cache的整体设计thread cache哈希桶的对齐规则threadcacheTLS无锁访问central cachecentralcache整体设计central cache 结构设计central cache核心实现page cachepage 整体设计page cache结构设计page cache 中获取一个非空span申请内存过程联调threadcache回
2024-02-05 12:00:21
1138
原创 MySQL视图特性
视图的数据变化会影响到基表,基表的数据变化也会影响到视图。并且在数据库对应的目录下,会增加一个对应的xxx.frm文件,但并没有与之对应的xxx.ibd文件,这也证明了视图和基表使用的是同一份数据。当我们要查询每个员工及其对应的部门名称时,需要使用员工表和部门表进行多表查询,并筛选出员工的部门号等于部门的部门号的记录。下面用员工表和部门表作为测试表,员工表中的ename代表的是员工的姓名,deptno代表的是员工所在部门的部门号。部门表中的dname代表的是部门名,deptno代表的是部门的部门号。
2024-01-03 23:19:44
757
1
原创 MySQL事务管理
其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点;不可重复读的重点是修改和删除:同样的条件,你读取过的数据,再次读取出来发现值不一样了;幻读的重点在于新增:同样的条件,第1次和第2次读出来的记录数不一样;说明: mysql 默认的隔离级别是可重复读,一般情况下不要修改;上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大。隔离级别脏读不可重复读幻读加锁读。
2023-12-31 00:09:53
937
原创 MySQL索引
所谓的操作系统与磁盘IO的基本交互为4KB,其实是指内核缓冲区与磁盘之间是以4 KB进行数据交互的,而MySQL与磁盘之间并不是直接进行交互的,所以MySQL与磁盘之间交付的基本单位是16KB指的是MySQL与内核缓冲区交互的基本单位是16KB,只不过在说的时候更关注的是MySQL和磁盘之间的关系,所以直接说的是MySQL与磁盘交互的基本单位是16KB,相当于忽略了中间的内核缓冲区。它有着更高的IO场景,所以,为了提高基本的IO效率, MySQL 进行IO的基本单位是 16KB。
2023-12-25 23:14:36
221
1
原创 MySQL内外连接
内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。题目要求学生没有成绩也要讲个人信息显示出来,我们就可以使用左外连接,当左边表和右边表没有匹配时,也会显示左边表的数据。对stu表和exam表联合查询,把所有的成绩都显示出来,即使这个成绩没有学生与它对应,也要显示出来。为了方便进行演示,我们创建两张表,一张学生表,一张成绩表并插入数据。右外连接跟左外连接的道理一样,即使这个学生没有成绩也要将他显示出来。
2023-12-23 22:27:34
238
原创 MySQL复合查询
然后将上述查询作为子查询,在查询员工表时在where子句中使用in关键字,判断员工的工作岗位是子查询得到的若干岗位中的一个,如果是则符合筛选条件,由于要求筛选出来的员工不包含10号部门的,因此还需要在where子句中指明筛选条件为部门号不等于10。先查询30号部门员工的工资,在查询时最好对结果进行去重,因为30号部门的某些员工的工资可能是相同的,然后将上述查询作为子查询,在查询员工表时在where子句中使用all关键字,判断员工的工资是否高于子查询得到的所有工资,如果是则符合筛选条件。
2023-12-22 23:53:27
200
原创 MySQL内置函数
rand函数用于生成0.0到1.0的随机浮点数,如果想要生成0到100的随机数,可以用生成的随机浮点数乘以100,然后再以某种取整方式进行取整。有如下成绩表,要求显示exam_result表中的信息,显示格式:“XXX的语文是XXX分,数学XXX分,英语XXX分”。strcmp函数用于逐字符按照ASCII码比较两个字符串的大小,两个字符串大小相等返回0,前者大返回1,后者大返回-1。substring函数用于从字符串的指定位置开始,向后截取指定个数的字符。
2023-12-21 09:41:59
121
原创 MySQL表的约束
真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的。表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofill,primary,key,auto_increment,unique key。
2023-12-18 10:47:57
211
原创 MySQL数据类型
MySQL本身是不支持bool类型的,当把一个数据设置成bool类型时,数据库会自动将其转换成tinyint(1)的数据类型,其实这个就是变相的bool类型,因为tinyint(1)只有1和0两种取值,可以分别对应bool类型的true和false。该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的,可以通过UNSIGNED来说明某个字段是无符号的,接下来我们来看一下无符号类型tinyint测试。
2023-12-15 13:12:39
183
原创 MySQL表的操作
在项目实际开发中,经常修改某个表的结构,比如字段名字,字段大小,字段类型,表的字符集类型,表的存储引擎等等。我们还有需求,添加字段,删除字段等等。这时我们就需要修改表。若不使用可选参数进行指定,则新增列在表的最后。在修改现有表时,要确保新增列与现有列不会产生冲突或重复。我们在user1表中添加一列用来保存用户电话号码。示例:需要将user1修改表名为employee。MySQL 数据库表中添加列,可以使用。示例1:修改name,将其长度改成60;示例:比如我们要删除password列;
2023-12-11 11:18:30
224
原创 MySQL库的操作
表恢复之前需要先选中一个数据库,表明需要将表恢复到哪一个数据库中,为了防止恢复出来的表与该数据库中已有的表的表名重复,一般在恢复表时会选择创建一个空的数据库,然后在该数据库中进行表的恢复。使用不同的校验规则操作数据库中的数据可能会得到不同的结果,比如utf8_general_ci校验规则在比对数据时是不区分大小写的,而utf8_bin校验规则在对比数据时则是区分大小写的。在对数据库当中的数据进行增删查改时,不可避免的需要进行数据的比对,因为在对数据做增删查改之前,都需要先通过比对的方式找到目标数据。
2023-12-11 09:27:03
517
1
原创 MySQL数据库基础
数据库是按照数据结构来组织、存储和管理数据的仓库,是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。存储数据用文件就可以了,为什么还要弄个数据库?文件的安全性问题:数据误操作以后无法进行回滚。回滚(Rollback)指的是程序或数据处理错误,将程序或数据恢复到上一次正确状态的行为;文件不利于数据查询和管理:没有将存储的数据以某种数据结构组织起来;文件不利于存储海量数据:数据的控制需要由用户自己来完成;文件在程序中控制不方便:数据量越大用户的操控成本就越高。
2023-12-10 10:38:41
143
原创 Epoll服务器(ET工作模式)
如果我们传输的单纯是一个字符串,直接发送到网络中就可以了,但是如果是一些结构化的数据,比如实现一个计算器,他会存在左操作数,右操作数,操作符等,如果一个一个进行发送,就需要一个一个进行接收,此时服务端还需要纠结这些数据如何组合,所以我们可以将这些结构化数据打包。未来我们除了要添加_listensock以外,还需要需要添加大量的sock,所以我们的AddConnection函数就需要就需要将读回调,写回调,异常回调全部考虑在内,在进行_listensock添加时将写回调,异常回调设置为空即可;
2023-12-09 15:09:08
227
原创 I/O多路转接之select/poll/epoll
虽然当前的select服务器是一个单进程的服务器,但它却可以同时为多个客户端提供服务,根本原因就是因为select函数调用后会告知select服务器是哪个客户端对应的连接事件就绪了,此时select服务器就可以读取对应客户端发来的数据,读取完后又会调用select函数等待某个客户端连接的读事件就绪。此时如果select监视的文件描述符上有事件就绪,那么select函数的返回值就是大于0的,如果select监视的文件描述符上没有事件就绪,那么select的返回值就是等于0的。
2023-12-01 10:56:33
234
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人