自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(125)
  • 收藏
  • 关注

原创 8.达人探店、好友关注、附近商铺搜索、用户签到、UV统计

1、达人探店1.发布探店笔记2.查看博客3.点赞笔记关于点赞的分析实现步骤4.点赞排行榜分析使用Redis的哪种数据类型使用sortedSet修改之前的代码2、好友关注1.关注和取关2.查看他人主页查看用户主页博客分页查询3.共同关注4.关注推送推送到粉丝收件箱实现分页查询收邮箱3、附近商铺搜索1.GEO数据结构 2.数据预热,将店铺数据按照 typeId 批量存入Redis。3.查找附近商户4、用户签到1.BitMap2.签到功能 3.签到统计5、UV统计1.两个概念2.Hyperloglog项目地址

2024-10-30 11:28:32 829

原创 7.使用Redis进行秒杀优化

上面的都是我们为了解决程序可用所做的。现在程序执行不会出现超卖问题的。但是其性能可能不太好。– 判断秒杀库存是否足够 –加分布式锁 –在这7步操作中,加粗黑体字的操作是要去操作数据库的,而且还是一个线程串行执行, 这样就会导致我们的程序执行的很慢,所以我们需要我们可以将一部分的工作交给Redis,而是通过开启一个独立的子线程去异步执行数据库的一些操作,从而大大提高效率。

2024-10-28 18:03:43 1297

原创 go-zero 的使用

本文章讲解使用go-zero生成一个微服务的过程。其中的一些命令或者名不太熟悉的话,可以参考go-zero官网。项目名字叫zero。创建zero目录,并在该目录下创建user目录。

2024-10-28 17:01:25 1066

原创 6.一人一单超卖问题和分布式锁

很多时候有些商家要拿出一部分好用且贵重的产品来做促销引流,而将该物品进行低价售出或者出售一些折扣力度很大的优惠卷,此时为了防止有人恶意低买高卖以及保证引流的效果,我们。一人一单超卖问题可以分成两种,单机的和集群下的。

2024-10-25 10:01:12 693

原创 5.全局唯一的订单id和超卖问题

线程1查询库存,发现库存充足,可以创建订单,当同时线程2和线程3也发现库存充足。然后线程1执行完扣减操作后,库存变成了0,但线程2和线程3也同样完成了库存减扣操作,最终就导致库存变成了负数。线程1查询完库存后进行库存扣减操作,线程2在查询库存时,发现库存充足,也准备执行库存扣减操作,但是需要。综上所述,使用CAS法要更加好,能够避免额外的内存开销,而对于我们的需求,需要修改代码的地方也很少的。,结果发现库存数量发生了改变,这就说明数据库中的数据已经发生了修改,需要进行重试或直接失败。

2024-10-23 10:05:18 659

原创 4.缓存穿透、缓存雪崩、缓存击穿的问题

缓存出现问题的原因和解决方案如下:该图来自 极客时间专栏《Redis 核心技术与实战》,再经过一些修改很明显,服务熔断、服务降级、请求限流都是属于"有损"方案,再保证数据库和整体系统稳定的同时,也是会对业务应用带来负面影响的,要是这些方案有好处又无损的话,平常时候怎么不使用呢。使用服务降级,有部分数据的请求就只能返回错误信息,无法正常处理使用服务熔断,那么整个缓存系统的服务都会被暂停,影响的业务范围是更大的。

2024-10-22 09:23:39 612

原创 3.添加缓存和缓存更新策略

我们查询商店的时候,通过接口查询到的数据有很多,我们希望在此。对于店铺的详细数据,这种数据变化比较大,店家可能会随时修改店铺的相关信息(比如宣传语,店铺名等),所以对于这类变动较为频繁的数据,我们是直接存入Redis中,并且设置合适的有效期。在internal目录添加shopservice文件夹,添加shopservice.go文件。软件首页的这块列表信息是不变动的,因此我们可以将它存入缓存中,避免每次访问时都去查询数据库那么这里一个key就会有多个元素,那我们可以使用Redis的list类型来存储。

2024-10-21 10:26:17 1322

原创 2.登录业务

