自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 网络模型-IO多路复用-select和epoll

能监听的FD最大不超过1024每次select都需要把所有要监听的FD都拷贝到内核空间每次都要遍历所有FD来判断就绪状态poll模式的问题:poll利用链表解决了select中监听FD上限的问题,但依然要遍历所有FD,如果监听较多,性能会下降epoll模式中如何解决这些问题的?基于epoll实例中的红黑树保存要监听的FD,理论上无上限,而且增删改查效率都非常高。

2024-08-08 09:17:59 595

原创 HOT100:153. 寻找旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]]。

2024-08-04 12:25:08 196

原创 ThreadPoolExecutor笔记(一)

这些信息存储在一个原子变量 ctl 中,目的是将线程池状态与线程个数合二为一,这样就可以用一次 cas 原子操作。从数字上比较,TERMINATED > TIDYING > STOP > SHUTDOWN > RUNNING。ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量。希望多个任务排队执行。线程数固定为 1,任务数多于 1 时,会放入无界队列排队。任务执行完毕,这唯一的线程。

2024-07-31 21:51:37 963

原创 自定义线程池(二)

/注意传递参数。

2024-07-31 20:32:45 694

原创 自定义线程池实现(一)

测试没什么问题,但是能发现如果当前工作线程都是busy,并且任务队列也满了,当执行put的时候,就会阻塞在这里,put阻塞—>execute阻塞---->main线程阻塞,当然阻塞也是一种方式那如果不想让它阻塞,比如我添加不进去想让他直接丢弃或者抛出异常应该怎么办,那就需要自定义一套拒绝策略,下一节继续。反之将其添加到任务队列,若是当前任务队列已经满了,可以执行拒绝策略(拒绝策略有很多种,例如死等[会阻塞main线程],放弃任务,抛出异常等等)3.拒绝策略(在下一篇中添加)2.自定义拒绝策略(下一节)

2024-07-31 19:50:43 1097

原创 HOT100:P215数组中第k大元素(堆排复习)

这个过程一直持续到堆的根节点。由于交换后,堆的根节点可能不满足堆性质,因此需要对新的根节点进行调整,使其重新满足堆性质。从最后一个非叶子节点开始,即索引为(n/2) - 1的节点开始,对于每个节点,将其与左右子节点中的较大者(对于最大堆)进行比较。重复上述过程,每次从堆中移除最后一个元素(即当前已排序的最大元素),并调整堆顶元素,直到堆中只剩下一个元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。输入: [3,2,3,1,2,4,5,5,6], k = 4。

2024-07-28 18:29:05 237

原创 HOT100:P394字符串解码

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。给定一个经过编码的字符串,返回它解码后的字符串。

2024-07-28 17:52:17 232

原创 JUC并发编程:基于Condition实现一个阻塞队列

await(): 当前线程进入等待状态,直到被通知(siginal)或中断【和wait方法语义相同】。awaitUninterruptibly(): 当前线程进入等待状态,直到被通知,对中断不敏感。awaitNanos(long timeout): 当前线程进入等待状态直到被通知(siginal),中断或超时。awaitUnitil(Date deadTime): 当前线程进入等待状态直到被通知(siginal),中断或到达某个时间。

2024-07-28 14:57:22 379

原创 JUC并发编程:AQS原理自定义锁

AQS全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁getState - 获取 state 状态setState - 设置 state 状态compareAndSetState - cas 机制设置 state 状态独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源。

2024-07-28 11:59:09 289

原创 库存更改和订单重复提交:幂等性解决方案

幂等性就是相同的操作返回同样的结果,可以理解为数据库层面的幂等性,比如说唯一主键(多次插入直接失败),以及业务层面的幂等性,比如多次点击“提交订单”,不会令用户重复支付,接下来我们将看一下幂等性常见实现方案以及各自的问题。接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用;

2024-07-27 16:18:55 1225

