黑马点评项目问题

1.你是如何实现手机号登录功能的?

首先单体项目考虑使用基于session登录。

  • 首先是用户输入手机号,然后点击发送验证码,服务端收到这个请求之后,校验手机号是否不符合(前端也会校验),然后生成验证码(随机6位数),保存验证码到session中,然后把验证码发送给客户端。
  • 客户端根据收到的验证码 填入验证码并点击登录按钮,服务端收到请求之后,从session中校验验证码和手机号是否符合,如果符合,继续往下。从数据库中查询用户是否存在,如果不存在,则新增用户,如果存在,则将用户的信息保存到session中,并返回sessionid给客户端;客户端给保存到cookie中,后续请求都带着这个cookie在请求头里面。

这种方式的缺点:但是一到了web服务器集群的环境下,因为session是保存在内存中的,可能a服务器有,b服务器没有,每次客户请求都可能分发到不同的服务器,导致用户小a还要再登陆一次,以此类推。这样用户体验很不好。

因而在集群中,最好采用redis实现短信登录。

  • 其中获取验证码的步骤与上面的一致,差别在于后续操作。

2. 你是如何处理redis缓存的问题的?

首先缓存更新我才用了cache aside方法,即读的时候读缓存,未命中则从数据库中读,并更新到redis中;如果是写则,先写数据库,然后删除缓存。

针对缓存可能存在的问题-缓存穿透,有两种方法,缓存空对象,布隆过滤器解决,项目采用的缓存空对象的方法。

布隆过滤器就是一个位图数组,n个hash函数,对于任意一个数,先用hash函数求n个hash值,然后对位图数组长度取余,然后将位图数组里面对应的位数置为1。

还可能存在的缓存击穿问题,采用逻辑过期的方法,还有设置互斥锁。

逻辑过期要进行数据预热,将热点数据加载到缓存中去。

3. 你是如何解决超卖问题的?

通过乐观锁的方式,有版本号法和cas方法,版本号法,即更新数据库的时候不止更新数量,还要更新版本。

实际采用的是cas的方式

4. 怎么解决一人一单问题?

单体下可以通过版本号法和悲观锁法来解决,查询订单是否存在时用到。

通过redis的setnx命令来实现分布式锁(还有zookeeper实现分布式锁)

分布式锁setnx优化过程

  • 设置value的时候设置成跟线程id有关的,这样释放锁的时候要判断锁是否属于当前线程,如果是的话,就释放,不是的话就不释放
  • 但是这种还可能出现一个线程准备删除锁的时候(已判断属于当前线程),然后被阻塞了,锁超时释放,其他线程继续获取锁,然后执行,此时第一个线程阻塞结束,释放不属于自己的锁,导致其他线程可以继续获取锁,从而导致超卖。—使用lua脚本保证原子性(需要编程保证操作都是正确的,类似于redisMULTI(开启事务)/EXEC(触发事务,一并执行事务中的所有命令))
  • 但是这种锁还是没实现可重入(锁计数,用hash结构)、重试机制、超时释放(即没有续约机制)、主从一致性问题。–使用Redisson

综上:

5. 异步优化秒杀问题

可以采用异步执行的方式来进行优化整个流程,即开启新的线程去执行比较耗时的操作。

redis的stream流支持消费者组:

stream类型消息队列的XREADGROUP命令特点:

  • 消息可回溯
  • 可以多消费者争抢消息,加快消费速度
  • 可以阻塞读取
  • 没有消息漏读的风险
  • 有消息确认机制,保证消息至少被消费一次

6. 达人探店的点赞功能

对于点赞这种高频变化的数据,如果我们使用MySQL是十分不理智的,因为MySQL慢、并且并发请求MySQL会影响其它重要业务,容易影响整个系统的性能,继而降低了用户体验。那么如何我们要使用Redis,那么我们又该选择哪种数据结构才更加合理呢?

这里我推荐使用Set,因为Set类型的数据结构具有

  • 不重复,符合业务的特点,一个用户只能点赞一次
  • 高性能,Set集合内部实现了高效的数据结构(Hash表)
  • 灵活性,Set集合可以实现一对多,一个用户可以点赞多个博客,符合实际的业务逻辑

当然也可以选择使用Hash(Hash占用空间比Set更小),如果想要点赞排序也可以选用Sorted Set

7. 共同关注你是怎么处理推送的?

本例中的个人页面,是基于关注的好友来做Feed流,因此采用Timeline的模式。该模式的实现方案有三种:

拉模式:

推模式:

推拉结合:也叫做读写混合,兼具推和拉两种模式的优点。在推拉结合模式中,数据提供方会主动将最新的数据推送给终端用户或应用程序,同时也支持用户通过拉取的方式来获取数据。这样可以实现实时的数据更新,并且用户也具有按需获取数据的能力。推拉模式是一个折中的方案,站在发件人这一段,如果是个普通的人,那么我们采用写扩散的方式,直接把数据写入到他的粉丝中去,因为普通的人他的粉丝关注量比较小,所以这样做没有压力,如果是大V,那么他是直接将数据先写入到一份到发件箱里边去,然后再直接写一份到活跃粉丝收件箱里边去,现在站在收件人这端来看,如果是活跃粉丝,那么大V和普通的人发的都会直接写入到自己收件箱里边来,而如果是普通的粉丝,由于他们上线不是很频繁,所以等他们上线时,再从发件箱里边去拉信息

8. 如何实现uv统计?