登录有两种方式,一种是通过手机号码发送验证码登录,另一种是通过账号密码进行登录。通过验证码登录的话,服务端就要存储该手机号码的验证码,这就键值对,还有要给验证码设置过期时间,这个就可以存储在Redis中。在config.yaml添加Redis的内容在config.go文件添加Redis配置的结构体。在db目录创建redis.go文件。使用一个常用的go在main.go中进行创建redis客户端。

2024-10-18 16:12:51 1150

原创 1.项目初始化

创建的sql语句保存在dianping.sql文件中。其中已经添加了一些用户信息和商户的信息。

2024-10-17 17:52:59 915

原创 Go语言实现黑马点评项目

⿊马点评是⼀个⼤量使⽤Redis的项⽬,其功能类似⼤众点评。该项目原是用Java写的,这里我使用Go语言按照自己的思考来改写。可以使用命令行curl或者postman软件或者Go语言编写http客户端来测试。使用Go语言实现黑马点评项目,这里是只实现了后端,本人能力有限,没有实现前端。

2024-10-17 17:52:13 404

原创 Redis主从、哨兵、cluster集群的部署和细节

哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过 sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis 主节点通知给client端(这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)当节点删除或者发生宕机时,节点上保存的数据也就丢失,但如果数据绑定的是插槽,那么当出现该情况时候,就可以将故障接的插槽转移到存活节点上。

2024-05-23 10:41:33 1084

原创 Redis如何避免数据丢失?——RDB

写时复制的核心思想是 若有多个调用者同时请求相同资源,他们会共同获取相同的指针指向相同的资源,直到某个调用者视图修改资源的内容是,系统才会真正复制一个专用副本给该调用者,而其他调用者所见的最初的资源仍然保持不变,而该过程对其他的调用折是透明的,不被感知的。此作法主要的优点是如果调用者没有修改该资源,就不会有副本(private copy)被建立,因此多个调用者只是读取操作时可以共享同一份资源。

2024-05-10 15:00:12 1292

原创 Redis如何避免数据丢失?——AOF

Redis是把数据储存在内存的键值数据库,而服务器一旦宕机,那内存中的数据将全部丢失。像MySQL那样,是有宕机后数据恢复机制的。那Redis也是有的,其有两种方式:AOF和RDB。该章节讲解AOF。MySQL是使用redo log(重做日志)来进行宕机恢复的。其是使用了写前日志(Write Ahead Log,WAL),即是在实际写数据前,先把修改的数据写到日志文件中,方便出故障时候进行恢复。而AOF正好相反,是。这是个文本日志,不是二进制文件。

2024-05-08 11:10:14 1107

原创 Redis的事务机制能保证ACID属性吗?

Redis使用 multi、exec、discard、watch 四个命令来支持事务机制。multi:开启一个事务exec:提交事务,从命令队列中取出提交的操作命令,进行实际执行discard: 放弃一个事务,清空命令队列watch:检测一个或多个键的值在事务执行过程中是否发生变化,若发生变化,当前事务就放弃执行Redis的事务机制可以保证一致性和隔离性和一定程度的原子性(不提供回滚),无法保证持久性。

2024-04-30 17:17:43 1310 1

原创 如何保证Redis双写一致性?

1.场景一:并发读写情况下产生的短暂不一致场景,业务场景要能接受。并发读写情况下,缓存正好失效且读操作耗时大于写操作而产生的数据不一致。可以通过延时删除,或者给redis设置较短的存活时间。

2024-04-29 14:27:26 1483

原创 Redis网络部分相关的结构体2 和 绑定回调函数细节

创建连接时候,需要设置客户端的读回调。createClient--->connSetReadHandler--->(conn->type->set_read_handler)--->(connSocketReadHandler,其内部把读回调函数readQueryFromClient赋值给read_handler)--->(aeCreateFileEvent,把conn->type->ae_handler赋值给rfileProc)。

2024-04-25 17:18:45 1100

原创 Redis网络相关的结构体 和 reactor模式

上一章节讲解了Redis的网络交互流程,没有对关于网络部分的结构体有具体的讲解,所以该文章就主要讲解Redis网络部分使用的结构体。

