Jettcc Club http://1.12.44.120/ 学以致知,然后学以致用 消息队列(一)什么是消息队列? http://1.12.44.120/index.php/archives/16/ 2023-05-06T08:54:00+00:00 什么是消息队列?消息队列是在消息的传输过程中保存消息的容器,简单点理解就是传递消息的队列,具备先进先出的特点,一般用于异步、解耦、流量削锋等问题,实现高性能、高可用、高扩展的架构。一个消息队列可以被一个或多个消费者消费,一般包含以下成员:Producer: 消息生产者,负责产生消息推送到BrokerBroker:消息处理中心,负责消息存储、确认、重试,一般其中会有多个QueueConsumer:消息消费者,负责从Broker中获取消息,并进行相应处理为什么要使用消息队列?MQ的应用场景很多,有应用解耦、异步处理、流量削峰、日志处理、消息通信、消息广播等但核心场景就三个:解耦:将消息写入消息队列,需要消息的时候自己从消息队列中订阅,从而原系统不需要做任何修改。异步:将消息写入消息队列,非必要的业务逻辑以异步方式运行,加快响应速度。削峰:原系统按照数据库能处理的并发量从消息队列中拉取消息,在生产中,短暂的高峰期积压是被允许的。解耦假设有以下场景,用户向订单系统进行请求下单,订单系统中的逻辑调用为在下单成功之后还要调用积分系统、交易系统、短信系统,而其中短信系统调用失败了。但因为整个流程没有解耦,导致整个流程回滚且反馈给用户下单失败。而引入MQ后,整个流程就解耦很多了,用户调用订单系统下单,订单系统在处理完订单相关事宜后发送消息到消息队列,下游系统再根据topic、tag等内容进行消息的消费,积分系统、交易系统、短信系统的成功与否不影响订单系统的流程,订单系统可以直接反馈下单成功的信息。而如果再进一步,订单相关是公司的其中一个业务部门,此时有场景是用户下单后需要推送到大数据等部门做一些统计分析类的工作,如果此时有以下场景1. A部门需要在订单数据的基础上增加用户相关信息数据X 2. B部门需要在订单数据的基础上增加用户历史购物数据Y 3. C部门只需要订单数据的部分数据 4. D部门需要订单数据,但需要进行封装如果不考虑MQ,那么这些操作都是需要修改代码才能实现,几个系统都耦合在一起了。而引入MQ后,不需要在订单系统主动调用其他接口推送数据,只需要把数据推送到MQ中,哪些部门需要数据就自己去拉取就可以了。异步假设现在积分、交易、短信系统都是第三方服务,第三方服务可能会有宕机、执行缓慢的稳定性差的情况。如果没有MQ,当接口故障的时候要自己去编写重试逻辑(不关同步异步),还要考虑如果重试失败了是否要持久化下来在某个时间点通过定时任务重新推送,这一整个逻辑不仅仅影响功能复杂性,还影响性能。如果有MQ,那么只需要把消息推送到MQ中,再从MQ中消费就可以了,如果接口不可用,直接给MQ返回消费失败,下次还可以重新拉取消息进行消费,不需要编写复杂的重试代码。削峰大部分业务中的性能瓶颈都会在数据库,假设数据库可以支撑5k qps,但是在某些场景中(比如双十一、618活动)中qps可能有3w甚至5w、10w,这时候巨大的压力会把数据库打爆。而MQ扛几万的并发几乎没有任何问题,这时候我们就可以引入MQ,请求先写入到MQ中,再从MQ中慢慢消费落库。此时写入MQ的QPS在3w,但消费MQ只有5k,积压的请求可以在后面慢慢消费,这样子可以扛住高于甚至远高于数据库可支撑的请求数量消息队列有什么缺点?引入新技术解决问题的同时会带来新的问题,只不过如果解决新问题比解决旧问题容易,那么引入新技术就是利大于弊的。引入MQ也会带来问题,比如:系统可用性降低:引入的外部依赖越多就越容易挂掉,比如上文提到,ABCD四个系统要采集订单系统的数据,老方法是订单系统完成后调用ABCD四个系统的接口,但是引入了MQ,如果MQ挂了,那ABCD也用不了了。系统复杂度提高:本来架构技术栈很简单,但是引入了MQ,导致一些数据丢失、重复消费的问题,会使系统复杂度大大提高。一致性问题:还是ABCD四个系统采集订单系统数据,订单系统完成后调用ABCD接口,调用B失败就不再调用BCD而直接回滚数据了,结果引入了MQ,订单系统在完成下单后推送消息到MQ就直接返回成功了,但实际上可能只有ABC成功了,D失败了,这时候要通过其他手段来保证数据一致性。消息队列模型点对点模式:多个生产者可以相同一个消息队列发送消息,一个消息只能被一个消费者消费,消费成功后这个消息会被移除,如果消费者处理消息失败了,那这条消息会重新被消费。发布-订阅模式:单个消息可以被多个消费者并发获取、处理。多个生产者可以将多个消息写到同一个topic中,被同一个消费者消费(topic中可以通过tag区分)消息队列的选择市面上常用的消息队列有Kafka、RocketMQ、RabbitMQ、ActiveMQ下面根据特性和数据进行对比特性RocketMQRabbitMQKafkaActiveMQ单机吞吐量10万级,RocketMQ 也是可以支撑高吞吐的 MQ万级10万级别,吞吐量高是kafka最大的优点万级topic数量千级,topic数量达到千级会有性能下降百万级百级千级消息顺序性有序有序分区有序有序消息重复至少一次,最多一次至少一次至少一次,最多一次至少一次时效性ms微秒级,RabbitMQ的一大优点msms可用性非常高,分布式架构高,基于主从架构实现高可用性非常高,分布式架构,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用高,基于主从架构实现高可用性消息可靠性经过参数优化配置,理论上消息可以做到0丢失有较低的概率丢失数据经过参数优化配置,理论上消息可以做到0丢失有较低的概率丢失数据消息回溯支持(按时间回溯)不支持支持(按offset回溯)不支持语言支持支持Java、C++,但C++不成熟支持几乎所有最受欢迎的编程语言:Java,C,C ++,C#,Ruby,Perl,Python,PHP等支持多语言,Java优先支持多语言,Java优先综上:Kafka 和 RocketMQ 都支持 10w 级别的高吞吐量。Kafka 一开始的目的就是用于日志收集和传输,适合有大量数据产生的互联网业务,特别是大数据领域的实时计算、日志采集等场景,用 Kafka 绝对没错,社区活跃度高,业内标准。RocketMQ特别适用于金融互联网领域这类对于可靠性要求很高的场景,比如订单交易等,而且 RocketMQ 是阿里出品的,经历过那么多次淘宝双十一的考验,大品牌,在稳定性值得信赖。但如果阿里不再维护这个技术了,社区有可能突然黄掉的风险。因此如果公司对自己的技术实力有自信,基础架构研发实力较强,推荐用 RocketMQ。RabbitMQ 适用于公司对外提供能力,可能会有很多主题接入的中台业务场景,毕竟它是百万级主题数的。它的时效性是毫秒级的,但实际毫秒级和微秒级在感知上没有什么太大的区别,所以它的这一大优点并不太会作为考量标准。同时,它的功能是比较完善的,开源社区活跃度高,能解决开发中遇到的bug,所以万级别数据量业务场景的小公司可以优先选择功能完善的RabbitMQ。它的缺点就是用 Erlang 语言编写,所以很多开发人员很难去看懂源码并进行二次开发和维护,也就是说对于公司来说可能处于不可控的状态。ActiveMQ现在很少有人用,没怎么经过大规模吞吐量场景的考验,社区不怎么活跃,官方社区现在对 ActiveMQ 5.x 维护也越来越少,所以不推荐使用。 记录一次MySQL死锁的问题与引发的思考 http://1.12.44.120/index.php/archives/13/ 2022-10-16T09:41:07+00:00 作为最为流行的开源数据库软件之一,MySQL有着广泛的应用。由于是比较典型的运营系统后台,12分区devops系统也选择了用它来存储数据。不过,开发过程中却意外地因为一个看似简单的数据库死锁问题卡住了许久,这里把问题和对应的知识点记录下来供以后翻阅,也避免其他人踩坑。背景一个服务有多个二进制,每个二进制有对应的编译信息,判断编译信息不存在时,则插入数据。执行的时候却发现,对一个服务的多个二进制的编译信息进行插入时,发生了死锁。简化问题抛开业务属性,对于表buildingCREATE TABLE `building` ( `appid` int(11) DEFAULT 0, `buildid` int(11) DEFAULT 0, KEY `idx1` (`appid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci执行以下语句时,发生了死锁:begin select * from building where appid = 5 for update; // 判断结果为空,则插入数据 insert into building values (5, 1); commit即,并发执行select for update + insert时导致死锁先解决问题死锁的原因首先,使用的MySQL版本为5.7.18,使用了默认的隔离级别可重复读(Repeatable read)。 假设执行语句前数据库里有如下数据:appid(有索引,起外键作用)Build-id101112022230333执行过程如下transaction1transaction2begin // 1begin // 2select * from building where appid = 5 for up date; // 3, 成功执行select * from building where appid = 6 for up date; // 4, 成功执行insert into building values (5, 444) // 5, 卡住insert into building values (6, 555) // 6, 死锁说明原因:步骤3和4同时持有了gap锁,非互斥,都到了下一步步骤5的插入意向锁与步骤4的gap锁冲突,卡住步骤6的插入意向锁和步骤3的gap锁冲突,卡住,但是数据库发现有环,直接报错死锁ps: 步骤6报错并回滚之后,transaction 1是可以执行的。解决方案:可以修改隔离级别为已提交读(Read Committed),就不会有gap lock的问题【备注:未解决业务问题】可以修改索引类型为唯一索引,然后就不需要先select再insert了,直接insert(可能报错) 或者insert ignore,insert ... on duplicate key update【备注:实际情况复杂一些,不只是appid单列的唯一索引】引发的思考:隔离级别有影响么?表中包含哪些原始数据,有关系么?语句3和4在where条件一样的时候就会互斥么?间隙锁(gap lock)和插入意向锁(intert intention lock)作用到底是什么?最初写这个事务的目的是为了防止同appid的并发插入问题(即上述例子中, 步骤4的 where语句条件为appid=5),能正确执行么?MySQL的知识点隔离级别隔离级别脏读(Dirty Read)不可重复读(NonRepeatable Read)幻读(Phanto)未提交读(Read Uncommitted)可能可能可能已提交读(Read Committed)不可能可能可能可重复读(Repeatable Read)不可能不可能可能可串行化(Serializable)不可能不可能不可能一般来讲,上表中从上到下按照隔离的级别由低到高,越高的隔离,效率越差。脏读 :一个事务读取到另一事务未提交的更新数据不可重复读 : 在同一事务中,多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事务已提交的更新数据。相反, “可重复读”在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据。幻读 : 并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的select操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些select某记录是否存在,不存在,准备插入此记录,但执行insert时发现此记录已存在,无法插入,此时就发生了幻读。不可重复读例子:设置隔离级别为Read Committed。transaction 1transaction 2begin // 1begin // 2select * from building where appid = 5 // 3, 空数据insert into building values (5, 555); // 4, 成功执行select * from building where appid = 5 // 5, 空数据commit // 6, 成功执行select * from building where appid = 5 // 7, 数据非空 幻读例子设置隔离级别为Repeatable Read,将appid改为唯一索引。transaction 1transaction 2begin // 1begin // 2select * from building where appid = 40 // 3, 没有for update 空数据insert into building values (40, 444); // 4 成功执行select * from building where appid = 40 // 5, 空数据commit; // 6. 成功select * from building where appid = 40 // 7, 空数据 insert into building values (40, 444) // 8, 报错Duplic ate entry '40' 锁分类1. 锁类型表锁:对一整张表加锁,一般是DDL(数据定义语言)处理时使用,也可以自己在SQL中指定。由MySQL服务器实现。特点:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;行锁:锁定某一行数据或某几行,或行和行之间的间隙。由存储引擎实现,常见的就是InnoDB。行锁是加在索引上的(MyISAM存储引擎只能使用表锁)。特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。行锁细分(上面的问题主要就集中在这里介绍的锁上)记录锁(Record Lock)锁直接加在索引记录上面,锁住的是key。没有显示索引时,会用数据库隐式创建的一个索 引。如果Where条件中指定的列是非聚簇索引,那么记录锁不仅会加在该索引上,还会加在对应的聚簇索引上。间隙锁(Gap Lock)锁定索引记录间隙,确保索引记录的间隙不变。间隙锁在事务隔离级别为可重复读或以上级别时生效。 MySQL使用间隙锁可以防止其他事务在该范围内插入或修改记录,保证两次读取这个范围内 的记录不会变,从而防止出现幻读现象。 对于上面的例子,执行事务前间隙包括:(-∞,10),(10,20),(20,30),(30,+∞)。执行期间where语句的条件落在了同一个间隙中,因此互相锁住。同时,值得注意的是间隙锁之间并不互斥。Next-Key Lock 即行锁和间隙锁组合起来,是加在某条记录以及这条记录前面间隙上的锁。(疑问:实际操作 发现,where命中记录时,条件前后的间隙都会加锁,而不是只有前面间隙) Next-Key锁同间隙锁一样在事务隔离级别为可重复读或以上级别时生效。Locking reads(select ... for update或lock in share mode),Update和Delete时,除了对唯一 索引的唯一搜索外都会获取gap锁或next-key锁。即锁住其扫描的范围。"唯一索引的唯一搜 索"表示where条件用了唯一索引且搜索到了记录。插入意向锁(Insert Intention Locks)一种特殊的间隙锁,用于Insert的时候。插入意向锁只会和间隙锁或Next-Key锁冲突,和插入意向锁并不冲突。锁兼容矩阵事务A想对数据R获取(row)的锁,但是数据已持有(col)的锁时的兼容性。已持有的锁\想获取的锁RecordGapNext-KeyInsert IntentionRecord0101Gap1110Next-Key0100Insert Intention1111第一列表示已经有的锁,第二列到第五列表示待加的锁。注意此矩阵并不对称。主要是一个事务已经获取了插入意向锁,对其他事务是没有任何影响的。而一个事务想要获取插入意向锁,如果有其他事务已经加了间隙锁或Next-Key锁,则会阻塞.2. 锁模式读锁(S) 又称共享锁,加了读锁的记录,所有的事务都可以读取,但是不能修改,并且可同时有多个事 务对记录加读锁。写锁(X) 又称排他锁,加了写锁的记录,只有拥有该锁的事务可以读取和修改,其他事务都不可以读取 和修改,并且同一时间只能有一个事务加写锁。读意向锁(IS) 为表级锁,当事务试图读某一条记录时,会先在表上加上读意向锁,这样判断表中是否有记录 加锁就很简单了。写意向锁(IX) 为表级锁,当事务试图写某一条记录时,会先在表上加上写意向锁,这样判断表中是否有记录 加锁就很简单了(例如,判断其他事务已表上加IX锁,则本事务无法在表上加X锁)。锁兼容矩阵:已持有的锁\想获取的锁XIXSISX0000IX0101S0011IS01113.相关命令查看全局和会话事务隔离级别select @@global.tx_isolation; select @@session.tx_isolation; select @@tx_isolation;设置当前session的隔离级别set session transaction isolation level repeatable read展示事务的相关信息(包括锁)show engine innodb status // 结果中的TRANSACTIONS部分展示锁相关信息select * from information_schema.innodb_locks;细分问题的解答隔离级别有影响么?答:有,RR隔离级别及以上才有Gap lock, Next-Key lock。表中包含哪些原始数据,有关系么?有,影响Gap lock的范围语句3和4在where条件一样的时候就会互斥么?不是,需要where中使用唯一索引且命中记录gap lock和intert intention lock作用到底是什么?最初写这个事务的目的是为了防止同appid的并发插入问题(即上述例子中, 步骤4的where语句条件为appid=5,能正确执行么?这个问题需要再稍微展开说明一下。其实最初select + insert的本意是为了先查找某条数据(的 索引),确认其不存在,然后插入数据。没意识到查找会影响其他数据(即上面的appid = 5和appid = 6互相影响了)。而用select ... where ... for update的初衷应该是希望对同一个索引有相互阻塞作用,讲人话就是想要在一条不存在的记录上加上互斥的读锁(如果已存在的话,insert不会发生,不会产生额外的数据,也就无所谓了)。那么,这个情况是MySQL能解决的么?很遗憾,答案是不能。可这种情况确实存在怎么办呢?可能有如下的解法:用mutex table。即在另一张有唯一索引,且确保索引对应的记录存在的行上进行select ... for update操作。对上面的例子来说,select * from app where id = 5 for update即可(因为用appid=5查building的时候,id为5的app记录已经存在了)改用唯一索引,并舍弃掉select...for update操作。可以改用insert ignore即可,让MySQL自身保证不会有重复数据。重试。不管是前面例子的问题,还是本问题,其实MySQL发现死锁后,会立即回滚,结果就是有一个事务会成功。失败的事务,重试即可。【备注:并发多的时候,可能会需要重试多次】用GET_LOCK / RELEASE_LOCK。用redis等其他系统来加锁。上面的例子中方法1,2,3应该都可以。值得注意的是,部分情况下2不可行,例如判断如果不存在,则一次插入多条数据的情况。 redis源码阅读(三):数据结构之Dict http://1.12.44.120/index.php/archives/11/ 2022-08-11T10:18:00+00:00 前言如果您能看到我的blog并且感到有帮助, 我倍感荣幸我们知道, Redis是一个键值型(Key-Value Pair)的数据库, 我们可以根据键实现快速的增删改查。而Dict数据结构在其中更是起到了非常非常重要的作用, 我们甚至可以认为, 整个redis其实就是一个巨大的Dict。而键与值的映射关系正是通过Dict来实现的。这次文章内容比较多, 所以我很多内容都在注释里 一定要看注释呀![...] redis源码阅读(二):数据结构之ADList http://1.12.44.120/index.php/archives/7/ 2022-08-04T12:26:00+00:00 前言最近学习了黄建宏大佬的《redis设计与实现》,真心觉得redis非常非常强(建宏大佬也强),但是我觉得书本的阅读始终是入门, 真正要深入redis的思想和原理,还是要去看一看源码。于是我就在redis源码下载地址上下载了redis7.0.4版本的源码;结合网上一些大佬的博客,开始阅读redis。redis源码阅读起来并不是一件简单的事情,并且也想着不是阅读一次就算了,我决定开个blog记录一下阅读的内容。如果您能看到我的blog并且感到有帮助,我倍感荣幸[...] 学院采访 http://1.12.44.120/index.php/archives/4/ 2022-07-30T03:57:00+00:00 学院采访1. 刚刚毕业有什么感觉,在学校与社会的不同体会感觉的话,大一大二的时候,总是抱怨学校管得严,抱怨时间过得太慢。到了大三,就迫不及待的想要离校去实习,找到实习了还很开心脱离了学校。现在大四已经结束了,毕业了。回过头去看,感觉时间过的很快,当初应该好好珍惜一下在校的时间。体会的话,感觉是开始了一段孤独的旅程,生活上要自己去规划吃喝玩乐,计较自己的每一份工资怎么使用。工作上也是,安排的任务只能自己去做,每个人都是拧螺丝,你的螺丝没人能帮你。社交上如果想认识谁谁也没有了社团的牵线,就觉得从一群人变成了一个人吧。2. 简单介绍一下工作从事的内容我现在是在 腾讯WXG事业群 企业微信部门,工作的话因为刚毕业嘛,也没有做什么非常核心的工作,主要就是负责一些企微的优化和解决各个企业(比如 伊利、省政府)提出来的一些问题,目前来讲的话还是非常喜欢这份工作的。3. 面试时候需要注意什么呢首先面试之前一般都会写简历嘛,写简历的时候就要对自己有一个清晰的认识,比如知道面试大概会问ABC三个模块,自己比较熟悉的是AC,那写简历的时候就是AC写细一点,B模块略写就好了。其次就是面试的时候要注意三个点,第一是要用最简短的话输出最多的信息,讲话不要嗯嗯啊啊磕磕绊绊的,面试官可能听半天不知道在说什么,会觉得你抓不住重点。第二是要掌握面试的节奏,具体表现在面试的时候尽量把面试的问题往自己擅长的方向引。第三就是要对自己有充分的自信,在面试之前可以怀疑自己这里不会那里需要学,但是一旦开始面试,就一定要告诉自己,自己就是最牛的,学了这么多,不可能不会。(自信是一个很加分的项)然后也补充一些面试之外的事情,其实我觉得很多同学都是有很好的能力但是却不知道去哪里投简历,导致裁了很多坑。这个问题的话其实很简单的,因为如果真的是一个像样的公司,他们肯定有自己的招聘网站,所以想投简历的话去找招聘网站就好了,比如“腾讯招聘”,“字节跳动招聘”这些,随便百度一搜就有了。4.您觉得大公司比较看重大学生哪方面的素质呢因为我实习是在腾讯游戏,毕业是在腾讯微信,所以我就详细说一说我在腾讯这边的感受吧首先腾讯这边对于一个校招生会比较看重 基础 和 实践。注重基础是因为腾讯这边有一个比较常见的行为:它招进来一个同学,会花很多力气去培养,并希望他们能一直留在腾讯。所以腾讯在面试的时候会有一个类似“潜力值”的评分,而潜力值就体现在这位同学他在大学里学的怎么样,基础扎不扎实,有没有深入了解过计算机的某某某模块。然后实践这块在腾讯来说一般体现为两个方面,一个是动手能力,另一个是思考。其实有些师弟师妹可能已经面试过腾讯,就会发现其实他们很喜欢问:你某某某项目这样做,为什么这样做?你是怎么思考的?这个问题同样的解决方案还有ABC三种,为什么你会选择这种呢?所以对于腾讯来说我个人认为更注重培养价值吧,我们在学校里常说的 大公司看重学历,看重啥啥啥的,我个人的看法是没有,至少我没遇见过。而且,要知道当加入腾讯了会跟一群985甚至是QS前100大学的同事一起工作,这说明了自己和他们能力是一样的,应该感到自豪。5.当初为什么选择这个专业有两个原因,一个是我小时候玩那些单机游戏,有时候打不过嘛,我就去下修改器什么的,然后就很好奇为什么修改器能修改数据呢,就开始了解了计算机的内存啊数据啊什么的,这算是兴趣的开端。第二个原因是我堂哥是学计算机的,我初高中的时候他经常带我玩,我也就听他讲过很多关于计算机的事情,就更让我加深了对计算机的兴趣。所以在高考之后我其实也可以报其他的学校,但是为了追求自己的兴趣最后选择了东莞理工。6. 大学期间有什么好的学习方法来提升自己呢这个能说的有点多啊,尽量长话短说6.1. 首先是我们要去找到自己感兴趣的东西就拿计算机来说,我们知道计算机有开发、研发、运营这些岗位,但是细分下来呢,开发有前端、后端、客户端这些,研发有机器学习、自然语言、计算机视觉这些。在学校也经常听一些学长学姐说过,前端好或者后端好,但我觉得这需要自己去探索,别人觉得好的自己不一定觉得好,所以我们就需要去找到自己喜欢的东西,我第一个建议就是,花一段时间(可以很长)去尝试、了解、实践各种各样的方向,了解可以是google、百度、知乎,找到一个自己最喜欢的方向。6.2. 找到自己方向之后,要有清晰的规划假设最后找到了方向是要走后端,且不想考研,那就可以直接去前面提到的比如腾讯招聘的网站,它是有明确写出需要什么样的同学。那我们就以它的需求广度优先搜索一下,比如它要求:会操作系统,会计算机网络,会数据库,那我们就可以继续去找了,操作系统要学什么,计算机网络要学什么,数据库要学什么,这样自己的规划就越来越清晰了。6.3. 要有耐心,不要着急大学生最多的就是时间,所以在学习的时候不用着急,而且学的东西那么多,着急也学不完,着急反而会让自己陷入漩涡里面,越急越学不会。所以只要慢慢来就好了。但是也不能因为时间多三天打鱼两天晒网,有些东西今天学明天玩,第三天就忘了。6.4. 信息检索能力很重要刚刚有说过,有很多同学明明能力很强但是却不知道去哪投简历。也有很多同学一遇到问题就懵逼,就不知道去哪里找答案。但其实很多问题只要去百度或者Google一搜就有了,这就是信息检索能力的区别,应用到别的场景上,找工作的时候,主动去找一些师兄内推,主动去参加公司的夏令营,这样子都会对自己的职业规划有很大的帮助。6.5. 要注重实践能力计算机属于工科,既然是工科那肯定就非常注重实践能力,所以我认为除了学习纯理论知识比如操作系统计算机网络这种,其他的都应该自己动手敲敲代码。我自己的观点是 学习计算机的道路就是一个不断试错的过程,只有多去实践,多主动才能有提升。当踩得坑多了,以后再遇到这些问题就不会再错了。7.在大学我们会为考研还是找工作烦恼,你当初面对考研和工作是怎么选择的考研这个问题其实还是比较严肃的,考研和工作其实关键在于你想得到什么。举个例子,我们在发掘自己兴趣的时候觉得自己对某某某研发(比如机器学习)很感兴趣,那了解到机器学习是需要考研的之后,决定去考研。或者说,我为了提升学历,提升学历后不管是走计算机这行还是去考公,都是很大的优势。再或者,我是为了建设国家计算机行业,我不仅要考研,还要读博。这三种我都觉得是挺好的,因为就如我刚刚说到的,它们都有很清晰的规划。最害怕的是什么呢,大学没学到什么,害怕工作,逃避社会而去考研,这种情况我甚至不看好考研的成功率。而说到我身上的话其实我当初都没有烦恼过这个事情,因为在大二的时候我就已经跟我舍友一起做好规划了以后要去工作,所以几乎没想过考研的事情。而现在我们都在微信,他就在我隔壁部门,几乎每天吃饭都能看到他,这也算是规划清晰的一个成果吧。8.东莞理工学院建校30周年,有什么话想对母校说呢首先我非常感谢莞工能带给我一个学习的平台,让我认识了很多很有趣的同学,找到了志同道合的朋友。这大学四年我印象更多的可能是每天早上去上课的校道、晚上从图书馆骑车回来吹过的风和始终热热闹闹的宿舍,总觉得还没好好体验大学就已经结束了。莞工带给了我非常难忘的一段时光,而我也希望能为莞工高水平理工大学的建设出一份力,祝愿学校越来越好。还有就是改善一下校园网吧哈哈哈。 redis源码阅读(一):数据结构之SDS http://1.12.44.120/index.php/archives/3/ 2022-07-13T12:46:00+00:00 前言最近学习了黄建宏大佬的《redis设计与实现》,真心觉得redis非常非常强(建宏大佬也强),但是我觉得书本的阅读始终是入门, 真正要深入redis的思想和原理,还是要去看一看源码。于是我就在redis源码下载地址上下载了redis7.0.4版本的源码;结合网上一些大佬的博客,开始阅读redis。redis源码阅读起来并不是一件简单的事情,并且也想着不是阅读一次就算了,我决定开个blog记录一下阅读的内容。如果您能看到我的blog并且感到有帮助,我倍感荣幸[...] 面试经验 | 腾讯WXG | 一二+面委+HR|已拿offer http://1.12.44.120/index.php/archives/6/ 2022-01-18T07:23:00+00:00 背景学历:双非一本,软件工程大四在读项目:一个分布式的商城管理后台,简单的分布式系统一个Spring cloud (nacos + gateway) + security + netty实现的分布式聊天室实习:2021.4 - 2021.8 腾讯IEG更新:add: 1.23 hr面add: 1.24 已oc,准备沟通add: 1.26 已offer,准备上班一面(一个半小时):算法(一个小时):topK,分别写出范围小、范围大、范围超大(说思路)的情况。答: 分别是计数、快选、分治超大数计算,两个长度>100的数字进行加减法, 要考虑负数。答:很简单,处理好进位借位就行基础:(半个小时,时间比较短,感觉因为wxg用的是C++, 而我用的是Java,所以问的不多)堆和栈的区别是什么,哪一个需要程序员控制?Java加锁有几种方式?不同进程中malloc函数返回的值会是相同的吗?(会,因为有虚拟内存)栈和队列在操作系统中有哪些应用场景?(递归和调度)Java的GC,新和老分别是什么算法?为什么?TCP和UDP的区别是什么?应用场景是什么?你觉得微信聊天中哪些功能是UDP哪些是TCP?(聊天tcp、视频udp)反问:工作地点?(广州)能给我一些建议吗?(对于一个知识点要深入挖掘)二面(一个小时):算法(40分钟):剑指offer原题 1-n中出现了几次1答:裂开来,虽然是剑指offer原题但是我没做过,现场推导了一个O(n)的数学法。面试官问有没有更好的方法,我说不会了,再推下去这面试就太久了基础:(20分钟,我觉得时间短的原因同一面)Java里HashMap长度为什么是2的幂次?HashMap如果不给长度,第一次初始化是在什么时候?(put方法里)如果让你设计一个线程池,你会考虑什么东西?为什么要做一个聊天室?NIO的buffer区是双向的吗?你为什么用nacos,为什么不用eureka?为什么用gateway不用zuul?你怎么思考的?反问:没有反问环节,问完最后一个问题面试官说:总体不错,算你通过了。然后就说要去开会了,直接退出了会议。虽然没有反问环节但是我一点不介意是怎么回事?(狗头)---------------------------------------面委分割线---------------------------------------.面完二面大概一个小时,HR小哥哥打电话约面委,直接告诉我接下来会有两场面委,并且一次约了两场的时间很慌,因为之前听说过面委的可怕,从收到面委邮件就开始紧张有朋友问什么是面委?面委全称面试委员会,是微信特有的一个面试轮次。面试官都是超级大佬(最低也是总监),且面试过程都是黑盒,面试者不知道面试官是谁(比如跨部门的大佬),面试官也只能看到你的简历和面试的岗位。面委会对面试者的能力进行再次考核,以便进行定岗定级。一轮面委基础:实习做了什么?遇到过什么难点?是怎么解决的?你遇到问题是更喜欢自己找答案还是去问别人?(先自己找答案,实在不行再去问。这样可以告诉别人我做了什么)为什么用协程不用线程?(因为协程更轻量级)如果你的机器都跑不满,进程和线程和协程又有什么区别?线程一定比协程更好吗?TCP和UDP的区别?http和https的区别?https数字证书交换的过程详细说一下?(这里说的有点乱,但是大佬说问题不大)TCP的accept()函数发生在第几次握手?(大坑我超,直接说是三次握手之后,大佬笑了一下说没坑到我)进程调度有哪些算法?(按照批处理、实时、交互式区分了一下)那在Linux里调度用了什么算法?(都不是,用的完全公平调度程序CFS) 11.1. 哦?介绍一下CFS?Linux里进程通信有几种方式?(我刚说:可以分为消息传递模型和共享内存模型,大佬打断说ok了不错不错)进程同步有几种方式?介绍一下管程?CAS的原理是什么?(TSL指令,最终会在CPU上会执行LOCK CMPXCHG指令)算法:给你一个数组, 把他变成大顶堆/小顶堆反问:以您的角度,我需要补充什么样的知识?(继续保持挖掘深度的热情,看得出你也比较有想法,要明白一切靠自己)二轮面委没有基础面试算法给一个二维数组, arri代表点i -> 点j的距离,从0号点开始出发,遍历每一个点最后回到0号点,每个点只能经过一次,输出最短路径和路径的权值和答:经典问题了,最后用哈密顿图解决,不过感觉dij也能做,有兴趣小伙伴可以研究一下。(但是处理输出处理了很久= =)某城市有两种颜色的出租车:蓝色和绿色(市场占有比例为15∶85)。一辆出租车夜间肇事后逃逸,但还好当时有一位目击证人,这位目击者认定肇事的出租车是蓝色的。但是,他“目击的可信度”如何呢?公安人员在相同环境下对该目击者进行“蓝绿”测试得到:80%的情况下识别正确,20%的情况不正确。请问可以算出在有目击证人情况下肇事车辆是蓝色的概率为多少?答:经典贝叶斯公式,注意识别正确有两种可能,分别是正确识别蓝车和错误识别绿车,最终答案41%rand5()实现rand3()rand5()实现rand7()闲聊环节:家住哪?(广州)平时花在写代码上的时间多吗?(平均每天一道算法题,外加一下午写项目,如果下午没写完晚上还会写,写完了就打游戏)反问环节您对我有什么建议?(我觉得你很不错,不论是数学还是算法都做的很快,继续保持学习,加油)HR面自我介绍实习期间有什么亮点实习的时候为什么没有留下实习最大的收获是什么大一的时候去找老师做项目是自己主动去的吗?为什么大一就想去做项目了?在简历上你提到带了一个团队,能说说是为什么要带这个团队吗?初衷是什么?你觉得自己的优点和缺点是什么?家是住在哪里?有打算过毕业之前来实习吗?手上有其他的offer吗?反问:如果我想去实习,我需要做一些什么准备?1.24更新,已oc,准备沟通1.26更新,offer到了,定好了入职时间,开始踏入社会第一步 为什么MySQL要用B+树? http://1.12.44.120/index.php/archives/8/ 2021-11-05T06:57:00+00:00 为什么MySQL要用B+树?为什么MySQL要用B+树?​ 这是数据库相关面试中非常常见的问题,对于这个问题我听过很多答案,例如:B+树节点存id节约空间、B+树子树之间有指针、B+树只需要较低的层高就能存大量数据...​ 并不是说这些答案不对,但是终究是有点片面。​ 所以今天我们来系统的讨论下,为什么MySQL要用B+树。前言首先要明白的一点是,B+树跟MySQL没有任何直接关系,真正跟B+树有关系的是MySQL的存储引擎,而存储引擎的主要作用是负责数据的存储和提取。MySQL的默认存储引擎是InnoDB,当然也可以使用MyISAM,今天不讨论MyISAM,只说说InnoDB。那么问题来了?为什么MySQL的默认存储引擎InnoDB要使用B+树来作为数据的存储结构呢?​ 相信有阅读过MySQL索引章节的同学们都了解过,表中的索引不论是主键还是辅助索引都会使用B+树进行存储,前者使用的存储方式是<id, row>,后者的方式是<row_index, id>。这也比较容易理解:在主键(聚簇索引)中,id是主键,数据库通过id去查找数据行。在非聚簇索引(辅助索引)中,索引的列(或者说数据行的列)构成了主键,通过索引的列去找到索引的id。(如果有需要,还可以通过id去找当前数据行的全部内容,这也是为什么辅助索引需要再回表的原因)讨论现在疑问来了,InnoDB为什么要用B+树呢?用B树不行吗?用hash表不行吗?ok,我们从两个角度来分析这个问题:InnoDB 需要支持的场景和功能需要在特定查询上拥有较强的性能CPU 将磁盘上的数据加载到内存中需要花费大量的时间这其实就是我们使用数据库最平常不过的两个操作:对数据的持久化与对持久化数据的查询。实时查询数据需要快,而持久化数据需要IO,在这两者同时兼顾的情况下,B+树成为了最好的选择。读写性能​ MySQL作为传统的关系型数据库(OLTP),InnoDB作为传统关系型数据库的存储引擎,通常要用来执行以下操作:通过Insert、Delete、Update对单行数据进行增删改通过 Update 和 Delete 语句对符合条件的数据进行批量的删除;通过 Select 语句和主键查询某条记录的全部列;通过 Select 语句在表中查询符合某些条件的记录并根据某些字段排序;通过 Select 语句查询表中数据的行数select count(*);通过唯一索引保证表中某个字段或者某几个字段的唯一性;如果我们尝试对一条数据进行修改/访问时,SQL执行的时间复杂度时O(logN),而N是树的高度。但是这时候有小伙伴就要问了:啊!你这O(logN),Hash表读可是可以达到O(1)的!B+树8彳亍!虽然对于读取单条数据的场景说,哈希表确实爆杀B+树,但是不要忘了,我们还有范围查询的场景:select * from table where age='22' order by desc; select * from table where age > 18; update table set features = '超级帅' where name = '十七'; delete from table where name = 'hug';​ 我们都知道哈希表的原理是根据字符串进行哈希然后均摊在哈希桶中,而哈希表不论是哈希桶还是哈希值都是无序的。​ 这就意味着,当遇到范围匹配的场景时,哈希表构成的索引就完全没有用处了,只能进行全表查询并且一个一个的去判断是否满足条件。而全表查询对于数据库来说十分的糟糕!==(所有的查询都应该避免全表查询!)==换句话说,在范围查询时,哈希表有跟无, 没有区别。​ 而B+树是能够保证数据按照主键的顺序进行存储,也就是说在B+树中,相邻的数据其实都是按照自然顺序排列的(这里就不讲B+树的原理了)​ 这时候又有小伙伴要问了:啊!不是还有B树吗!B树也可以排列啊!为啥不用B树!(是不是因为作者没有B树!)​ B树和B+树在数据结构上确实是类似的,他们都可以按照顺序对索引中的内容进行遍历,对于排序和范围查询等操作,B树相对于B+树来说会有更好的性能。(当然如果索引建的比较差劲或者SQL写的复杂,也是会全表查询。)小结与 B 树和 B+ 树相比,哈希作为底层的数据结构的表能够以 O(1) 的速度处理单个数据行的增删改查,但是面对范围查询或者排序时就会导致全表扫描的结果。而 B 树和 B+ 树虽然在单数据行的增删查改上需要 O(log n) 的时间,但是它会将索引列相近的数据按顺序存储,所以能够避免全表扫描。数据加载我们来回答小伙伴的问题,哈希表已经被我们排除了,B+树和B树一样都可以相对高效的执行查询,那为什么不选择B树?这时候我们就要来讨论第二个因素——数据加载先来说说读取数据稍微了解操作系统的小伙伴们都知道,计算机在读取文件的时候会按页为单位将数据读到内存中。页的大小在大多数操作系统上都是4KB,可以通过$ getconf PAGE_SIZE 16384/4096 ...来获取,我的电脑一页是16KB,因操作系统不同而不同。在我们执行查询数据时,CPU会发现当前数据在磁盘里而不是内存中,这时候就会触发I/O将数据从磁盘中读入内存中进行访问。而我们都知道数据从磁盘读到内存的成本非常大。就以普通磁盘为例,加载数据需要经过队列、寻道、旋转、传输等过程,总计算大约需要10ms的时间。回到数据库一般我们估算MySQL查询时间时就可以用10ms来衡量随机I/O时间,这里需要特别说一下,这个时间指的是随机I/O的时间,顺序读取磁盘数据是可以达到40MB/s的,两者差距是几个数量级,因此在日常开发中,要注意减少随机I/O的次数,以提高性能。而B树和B+树最大的区别在于,B树可以在非叶子结点中存储数据,但是B+树的所有数据都存在叶子结点中,下面来举个栗子,假设有以下语句:select * from table where id > 3 and id < 9那么,如图所示:如果我们不考虑优化,在上面的B树中执行查询的顺序是:加载根节点,发现根节点第一个元素是5,大于3(第一次随机I/O)通过根节点加载左叶子节点,遍历叶子结点的数据,找到匹配的数据(第二次随机I/O)加载回根节点,发现根节点不包含第二个元素(第三次随机I/O)加载右叶子节点,遍历叶子结点数据,找到匹配的数据(第四次随机IO)由此得出,执行上面的简单的查询语句在B树中我们需要进行4次随机IO才能找到所有满足条件的行,当然我们也可以用各种方式来优化查询,不过,B树能做的优化基本上B+树都可以。但有的优化,B+树可以,B树不彳亍。B+树可以,B树不行的优化由于所有的节点都可能包含目标数据,我们总是要从根节点向下遍历子树查找满足条件的数据行,这个特点带来了大量的随机 I/O,也是 B 树最大的性能问题。但B+ 树中就不存在这个问题了,B+树所有的数据行都存储在叶节点中,而这些叶节点可以通过指针依次按顺序连接,遍历数据时可以直接在多个子节点之间进行跳转,这样能够节省大量的磁盘 I/O 时间,也不需要在不同层级的节点之间对数据进行拼接和排序。通过一个 B+ 树最左侧的叶子节点,我们可以像链表一样遍历整个树中的全部数据,也可以引入双向链表保证倒序遍历时的性能。当然,有的小伙伴可能就会问了:啊!你这个B+树的结构会因为数据量不断增加高度从而增加整体的耗时!然而,根据B+树的原理高度为 3 的 B+ 树就能够存储千万级别的数据,实践中 B+ 树的高度最多也就 4 或者 5,所以不用担心,这不是性能瓶颈。总结如果一个设计不考虑场景,那么所有的设计都是纸上谈兵当我们了解需求场景和使用原理,再对不同的数据结构进行选择就成了理所当然的事情。只能说,B+树不是最好的数据结构,但是对于MySQL来说,B+树就是合适的结构,他能在尽量优秀的情况下解决大多数情况下MySQL会遇到的问题。我们来把文章的内容总结一下,为什么MySQL默认的存储引擎选择B+树而不是哈希表或者B树呢?原因:哈希表有极其优秀的单数据操作性能,但是对于范围查询和排序却无能为力,反而会引起全表扫描。B树能够在非叶节点中存储数据,但是这也导致在查询连续数据时可能会带来更多的随机 I/O,而 B+ 树的所有叶节点可以通过指针相互连接,能够减少顺序遍历时产生的额外随机 I/O。当然,有的小伙伴可能会问了:啊!我就不能两个都用吗!单行数据的时候我用哈希,顺序查询的时候我用B+树!答案是当然可以,但是必须能够容忍更高的复杂度。在同一张表上可以同时建哈希表和B+树构成的存储结构,这样在不同的操作时可以选择更快的数据结构,但是!这会导致更新和删除时在redo log中操作更多份数据,总表的体积也会变得非常非常大从今天的角度来看,B+树可能不是 InnoDB 的最优选择,但是它一定是能够满足当时设计场景的需要。结尾引用自draveness大大的一句话数据库、程序、系统设计思想的发展到今天已经过了几十年的时间,我们不得不说优秀的工程设计确实有足够的生命力。而我们作为工程师,在设计系统、设计算法、设计数据结构时也应该非常清楚地知道不同数据结构、程序架构适合的场景,因为软件工程中没有银弹。ReferenceDraveness Blog: whys the design ? B+ tree · WikipediaWhat is the difference between Mysql InnoDB B+ tree index and hash index? Why does MongoDB use B-tree?B+Trees and why I love them, part IWhat are the main differences between INNODB and MYISAMB+ Tree File OrganizationDatabase Index: A Re-visit to B+ TreeFundamentals of database systems 腾讯|后台实习|一二三+HR面 | 已拿offer http://1.12.44.120/index.php/archives/5/ 2021-03-21T10:20:00+00:00 背景双非一本,软件工程大三在读,面试后台开发,去年8月开始准备,刷题 + 看书 + 视频项目:做了一个分布式的销售系统(主要是为了用一用SpringCloud的组件之类的),顺便实现了一下主从复制,负载均衡什么的,可以说是一个大杂烩的Demo部门:ieg 腾讯游戏 3.29 更新 一二三面4.2 更新 hr面 许愿offer4.9 更新 已oc,拒了字节和阿里,腾讯冲冲冲3.11 一面(40分钟)技术自我介绍两个数组,单个数组数据不重复,怎么找重复元素?说说思路就好冒泡排序说一说?插入排序说一说?你简历上写有一直刷题,给我看看你leetcode主页呗你项目上的主从复制怎么实现的?你怎么保证主从数据一致性?如果出现了某种原因数据不一致了怎么办?你用redis做缓存,那有没有考虑过性能的问题?读写分离怎么实现的?Map线程安全吗?堆栈的区别说一说用过啥数据结构呀?(这里说了数组、链表、栈、集合、队列)为啥不用树?(说平时业务用树比较少,但是刷题刷过很多)设计模式了解吗?工厂模式说一说?单例模式呢?Linux用过吗?怎么查询24小时内修改过的文件?你是哪里人?(唠嗑环节)反问是哪个部门啊?(ieg,具体部门当时有点惊讶ieg没注意听5555)听说IEG用C++比较多,但我用的是Java,我需要补充一些什么知识?(了解一下go)3.20 二面(30分钟)技术自我介绍项目架构是怎么样的?负载均衡怎么实现的?有什么用?计算机的内存是怎么存在的?(位图或者链表)局部变量和全局变量在内存中有什么区别?索引的类型有几种?聚簇索引细说一下吧哈希索引和聚簇索引有什么区别?使用上呢,这两个使用上有什么区别?(当时没答上来,觉得是要从优化那块去说)三次握手三次握手为什么是三次,两次四次行不行?Linux常用命令,说三个吧top命令能不能说一说我想查端口占用情况用什么命令?算法 (全都是说思路就好)反转链表倒序输出链表二叉树前序遍历二叉树后序遍历当时觉得前面基础答得不好,所以跟面试官说递归太简单了我说迭代思路吧。面试官后面也有说算法基础不错,很开心反问这是同个部门的二面吗?因为当时我是初试完了又变成初试,我以为是挂了又被捞了。。(是同部门二面)这次面试您觉得我需要补充哪里的知识?(算法功底很扎实,相比起来基础有点逊色了,多看看数据库的基础)工作地点在哪?(深圳南山)3.29 三面(40分钟)技术之前做过什么项目?联合索引有什么规则?最左匹配的原理是什么?(一开始没想到,面试官提示从底层考虑,秒想到B+树排序的原因,面试官说不错不错)非技术你说你之前去找老师做项目,当时是怎么找的?在老师的项目组里你觉得你是怎么样的为什么要做一个分布式的项目为什么要做负载均衡?为什么主从复制?你是怎么想的?有没有面试别的公司?(回答了还投了字节)喜欢腾讯还是喜欢字节?(说腾讯面试的体验比字节好)那你前两面有啥感觉?(面试官这里是笑着说的,就开玩笑的那种感觉)家里同意来深圳吗?为啥不考研?生活中遇到过什么公平的事情?不公平的呢?大学里遇到过什么特别有挑战性的事情吗?技术非技术都可以说报高考志愿的时候有没有想过去更好的学校?描述一下你比较向往的工作状态反问我可能需要一些时间去学习go(如果你能进来的话会有缓冲期的,你现在也可以看看go)如果有幸进去的话,会做什么(应该是上层应用,分布式啥啥啥的,跟你做的那个项目差不多)面试隔得有点久(最近有点忙,别着急,我加你微信,到时候有啥事直接找我)面试结束一刷新,流程到HR了,开心4.2 HR面自我介绍当时是出于什么样的心态去找老师做项目的?能给我描述一下当时你做这个项目也业务吗?看你还有一个自己做的开源项目,你当时是出于什么目的去做这个项目的?在做这个项目的过程中遇到过什么困难让你特别有印象的?这次实习面试你准备了多久?你是怎么准备的?前面三轮面试感受如何?能大概说一说吗?除了腾讯还有投其他的公司吗?对比一下感觉怎么样?对深圳感觉怎么样?老师的项目组带给你什么样的影响?你说你因为老师比较严肃所以导致在交流上说话会有点直白,那有对这方面做出改变吗?大概会实习多久?什么时候能来实习?反问根据这次面试,您对我评价如何?(这个问题针对个人性比较强,就不写回答了)大概多久出结果?(预计3-5个工作日)面试感受腾讯的面试真的是投的几家公司里感觉最好的了,体验特别特别棒。offer来了,开心 欢迎你来到chovychan的club http://1.12.44.120/index.php/archives/1/ 2021-03-01T03:59:00+00:00 您能来到这我十分开心,如果我的文章对您有帮助,那我倍感荣幸