原创 认证中心: 基于OAuth2协议实现三方登录

其中client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET可以使用basic方式加入header中,返回值。

2024-07-26 21:21:45 627

原创 认证中心:基于cookie和session实现单点登陆

当用户退出系统,需要做的是销毁局部会话以及cookie,重定向到认证中心的退出接口,认证中心从会话中获取令牌,销毁全局会话,清除redis中该token的用户信息,调用缓存中系统的退出接口,清除每个客户端的局部会话,接着跳转登录页面。系统2使用该令牌创建与用户的局部会话,返回受保护资源用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话。用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数。不同域名之下(不同父域名)

2024-07-26 21:06:50 533

原创 秒杀业务: 简单梳理

(1)在一人一单优惠券秒杀中,先是解决了因线程安全导致的超卖问题,为了满足一人一单的业务需求需要给查询订单表查询库存表上锁,但是synchronized只能满足单机环境下线程安全,在分布式环境对多个JVM需要使用分布式锁,于是手写分布式锁,但是在极端情况下,例如业务超时,会出现“误删”问题,手写锁无法解决,于是引入redisson,借助看门狗机制可以有效解决这个问题。

2024-07-23 14:05:29 1695

原创 秒杀优化:Jmeter压测数据记录

stream只有在5.0之后才能用,这里贴上5.0版本。(影响因素太多,可能有MySQL缓存什么的,不一定准)平均响应时间100ms,吞吐量是295/sec。服务器内存不够,我直接用的windows版本。平均响应时间5ms,吞吐量311/sec。使用lua脚本+Stream改造之后,可以看到平均响应时间有明显的提高。参数: 1000个用户同时访问。

2024-07-23 11:00:41 742

原创 秒杀优化: 记录一次bug排查

然后在子线程中打了断点,然后再次启动,发现报出了一个空指针异常,定位到了是创建对象createVoucherOrder2当中Long userId = UserHolder.getUser().getId()中user居然是空,token也没失效。代码改造完成,使用Jmeter进行并发测试,发现redis中的数据和预期相同,库存减1,该用户也成功添加了进去,但是打开数据库的订单表,发现这条数据没有添加进去。队列中存在的订单对象中包含了userId,所以正确的做法应该是从订单对象里面取。

2024-07-22 20:49:16 867

原创 手写布隆过滤器:bitMap应用之缓存穿透问题的处理

‌哈希函数的数量越多,‌布隆过滤器中bit位置位的速度越快,‌这有助于提高过滤效率,‌但同时也会增加误报率。缓存穿透是指当缓存系统中无法命中需要的数据时,会直接请求底层存储系统(如数据库),但是如果请求的数据根本不存在,那么大量的请求就会直接穿透缓存层,直接访问底层存储系统,导致底层系统压力过大,甚至崩溃。总的来说,‌选择哈希函数个数和布隆过滤器长度时,‌应考虑到误报率、‌存储空间的消耗、‌过滤效率等多个因素,‌并根据实际应用的需求进行权衡和调整。继续对cloud进行散列hash后,3,4,6位被置为1。

2024-07-22 15:38:25 930

原创 全量数据同步:多线程性能优化

公司在做客服迁移迁移系统,下来的需求就是将公司的用户信息全量同步到那边的数据库,总数据量大概300w+,将无效数据过滤掉以及不需要进行同步的用户(手机号码不存在),剩下大概200w。开始采用的方案就是单线程分页查询,每批100条的数据量,定时任务写好放到测试环境里面跑了一下,预估大概每天能跑50w的数据量(两天反正很难完成任务)。另外就是核心线程数的设置,我在我自己机器上测,核心数是4,我设置线程数10速度是比较快的,和单线程相比较,大概能提升2.5倍,查询大概10分钟(仅仅是查询)。

2024-07-22 10:10:18 659

原创 测试数据生成:MySQL存储过程快速添加300w条数据