2024-04-25 10:10:48 1087 1

原创 Redis网络模型

我们知道redis 是单线程的,但是严格意义来说,redis 的网络读取命令和解析、发送客户端数据是多线程的。

2024-04-24 10:47:00 1107

原创 Redis是如何淘汰key的 -- 内存策略

Redis之所以性能强,最主要的原因是其是基于的(内存本身就是很快的)。然而。当内存使用达到上限的时候,Redis就无法存储更多数据了。那么,Redis是如何避免达到内存上限的,即是其内存策略是怎样的呢。

2024-04-21 13:19:31 845

原创 Redis对外可见的5种数据结构

所以,hash采用的编码与zset也基本一致的,只需把排序相关的skiplist去掉即可。通过封装, 可以根据对象的类型动态地选择存储结构和可以使用的命令, 实现节省空间和优化查询速度。Redis中会根据存储的数据类型不同,会选择不同的编码方式。根据存储的数据类型的不同,Redis会选择不同的编码方式,共包含11中不同类型。set是Redis中的集合,不保证元素有序的,其元素唯一,查询效率高。,dict和skiplist的优势不明显,而且会更耗内存。zset结构的编码转换是在插入时候进行判断的,在函数。

2024-04-18 10:30:20 985

原创 压缩列表的替代-----listpack

对比ziplist,listpack牺牲了内存使用率,从而避免了连锁更新的情况。而从代码复杂度上看,listpack也相对简单不少,也把增删改统一做出来,从其代码实现上看,是简洁高效的。listpack是在Redis5中就引入的(使用在streams),直到6才作为t_hash的御用底层数据结构。可以看出,极致的内存使用远远比不上Redis的处理性能。而且现在的内存价格是降低的,大容量内存的成本也没这么高。

2024-04-16 14:57:42 2390

原创 跳表skiplist

跳表可以说是平衡树的一种替代品。它也是为了解决的的问题。那这个问题,hash 表解决的很好,插入和查找都是 O(1) 的时间复杂度。但若呢?这个时候 hash 表就不行了,二叉查找树可以解决这个问题。但是由于二叉查找树在按大小顺序进行插入的时候,就会退化为链表。所以又出现了平衡二叉树,而根据算法不同,又分为AVL树、B-Tree、B+Tree、红黑树等。(先不用管这些数据结构的实现,其是复杂的)。而跳表的出现就是为了解决平衡二叉树复杂的问题,它以一种。

2024-04-12 15:25:04 842

原创 快速列表quicklist

和压缩列表一样,entry结构在储存时是一连串的内存块,需要将其每个entry节点的信息读取到管理该信息的结构体中,以便操作。便于在链表的两端进行插入和删除操作,在插入节点上复杂度很低,但是它的内存开销比较大,每个节点除了要保存数据之外,还要。quicklist是个双端链表,节点结构是quicklistNode,节点的zl字段指向压缩列表。​在 Redis 的早期设计中,如果列表类型的对象中元素的长度较小或数量比较少的,就采用。在Redis的quicklist结构中,实现了自己的迭代器,用于遍历节点。

2024-04-11 14:58:42 1209

原创 压缩列表ziplist

ziplist和普通的双向链表不同 ,ziplist不存储指向上一个链表节点和指向下一个链表节点的指针,而是存储上一个节点长度和当前节点长度,通过牺牲部分读写性能,来换取高效的内存空间利用率,节约内存,是一种时间换空间的思想。ziplist使用连续内存地址+偏移量的方式实现链表。适合存储一些int类型的数据或者长度比较短的字符串。压缩列表是 Redis 为节约空间而实现的一系列特殊编码的连续内存块组成的顺序型数据结构, 本质上是字节数组。

2024-04-10 14:13:05 2012

原创 Go语言实现Redis分布式锁2

注意,这里也是使用Lua脚本封装了确认锁与锁续期的操作来用于原子化,以防止误续期了其他持有者的锁。这里仍然存在一个问题:当锁的持有者任务未完成,但是锁的有效期已过,虽然持有者此时仍可以完成任务,并且也不会误删其他持有者的锁,但是此时可能会存在多个执行者同时执行临界区代码,使得数据的一致性难以保证,造成意外的后果,分布式锁就失去了意义。因此,需要一个锁的自动续期机制,分布式锁框架Redission中就有这么一个看门狗,专门为将要到期的锁进行续期。之前的是只尝试获取一次锁,要是获取失败就不再尝试了。

