- 博客(20)
- 资源 (1)
- 收藏
- 关注
原创 怎样从InnoDB表中导出大量冷数据
所以,如果我们要导出的数据量很大,还要用传统方案,0-100,100-200,200-300这样翻页,那么,就会导致大量的重复读取。我本人曾经在实际业务中遇到过一个这样的场景:导出上百万的数据,都是冷数据,数据库磁盘I/O飙升,buffer pool缓存使用率下降,最终导致正常业务收到影响。如,记录/流水类数据,随着时间的推移,数据量会越来越大。比如,导出几十万,甚至上百万数据,然后还要再从主表查询出数据之后,再调用其它接口查询数据,再进行聚合,再写入到表格中,这个过程,一定是耗时的。
2023-12-23 09:25:33
961
1
原创 Go语言中的make和new
可以看到,使用make创建map和chan时,分别调用了runtime.makemap和runtime.makechan,这两个函数的返回值都是指针,所以make出来的map和chan的大小都是8字节。可以看到,slice的大小是24字节,这个很好理解,因为slice的实现中,有指针指向底层数组,所以slice的大小是指针的大小(8字节)+ len(8字节)+ cap(8字节)。而当传递map时,是把hmap结构体的指针赋给了形参,所以在函数内部修改map,会影响到原来的map。
2023-12-18 07:34:28
248
原创 谈谈事务id的分配时机
那么,事务id是什么时候被分配的呢?其实是在执行第一条语句的时候分配的,准确的说,是执行第一条写语句或锁定读语(SELECT ... FOR UPDATE)句时执行的。其实,事务id是一个递增值,在time1的时候,分配的是一个虚拟的事务id,真正。在InnoDB存储引擎中,事务id是用来标识事务的唯一数字标识,每个事务都有一个唯一的事务id。我们可以看到,在执行begin语句的时候,查询结果为空,这个时候并没有真正开启事务。的事务id是在time3的时候分配的。
2023-12-18 07:33:29
494
原创 索引合并导致锁超时
虽然索引合并在某些情况下可以提高查询效率,但是在实际使用中,也会带来一些问题,比如死锁、锁等待超时等。当update语句使用到索引合并时,有可能会导致锁超时,甚至死锁。where条件涉及到的字段都放到一个联合索引中,这样可以避免索引合并带来的问题。索引合并指将多个索引的扫描结果合并起来,作为最终的扫描结果。可以看到其同时使用了index_a,index_b两个索引。我们可以看到,事务2(3931)在等待index_b上的锁。从表面上看,这两个事务并没有冲突,但实际上会发生阻塞。表结构及数据:如上。
2023-12-18 07:32:54
82
原创 使用RediSearch进行搜索
和Eleasticsearch、Solr等搜索引擎相比,RediSearch的功能还是比较简单的,它并不是要替代这些专业的搜索引擎,并不适用于所有场景。RediSearch使用了压缩算法和倒序索引算法,使得其在性能和内存占用上都有很好的表现。由于redis的数据都存储在内存中,如果索引数据内容过大,可能不适合使用RediSearch。在上面的代码中,我们创建了一个名为tangshi的索引,然后添加了5个文档。redissearch-go是一个支持RediSearch的go语言客户端,使用起来很简单。
2023-12-18 07:32:18
336
原创 CRLF的缺失导致smtp方式发送邮件失败
实际上,很多语言的库都会自动添加(CR-LF),比如go和python。客户端在发送的时候,没有将CR-LF追加到消息末尾,导致发送失败。BDAT: ESMTP协议中的一个命令,用于发送邮件内容,可以指定数据块的大小。这里面说,是由于没有将CR-LF追加到消息末尾,并且提示到了RFC2822。按照参考资料,准确的说是每一行都应该添加(CR-LF),而不仅是消息末尾。使用搜索引擎搜索这个错误,看到了一篇微软官方的文章,见。DATA:SMTP协议中的一个命令,用于发送邮件内容。CR-LF:回车换行,即。
2023-12-17 13:53:33
346
原创 sqlx使用入门
它能极大的方便我们对数据库的操作,提高开发效率,同时又没有GORM那么臃肿,学习成本也不高。对于我这种原生sql派来说,再好不过了。sqlx是一款go语言的数据库操作库,它是对go语言自带的database/sql的扩展,提供了更多的功能,使用起来更加方便。此处,我们引入如testify包以方便测试。这里如果使用Goland新建项目,会自动初始化,不需要手动执行。新建user.go,定义user结构体及相关操作。注:此文原载于本人个人网站,新建db.go,初始化连接。
2023-12-17 13:51:48
237
原创 SingleFlight导致慢请求的经历
防止缓存击穿,而是直接在调用接口时使用时,会导致慢请求增多,扩大请求的长尾效应,还不如直接调用接口。这个方法的核心,是WaitGroup,这个WaitGroup只有一个任务,有n个waiter。同一时刻,key相同时,如果有正在执行的调用,那么新的调用/请求都会等待。经过和提供接口B的同事核对,以及增加详细日志,发现原因是我在调用接口时使用了singleflight,导致一个慢请求变。通过查看日志(因为当时还没有引入调用链),判断是调用一个内部接口B时慢了,但是请求A接口。注:此文原载于本人个人网站,
2023-12-17 13:46:53
63
原创 update语句未使用索引的后果
update语句如果没有使用到索引,会进行全表扫描,会对表中/聚簇索引的每一行记录进行加锁,这会耗费较长时间。如果是用RR级别,即使被读取的记录不满足where条件,对应的记录锁也会不会释放,直到事务结束。今天来简单分析一下。所以,对于update语句,一定要尽量使用索引,而且要保证索引区分度较高,最好是保证where条件中的每一列都在索引中。MDL锁分为读锁和写锁,读锁之间不互斥,读锁与写锁之间互斥,写锁与写锁之间互斥。如果是用RC级别,如果被读取的记录不满足where条件,对应的记录锁会被立即释放。
2023-12-17 13:42:38
1411
原创 Web即时通讯的几种方式
延迟的程度,要看轮询周期,比如轮询周期是3s,某次轮询之后来了一条新消息,那么客户端只有在下次轮询请求的时候才能拉到这条消息,延迟时间就约3s。和短轮询不同的是,在长轮询中,服务端收到请求后,如果没有新消息/新通知,并不立即返回,而是一直等待,直到达到超时时间。短轮询,客户端周期性的向服务端发送请求(比如2s,3s,5s......),服务端收到请求后,不管是否有新消息/新通知,都立即返回。需要注意的是:sse是单工的,在连接维持期间,只能是服务端向客户端推送数据,客户端不能再向服务端发送消息。
2023-12-17 13:37:57
488
原创 asynq源码阅读
这个库实现了任务队列的基本功能,目前star数有7.1k,还不错。个人看法:可以当成一种轻量级的任务队列或者消息队列使用,但是是否在关键业务中使用,慎重。我们可以看到,asynq的server启动了很多goroutine,包括健康检查,任务处理等。我们这里只看普通任务的投递逻辑。我们先从官方提供的Client示例的入口来看一下asynq的任务存储是怎么实现的。将任务的信息存储到hash字典中中,包括任务的消息数据,任务状态,任务的入队时间。判断任务是否已经存在,如果存在,返回0。否则,继续执行下一步。
2023-12-17 13:25:45
711
原创 怎样开发一个grpc拦截器
在上面的代码中,我们启动了一个grpc服务,监听8091端口。在启动grpc服务前,初始化了链路追踪信息,然后在grpc服务中,使用了自定义的拦截器。在开发grpc服务时,我们经常会遇到一些通用的需求,比如:日志、链路追踪、鉴权等。从上面的定义可以看出,一元模式拦截器是一个函数,接收四个参数,返回两个参数。我们只需要实现一个上述类型的函数,在里面实现我们的功能,然后再执行handler函数,就可以实现一个拦截器了。可以看到,我们的链路追踪信息已经上报到了jaeger服务。我们新建一个项目grpcdemo。
2023-12-17 13:19:27
436
原创 B+树的叶子节点到底是双向链表还是单向链表
刚使用mysql的前几年,没有深入地了解mysql的内部实现,关于B+树的叶子节点的了解仅仅是:B+树的叶子节点按照自增id的大小自左至右排序,新增的元素排在右边。innodb的B+树的叶子节点是页(Page),页之间是双向链表,页内部有一个单向链表,这个单向链表是用来存储记录的。后来突然某一天在网上看到一篇文章,说B+树的叶子节点是双向链表,这让我很是疑惑,因为我一直以为B+树的叶子节点是单向链表,这篇文章是不是写错了呢?Innodb的页(Page)是存储数据的最小单位,页的大小默认为16KB。
2023-12-17 13:02:44
2590
原创 Go日志库zap和lumberjack库的使用
有一些日志库使用了基于反射的序列化和字符串格式化,这写都是CPU密集型的操作,会影响日志库的性能,这些都是。我们可以在初始化时,设置记录哪种级别的日志的调用栈信息。日志库在每个项目中都是必不可少的一部分,Go语言中有很多优秀的日志库,比如logrus、zap等,这里我们介绍zap日志库的使用。我们看到,logs目录下多了几个压缩文件(由于我们写入的是相同的字符串,所以压缩文件很小,在实际应用中,不会这么小)。可以看到,info级别的日志没有打印调用栈信息,而error级别的日志记录了调用栈信息。
2023-12-17 12:52:36
592
原创 InnoDB的Buffer Pool简介
线性预读是指在访问某个区的页面超过系统变量的值,就会异步地预读下一个区的页面。全表扫描时,虽然首次加载到 Buffer Pool 中的页放到了 old 区域的头部,但是后续马上就会访问到,每次进行访问时又会把该页放到 young 区域的头部,这样仍然会把那些使用频率高的页面 排挤 下去。当 innodb_buffer_pool_size 的值小于 1GB 时,设置多个实例是无效的,因为 InnoDB 会自动把 innodb_buffer_pool_instances 修改为 1。影响请求的处理速度。
2023-12-17 12:47:06
83
原创 gRPC入门系列之5-添加DB操作
在现实中,如果业务变复杂以后,一般会有专门的服务来处理用户信息,这个时候,用grpc来实现相关服务,是个不错的选择。bcrypt库生成的密码hash值,包含了加盐信息,所以我们不需要额外字段来存储盐(salt)值。在存储密码时,我们不存储明文密码,而是存储密码的hash值,并且进行加盐处理。为了方便,我们就不适用go语言编写客户端代码,而是直接使用evans来测试。这本篇文章里,我们新建一张用户表,实现简单的用户操作功能。命令来安装sqlc。后续,我们将继续完善grpc服务,添加更多功能。
2023-12-17 12:30:06
765
原创 gRPC入门系列之4-consul服务注册与发现
在生产环境中,除非是直直接在固定ip的物理机/虚拟机上运行,否则ip地址是不固定的,而且服务的数量也是不固定的,这时候就需要服务注册与发现了。需要说明的是:在现实中,consul服务的地址可能是通过配置文件,或者配置中心获取的,不会写死在代码中。在微服务架构中,服务的注册与发现是一个非常重要的组件,它可以让服务之间的调用更加简单,也可以让服务更加健壮。在上面的代码中,我们通过consul客户端获取服务列表,然后随机选择一个服务节点,调用服务。根据服务列表返回的节点,随机选择一个节点,调用服务。
2023-12-17 11:55:38
897
原创 gRPC入门系列之3-stream模式
而在后面的输出中,调用的是 Average 方法,客户端输入了 5 个数字:[1 2 3 4 5],服务端返回的是已经输入的数字的平均值。在上面的代码中,我们从 stream 中读取数据,如果 err 为 io.EOF,则结束循环,否则将读取到的数据累加到 sum 变量中。如你所见,我们启动了一个 grpc 服务,使用的端口是 5633,并且进行了反射注册(这只是为了后面的测试,不是必须的)。在上面的测试中,我们分别输入了三个参数 5、2、3,服务端返回了三次,每次返回的都是已经输入的数字的平均值。
2023-12-17 11:36:13
1261
原创 gRPC入门系列之2-evans工具的使用
evans(https://github.com/ktr0731/evans)是一款用于调试gRPC接口的工具,利用它可以不用编写客户端代码就可以测试gRPC服务,非常方便开发调试。本文介绍了evans的简单使用,想了解详情,可以到访问仓库地址:https://github.com/ktr0731/evans。除了evans,也有其它工具可以用来测试grpc接口,比如GoLand自带的grpc工具,以及postman。这里介绍一下evans的两种使用方法:基于proto文件的测试和基于反射的测试。
2023-12-17 10:54:55
576
原创 grpc入门系列之1-Unary模式
Unary模式,也可以称为“一问一答模式”,客户端发送一个请求给服务端,服务端返回一个响应,和一次普通的函数调用类似。在项目目录下执行make tidy,拉取相关库,然后执行 make greet-build,生成可执行文件。其中最常见的是Unary模式(即一元模式),我们在本章节仅介绍Unary模式。下面我们来实现一个简单的Unary接口。Greet.go,Greet方法实现。执行成功,在pb目录下生成相关文件。接口定义(.proto文件)。main.go,服务入口文件。
2023-12-17 10:50:12
528
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人