需要自己搞测试数据做测试,我测试总共用了不到两个小时,如果快的话,可能一个多小时就搞定了。表名和插入格式根据自己的稍微改动一下。

2024-07-22 09:23:06 252

原创 实际业务场景中大量if..else的优化:ApplicationContextAware的应用

如果操作的表不再改变这样,好像也不是不行,但是如果突然有其他表也需要做数据同步到BI库了,那么代码每次都需要改变,就会有大量的if…而这样的代码也不符合公司开发规范。在公司做一个Canal数据同步的时候,我们需要根据CanalEntry中传过来的表名,获取到相应的实例,然后调用相应的新增,更新删除数据的方法,如果能在spring初始化好Bean之后提前把表名和实例的映射放到map中,然后用到的时候直接get,就避免了大量if…比较直观的是通过if…当前的问题是如何根据表名获取到相应的实例呢?

2024-07-21 18:45:46 503

原创 [收件箱功能]如何使用Zset实现滚动分页?

假设在t1 时刻,我们去读取第一页,此时page = 1 ,size = 5 ,那么我们拿到的就是10~6 这几条记录,假设现在t2时候又发布了一条记录,此时t3 时刻,我们来读取第二页,读取第二页传入的参数是page=2 ,size=5 ,那么此时读取到的第二页实际上是从6 开始,然后是6~2 ,那么我们就读取到了重复的数据,所以feed流的分页,不能采用原始方案来做。2、我们需要找到与上一次查询相同的查询个数作为偏移量,下次查询时,跳过这些查询过的数据,拿到我们需要的数据。

2024-07-21 08:28:49 505

原创 [用户签到]如何使用BitMap实现签到功能?

我们只需要让得到的10进制数字和1做与运算就可以了,因为1只有遇见1 才是1,其他数字都是0 ,我们把签到结果和1进行与操作,每与一次,就把签到结果向右移动一位,依次内推,我们就能完成逐个遍历的效果了。假设今天是10号,那么我们就可以从当前月的第一天开始,获得到当前这一天的位数,是10号,那么就是10位,去拿这段时间的数据,就能拿到所有的数据了,那么这10天里边签到了多少次呢?用户一次签到,就是一条记录,假如有1000万用户,平均每人每年签到次数为10次,则这张表一年的数据量为 1亿条。

2024-07-20 21:06:16 1465

原创 [点赞排行榜]关于IN字段不按照顺序返回问题

无论因为何种问题,导致我们无法按照有规则的字段进行排序返回结果,只能通过in中顺序来返回的结果,我们只能使用自定义排序,MySQL中ORDER BY的field()函数,可以用来对SQL中查询结果集进行指定顺序排序。子句中指定的顺序不同的顺序返回。

2024-07-20 17:51:12 584

原创 分布式锁-redisson锁重试和WatchDog机制

接下来会有一个条件分支,因为lock方法有重载方法,一个是带参数,一个是不带参数,如果带带参数传入的值是-1,如果传入参数,则leaseTime是他本身,所以如果传入了参数,此时leaseTime!因为锁的失效时间是30s,当10s之后,此时这个timeTask 就触发了,他就去进行续约,把当前这把锁续约成30s,如果操作成功,那么此时就会递归调用自己,再重新设置一个timeTask(),于是再过10s后又再设置一个timerTask,完成不停的续约。TimerTask() {},参数2 ,参数3 )

2024-07-19 20:00:49 673

原创 Redis之五种数据类型

对⼀个内部表示成long型的string执行append, setbit, getrange这些命令,针对的仍然是string的值(即⼗进制表示的字符串),而不是针对内部表⽰的long型进⾏操作。因此,在这些命令的实现中,会把long型先转成字符串再进行相应的操作。String的内部存储结构⼀般是sds(Simple Dynamic String,可以动态扩展内存),但是如果⼀个String类型的value的值是数字,那么Redis内部会把它转成long类型来存储,从⽽减少内存的使用。