2024-04-08 09:01:43 1166 1

原创 整数集合intset

综上,Intset可以看做是特殊的整数数组Redis会确保lntset中的元素唯一、有序具备类型升级机制,可以节省内存空间底层采用二分查找方式来查询。

2024-04-08 08:54:40 808

原创 哈希字典Dict

在进行 rehash 期间,每次对字典执行 增、删、改、查操作时,程序除了执行指定的操作外,还会将 哈希表 ht[0].table中下标为 rehashidx 位置上的所有的键值对 全部迁移到 ht[1].table 上,完成后 rehashidx 自增。其实没有想象中的那么复杂,随着字典操作的不断执行,哈希表保存的键值对会不断增多(或者减少),为了让哈希表的负载因子维持在一个合理的范围之内,当哈希表保存的键值对数量太多或者太少时,需要对哈希表大小进行扩展或者收缩。,数组的每个元素称为一个哈希桶。

2024-04-07 15:50:41 865

原创 Go语言实现Redis分布式锁

本文将基于go语言,使用了一个常用的go Redis客户端一步一步探索与实现一个简单的Redis分布式锁。SETNX 命令用于在Redis中设置某个不存在的键的值。如果该键不存在,则设置成功,如果该键存在,则设置失败,不作任何动作。基于此可以实现一种简单的抢占机制。先连接redis。新建lock.go文件。创建lock结构体,加锁和解锁方法。

2024-04-04 16:09:43 2373 1

原创 redis链表结构和简单动态字符串(SDS)

这些看宏名字就很容易知道其功能的。//sds.h关于sdshdr##T,不太懂,在这里理解成它将sdshdr和T连接在一起,即表示不同的 sdshdr 类型。关于, 参数 s 是sdshdr 结构体中的字符串指针,即等价于 buf,参数 T 则是表示不同类型的 sdshdr,取值可以为 8/16/32/64。然后看其实现,是宏定义的一个变量,void*是将结果转换为void*类型,以便sh接收。而 (s) - ( sizeof(struct sdshdr##T) )则表示指向结构体变量的地址。

2024-04-02 09:14:11 785

原创 MySQL使用自增id无法插入id为0值的记录?

的时候,数据库会自动产生一个新的自增序列作为这条记录的ID。这就是我们插入0值ID记录时与期望不符原因。id是自增的,插入id=0的行数据,查看却显示id=10,这说明。因为在数据库表中ID采用了自增ID策略。这里就是记录下这种情况,该文章参考来自。这个情况有官方解释以及解决方案。

2024-03-21 14:27:17 612

原创 MySQL日志的一些疑惑解答

这时并不会回滚事务,虽然redo log是处于prepare阶段,但是能通过redolog的数据找到对应的binlog日志,这就是对应q情况2(a),MySQL认为对应的事务binlog是完整的,就会提交事务恢复数据。这个其实是不一定的。写了redolog后,会更新内存中的数据,要是这时进行查询,而数据还在内存中,就直接访问内存即可,不需要去读取磁盘,也不需要把redo log里的数据更新到数据磁盘中。在奔溃恢复时候,会对比磁盘数据页的LSN和checkpoint的LSN,要是其是相等的,就会跳过该页。

2024-03-20 10:44:30 990

原创 MySQL的日志:undo log、redo log、binlog有什么作用

在一个事务中执行下面语句。之后可能会对其有些疑惑:1.假如我想后撤,退回到update之前,而innodb是支持事务回滚的,即是可以有后悔药吃的,那是如何实现的呢?2.MySQL的行数据是存储在数据页中的(默认大小是16k)。该update语句需要操作的数据可能分布在多个数据页中,这样就需要对磁盘进行多处读写(即是随机读写),这样 IO 成本、查找成本都很高(随机读写比顺序读写慢很多)。而MySQL的速度却是比较快的,这和我们分析的不一致,这内部是使用了什么办法解决的呢?

