风变科技后端面试
Go语言相关
- goroutine应用场景
- 业务逻辑需要并发
- 比如一个服务器,接收请求,阻塞式的方法是一个请求处理完成后,才开始第二个请求的处理。其实在设计的时候我们一定不会这么做,我们会在一开始就已经想到使用并发来处理这个场景,每个请求启动一个goroutine为它服务,这样就达到了并行的效果。这种goroutine直接按照思维的逻辑来使用goroutine
- 性能优化需要并发
- 需要给一批用户发送消息,正常逻辑会使用
for _, user := range users { sendMessage(user) }
- 但是在考虑到性能问题的时候,我们就不会这样做,如果users的个数很大,比如有1000万个用户?我们就没必要将1000万个用户放在一个routine中运行处理,考虑将1000万用户分成1000份,每份开一个goroutine,一个goroutine分发1万个用户,这样在效率上会提升很多。这种是性能优化上对goroutine的需求
- 需要给一批用户发送消息,正常逻辑会使用
- 业务逻辑需要并发
- hash有什么特点
- Hash: 把任意长度的输入通过散列算法变换成固定长度的输出
- Hash的特性:
- 输入域无穷,输出域有限。例如:有无穷多个(在工程中可以具体到多少个,例如1000)输入参数经过hash函数映射后得到有限的输出域{1,2,3,4}。
- 输入参数确定,经过hash函数映射出的返回值一样。(不是随机函数,不同的输入参数可能得到相同的返回值)。
- 输入域上的值经过函数值映射后会几乎均等的分布在输出域上。
- 解决HASH冲突的办法
- 开放定址法(再散列法)
当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式: Hi=(H(key)+di)% m i=1,2,…,n 其中H(key)为哈希函数,m 为表长,di称为增量序列
- 线性探测再散列
- dii=1,2,3,…,m-1 这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。
- 二次探测再散列
- di=12,-12,22,-22,…,k2,-k2 ( k<=m/2 ) 这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。
- 伪随机探测再散列
- di=伪随机数序列。具体实现时,应建立一个伪随机数发生器,(如i=(i+p) % m),并给定一个随机数做起点。
- 线性探测再散列
- 再哈希法
- 这种方法是同时构造多个不同的哈希函数:Hi=RH1(key) i=1,2,…,k; 当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。
- 链地址法
- 这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
- 建立公共溢出区
- 这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
数据库相关
- 这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
- 开放定址法(再散列法)
- MySQL的事务
- 事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。ACID 四大特性,原子性、隔离性、一致性、持久性。
-
什么是事务?及其特性?
- 事务:是一系列的数据库操作,是数据库应用的基本逻辑单位。
-
事务特性:
-
(1)原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。
-
(2)一致性或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状态
-
(3)隔离性。在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务,
-
(4)持久性。事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存。
-
或者这样理解:
- 事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。要将有组语句作为事务考虑,就需要通过ACID测试,即原子性,一致性,隔离性和持久性。
- MySQL存储引擎有哪些,什么特点
-
MyISAM 是非事务的存储引擎,适合用于频繁查询的应用。表锁,不会出现死锁,适合小数据,小并发。
-
innodb 是支持事务的存储引擎,适合用于插入和更新操作比较多的应用,设计合理的话是行锁(最大区别就在锁的级别上),适合大数据,大并发。
-
两个存储引擎的区别
- 区别于其他数据库的最重要的特点就是其插件式的表存储引擎。切记:存储引擎是基于表的,而不是数据库。
- InnoDB与MyISAM的区别:
- InnoDB存储引擎: 主要面向OLTP(Online Transaction Processing,在线事务处理)方面的应用,是第一个完整支持ACID事务的存储引擎(BDB是第一个支持事务的存储引擎,已经停止开发)。
- 特点:
- 行锁设计、支持外键,支持事务,支持并发,锁粒度是支持mvcc的行级锁;
- MyISAM存储引擎: 是MySQL官方提供的存储引擎,主要面向OLAP(Online Analytical Processing,在线分析处理)方面的应用。
- 特点:
- 不支持事务,锁粒度是支持并发插入的表级锁,支持表所和全文索引。操作速度快,不能读写操作太频繁;
-
-
Redis应用场景
- 热点数据的缓存
- 由于redis访问速度块、支持的数据类型比较丰富,所以redis很适合用来存储热点数据,另外结合expire,我们可以设置过期时间然后再进行缓存更新操作,这个功能最为常见,我们几乎所有的项目都有所运用。
- 限时业务的运用
- redis中可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。
- 计数器相关问题
- redis由于incrby命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成、具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。
- 排行榜相关问题
-
关系型数据库在排行榜方面查询速度普遍偏慢,所以可以借助redis的SortedSet进行热点数据的排序。
-
在奶茶活动中,我们需要展示各个部门的点赞排行榜, 所以我针对每个部门做了一个SortedSet,然后以用户的openid作为上面的username,以用户的点赞数作为上面的score, 然后针对每个用户做一个hash,通过zrangebyscore就可以按照点赞数获取排行榜,然后再根据username获取用户的hash信息,这个当时在实际运用中性能体验也蛮不错的。
-
- 分布式锁
- 这个主要利用redis的setnx命令进行,setnx:”set if not exists”就是如果不存在则成功设置缓存同时返回1,否则返回0 ,这个特性在俞你奔远方的后台中有所运用,因为我们服务器是集群的,定时任务可能在两台机器上都会运行,所以在定时任务中首先 通过setnx设置一个lock,如果成功设置则执行,如果没有成功设置,则表明该定时任务已执行。 当然结合具体业务,我们可以给这个lock加一个过期时间,比如说30分钟执行一次的定时任务,那么这个过期时间设置为小于30分钟的一个时间 就可以,这个与定时任务的周期以及定时任务执行消耗时间相关。 当然我们可以将这个特性运用于其他需要分布式锁的场景中,结合过期时间主要是防止死锁的出现。
- 延时操作
- 这个目前我做过相关测试,但是还没有运用到我们的实际项目中,下面我举个该特性的应用场景。 比如在订单生产后我们占用了库存,10分钟后去检验用户是够真正购买,如果没有购买将该单据设置无效,同时还原库存。 由于redis自2.8.0之后版本提供Keyspace Notifications功能,允许客户订阅Pub/Sub频道,以便以某种方式接收影响Redis数据集的事件。 所以我们对于上面的需求就可以用以下解决方案,我们在订单生产时,设置一个key,同时设置10分钟后过期, 我们在后台实现一个监听器,监听key的实效,监听到key失效时将后续逻辑加上。 当然我们也可以利用rabbitmq、activemq等消息中间件的延迟队列服务实现该需求。
- 分页、模糊搜索
- redis的set集合中提供了一个zrangebylex方法,语法如下:
ZRANGEBYLEX key min max [LIMIT offset count] 通过ZRANGEBYLEX zset - + LIMIT 0 10 可以进行分页数据查询,其中- +表示获取全部数据 zrangebylex key min max 这个就可以返回字典区间的数据,利用这个特性可以进行模糊查询功能,这个也是目前我在redis中发现的唯一一个支持对存储内容进行模糊查询的特性。 前几天我通过这个特性,对学校数据进行了模拟测试,学校数据60万左右,响应时间在700ms左右,比mysql的like查询稍微快一点,但是由于它可以避免大量的数据库io操作,所以总体还是比直接mysql查询更利于系统的性能保障。
- redis的set集合中提供了一个zrangebylex方法,语法如下:
- 点赞、好友等相互关系的存储
-
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。 又或者在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。
-
这个在奶茶活动中有运用,就是利用set存储用户之间的点赞关联的,另外在点赞前判断是否点赞过就利用了sismember方法,当时这个接口的响应时间控制在10毫秒内,十分高效。
-
- 队列
- 由于redis有list push和list pop这样的命令,所以能够很方便的执行队列操作。
- 热点数据的缓存
- Redis基本数据类型
- String、Hash、List、Set、SortedSet
- 相关场景
- Hash
- Hash一般也被称为字典,redis自己也可以作为一个比较大的hash存储。
- 一些关系型数据库中不是特别复杂的表,也无需复杂的关系查询,可以使用Redis的Hash来存储,也可以用Hash做表数据缓存。
- List
- 列表用来存储多个有序的字符串,一个列表最多可以存储2^32 - 1个元素,在redis中可以对列表的两端插入push和弹出pop,还可以取指定范围的元素。
- 消息队列:我们公司就是使用redis做消息队列,lpush + brpop或rpop命令,实现先进先出,如果消费失败客户端把key再放回去,消费成功真的remove掉
- lpush + lpop 栈
- lpush + rpop 队列
- lpush + ltrim = 有限集合
- lpush + brpop = 消息队列
- Set
- 集合是用来保存多个字符串的元素,内部不允许有重复元素,集合内的元素是无序的,Redis支持集合的增删改查,同时支持多个集合取交集,并集,差集
- 标签
- SortedSet
- 它保留了元素不能重复的特性,并且元素是有序的。
- 排行榜,目前公司的飙车榜用的是redis的有序集合,返回前面排名的元素之后再使用redis的mget命令获取获取到的key信息。
- Hash
- more: HyperLogLog、Geo、Pub/Sub
- Redis Module,像BloomFilter,RedisSearch,Redis-ML
计算机网络相关
-
TCP(传输控制协议):
-
TCP是面向连接的
-
每一条TCP连接只能由两个端点,每一条TCP连接只能是点对点的TCP连接::= { socket_1,socket_2 } ={ (IP_1:port_1),(IP_2:port_2)}
-
TCP提供可靠交付的服务
-
TCP提供全双工通信
-
面向字节流
-
-
UDP(用户数据报协议):
-
UDP是无连接的
-
UDP使用尽最大努力交付,但是不保证可靠交付
-
UDP是面向报文的
-
UDP没有拥塞控制
-
UDP支持一对一,一对多,多对一,多对一的交互通讯
-
UDP首部的开销小
-
-
TCP的连接管理:
- 连接三次握手:
- 客户端请求建立连接:SYN=1,seq=x;
- 服务器对客户端的请求进行响应:SYN=1,ACK=1,seq=y,ack=x+1
- 客户端对服务器端的响应信息进行回应:ACK=1,seq=x+1,ack=y+1
- 注: SYN为同步信息,在建立连接过程中始终为1
- 断开连接四次握手:
- 客户端请求断开连接: FIN=1,seq = u;
- 服务端对客户端的请求应答:ACK=1,seq=v,ack=u+1;
- 服务端请求断开连接:FIN=1,ACK=1,seq=w,ack=u+1;
- 客户端对服务端的请求应答:ACK=1,seq=u+1,ack=w+1;
- 连接三次握手:
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
如果你觉得本文海星,不妨请我喝杯咖啡