2024-07-18 08:26:28 967

原创 Redis数据结构-Dict

类似java的HashTable,底层是数组加链表来解决哈希冲突Dict包含两个哈希表,ht[0]平常用,ht[1]用来rehash当LoadFactor大于5或者LoadFactor大于1并且没有子进程任务时,Dict扩容当LoadFactor小于0.1时,Dict收缩扩容大小为第一个大于等于used + 1的2^n收缩大小为第一个大于等于used 的2^nDict采用渐进式rehash,每次访问Dict时执行一次rehash。

2024-07-18 08:12:11 723

原创 Redis数据结构-ZipList

ZipList中所有存储长度的数值均采用小端字节序,即低位字节在前,高位字节在后。如果前一节点的长度大于等于254字节,则采用5个字节来保存这个长度值,第一个字节为0xfe,后四个字节才是真实长度数据。如果前一节点的长度大于254字节,则采用5个字节来保存这个长度值,第一个字节为0xfe,后四个字节才是真实长度数据。encoding:编码属性,记录content的数据类型(字符串还是整数)以及长度,占用1个、2个或5个字节。previous_entry_length:前一节点的长度,占1个或5个字节。

2024-07-17 21:51:59 595

原创 Redis数据结构-SDS

(1)获取长度的时候需要运算(strlen函数的底层实现通常是通过遍历字符串,直到遇到空字符(null terminator,即 ‘\0’)为止来计算字符串的长度的。时间复杂度是O(n))相较于C中的字符串,(1)可以直接从len字段中直接得到他的长度 (2)可以动态扩容 (3)是二进制安全的,SDS并没有用’\0’作为结束符,而是看的len,即使中间出现了’\0’,也会继续往后找。在redis当中,key都是字符串类型,value要么是字符串要么是字符串的集合,所以字符串类型是redis中最常用的类型。

2024-07-17 19:28:07 434

原创 一条SQL查询语句是如何执行的?

以我们的查询语句为例,因为没索引,就从第一条记录开始遍历,如果发现c=10,就把他存在结果集里面,如果不是10,就接着往下依次判断,直到最后一条记录,最后把结果集返回给客户端。这个值就是在执行器每次调用引擎获取数据行的时候累加的。以上面这条SQL为例,一种方案是先到t1里面查c=10的,然后再去t2里面查,另一种方案是先到t2里面查d=20的再到t1里面查c=10的。Server层包含连接器,分析器,优化器,执行器等,这和数据库使用的是哪种存储引擎没关系,是跨存储引擎的,核心功能都包含在这一层了。

2024-07-10 21:02:50 325

原创 kafka.common.KafkaException: Socket server failed to bind to xx:9092

然后重新启动,检查进程是否存在ps -aux | grep kafka。修改config下的server.properties,添加。部署分布式集群的时候遇到的错误。

2024-07-10 08:50:15 628

原创 主线程结束子线程不再执行

起因是在做分布式锁的时候,我在单元测试里面创建了10个线程,然后启动。每个线程都会在run方法打印内容,但是测试结果居然什么都没输出。就很纳闷,然后推测可能是主线程执行完了子线程直接结束了,果不其然,在加上thread.join()得到了预期结果。thread.join()是当前线程,也就是main线程要等到thread线程执行完成才能继续往后执行。如果是写在main方法是不存在这个问题的,但是单测的确存在这个问题。

2024-07-07 23:43:46 441 3

原创 canal数据增量同步解决方案

待填坑。

2024-06-20 18:58:33 183

原创 git生成密钥(免密)

当系统提示你“Enter a file in which to save the key”,直接按回车键接受默认位置。将生成的密钥放到github/gitee/gitlab,以后git push代码的时候不再需要每次都输入密码了。在提示你输入密码的时候,直接按回车键,生成没有密码的SSH密钥。参数后面跟的是你的邮箱地址,通常用于标识这个密钥。打开Git Bash。