2024-03-19 14:58:15 1292

原创 MySQL的事务隔离是如何实现的?

事务是在 MySQL 引擎层实现的,默认的 InnoDB 引擎支持事务。MySQL InnoDB 引擎的默认隔离级别是可重复读(RR),但不建议将隔离级别升级为串行化,因为这会导致数据库并发时性能很差。针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。针对当前读。

2024-03-13 15:41:53 1270

原创 MySQL的锁

锁是计算机协调多个进程或线程并发访问某一资源的机制。在 MySQL 里,根据加锁的范围,可以分为三类。

2024-03-12 11:20:28 951

原创 MySQL的加锁规则

加锁的规则:一个原则:加锁的基本单位是 next-key lock。加锁是对索引加锁的。一个bug:非唯一索引范围查询,该索引的临键锁不会有退化为间隙锁或记录锁。其他就通过常理来分析推理即可。唯一索引等值查询唯一索引范围查询非唯一索引等值查询非唯一索引范围查询非索引查询。

2024-03-11 16:53:49 1405

原创 Go实现日志2——支持结构化和hook

重点就是在e.fromat()和e.write()中。而在e.fromat()中按照规定的格式化数据后,把信息存在e.Buffer中,然后经由e.write()写入。其中日志记录的事件以结构化格式(键值对,或通常是 JSON)表示,随后可以通过编程方式对其进行解析,便于对日志进行监控、警报、审计等其他形式的分析。就不单单是输出msg=...。新的Format方法也好理解,主要是增添了调用appendKeyValue方法,该方法是进行键值对书写的。而JSON类型的是已经结构化,重点来看看TEXT文本格式的。

2024-03-05 16:54:19 916 2

原创 MySQL中有事务无法回滚的语句?

前面的修改表结构就是DDL语句。备注:若不了解DDL,可以查看该文章MySQL的SQL语句所有的 DDL 语句都会导致事务隐式提交。即是当你在执行 DDL 语句前,事务就已经提交了。这就意味着带有 DDL 语句的事务将来没有办法 rollback。看例子:在第5步查看结果的时候,发现表和插入的数据都有了,说明回滚没有生效。原因是在第3步,执行DDL语句之前事务就被隐式提交。DDL语句会进行隐式提交,是不能rollback的,所以大家在日常开发中一定要注意。

2024-03-04 18:08:06 907

原创 MySQL的一行数据是如何存储的?

1大多数人使用mysqly一般都是使用 InnoDB 引擎,这也是默认的表引擎。我们这里讨论的也是默认引擎InnoDB。InnoDB引擎表是数据是存储在磁盘的。那可能会好奇表的每一行是如何存储在磁盘中的呢?行结构是如何的呢?行格式(row_format),就是一条记录的存储结构。InnoDB 提供了 4 种行格式,分别是 Redundant、Compact、Dynamic和 Compressed 行格式。MySQL5.7 版本之后,默认使用 Dynamic 行格式。

2024-03-03 14:13:32 1143

原创 Go实现日志

那接着来看日志选项,一个日志中会有很多选项,比如输出地方,输出格式,日志等级,是否输出行号等等。在输出中,也要输出日志等级,那肯定不是输出数字的,那是要输出例如"DEBUG"这种的,所以用map来映射。提供了initOptions函数来初始化日志选项,参数是传入函数。这里还没有实现logger结构体,所以还没有到使用设置的地方,讲到logger结构体的时候会再讲解。在日志输出时候,是会判别该日志等级是否符合设定的等级,就需要比较,所以日志类型就用数值类型就好。那首先是会有日志等级,一共6个等级。

2024-03-02 18:24:28 1343 1

原创 MySQL的索引和B+tree结构

一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本 500 页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那你可能得找一会儿。同样,对于数据库的表而言,索引其实就是它的“目录”。所以,索引就是提高查询速度的数据结构(有序的)。而能提高查询速度的,说明这些数据是按照一定规则排序好的。索引的优缺点提高数据检索效率,降低数据库的IO成本通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗索引列也是要占用空间的。

2024-02-29 14:18:22 849

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除