2024-05-29 16:55:53 633

原创 Redis指令汇总(二)

第一行可以看到redis版本信息,后面还有操作系统(我这里用的是windows,所以是os:Windows),进程id,执行程序的位置,配置文件的位置。当 key 存在但没有设置剩余生存时间时,返回 -1。否则,以秒为单位,返回 key 的剩余生存时间。在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1。在本例中,我们移除了key的过期时间,使其永久有效(ttl返回-1代表这个key永久有效)7.randomkey随机返回key空间的一个key。

2024-05-19 10:37:29 189

原创 一条sql语句在mysql中是怎么执行的

连接器主要和身份认证和权限相关的功能相关,就好比一个级别很高的门卫一样。主要负责用户登录数据库,进行用户的身份认证,包括校验账户密码,权限等操作,如果用户账户密码已通过,连接器会到权限表中查询该用户的所有权限,之后在这个连接里的权限逻辑判断都是会依赖此时读取到的权限数据,也就是说,后续只要这个连接不断开,即时管理员修改了该用户的权限,该用户也是不受影响的。

2024-05-17 14:10:29 723

原创 BM11 链表相加(二)

例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。数据范围:0≤𝑛,𝑚≤10000000≤n,m≤1000000,链表任意值 0≤𝑣𝑎𝑙≤90≤val≤9。假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。要求:空间复杂度 𝑂(𝑛)O(n),时间复杂度 𝑂(𝑛)O(n)给定两个这种链表,请生成代表两个整数相加值的结果链表。输入:[9,3,7],[6,3]返回值:{1,0,0,0}输入:[0],[6,3]

2024-05-14 14:53:53 412

原创 BM10 两个链表的第一个公共结点

输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的{6,7}表示的是2个链表的公共部分。输入:{1,2,3},{4,5},{6,7}输入:{1},{2,3},{}

2024-05-14 14:21:39 478

原创 BM8 链表中倒数最后k个结点

过于简单,不再赘述。

2024-05-12 22:59:18 275

原创 BM7 链表中环的入口结点(快慢指针模板题)

输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台会根据第二段是否为空将这两段组装成一个无环或者有环单链表。思路:建立在上一道基础上,如果已知成环,慢指针移动到链表头部,快慢指针以1的步长去移动,直到两者相遇,有环必相遇。数据范围: 𝑛≤10000n≤10000,1<=结点值<=100001<=结点值<=10000。给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。可以看到环的入口结点的结点值为3,所以返回结点值为3的结点。

2024-05-12 22:20:34 354

原创 BM6 判断链表中是否有环(快慢指针模板题)

输入分为两部分,第一部分为链表,第二部分代表是否有环,然后将组成的head头结点传入到函数里面。-1代表无环,其它的数字代表有环,这些参数解释仅仅是为了方便读者自测调试。实际在编程时读入的是链表的头节点。数据范围:链表长度 0≤𝑛≤100000≤n≤10000,链表中任意节点的值满足 ∣𝑣𝑎𝑙∣<=100000∣val∣<=100000。可以看出环的入口结点为从头结点开始的第1个结点(注:头结点为第0个结点),所以输出true。要求:空间复杂度 𝑂(1)O(1),时间复杂度 𝑂(𝑛)O(n)

2024-05-12 21:10:25 184

原创 BM5 合并k个已排序的链表

数据范围:节点总数 0≤𝑛≤50000≤n≤5000,每个节点的val满足 ∣𝑣𝑎𝑙∣<=1000∣val∣<=1000。需要借助BM4写的代码,看我上一篇博客。然后从左向右每两个链表之间一一合并,得到最终结果。合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。要求:时间复杂度 𝑂(𝑛𝑙𝑜𝑔𝑛)O(nlogn)

2024-05-12 20:39:31 207

空空如也

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

TA关注的人

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