被面试官问到项目中的难点?是时候对自己的项目进行总结了(记一次项目问题总结)

文章目录

  • 项目介绍
  • 1、设计任务和事件的规则计算及存储方式
  • 2、分布式事务解决方案
  • 3、数据库与redis缓存的数据一致性
  • 4、缓存穿透
  • 5、分布式锁
  • 6、消息的延迟推送

项目介绍

此项目提供了小组成员共享任务提醒的功能。

具体功能为:

  • 管理员对任务或事件的创建,以及对任务的分配。

  • 定时给任务执行人发送提醒。

  • 任务执行人完成任务。

额外说明:

  • 小组中最少有一个管理员,最多有两个管理员。
  • 成员数量不做限制,但根据场景不建议超过10个。
  • 除管理员外普通成员没有创建和修改任务的权限。
  • 任务:固定时间点给执行人提醒要做的事情。
  • 事件:所有成员都可以看到的有时间段的事件,事件本身不具备提醒功能,可以添加关联的任务给相应的执行人发送提醒,比如在事件开始的时候关联一个事件开始的任务,在事件结束的时候关联事件结束的任务,也可以不关联事件的时间,只建立关联事件的任务。

1、设计任务和事件的规则计算及存储方式

设计方案

  1. 首先pass掉子任务(子课程)全量落表的方式(无限重复规则的按时间落表往后半年或1年的数据),此方式对数据库的压力太大。

  2. 采用存储任务规则的方式,对已经发生的任务落历史表,未发生的任务使用规则计算发生时间,未发生已修改的存特殊(special)表。

问题

  1. **开发时间成本问题:**任务规则引擎设计,人力成本及时间成本太大。

  2. **计算性能问题:**考虑到规则解析计算的性能可能会出现瓶颈,提出此问题。

解决方案:

  1. 使用rfc-2445标准规范,选用开源项目组件。寻找可靠的开源组件并测试其性能表现,最终经过Jmeter压力测试发现其性能瓶颈出现在http的并发请求上,规则计算不是其性能瓶颈,为减少网络开销,最终对接口进行封装,采用一次请求计算多条规则的方式设计接口。

  2. 对入口服务的接口采用redis缓存进一步缓解服务器压力,对常用接口的结果进行缓存,如首页的接口,由于其参数一天才变动一次,所以完全可采用缓存的方式存储数据。

2、分布式事务解决方案

问题

微服务架构的系统中总会出现分布式事务的问题,例如:任务服务和事件服务为两个单独的服务,而任务与事件又有关联的操作,修改一条事件需要修改所有与此事件关联的任务,这就涉及到数据的一致性了,需要使用分布式事务来解决问题。

解决方式

解决分布式事务有很多方法,例如:基于可靠消息的最终一致性方案、TCC事务补偿型方案、最大努力通知型。

经过讨论,最终选用了最大努力通知型。详细设计方案为:调用对方服务时,判断是否成功,成功则流程流程继续,失败就把调用信息存入重试表中,然后继续下面的流程。最后使用定时扫描的方式重新发起接口的调用,重试调用一定次数,如果成功则结束,如果一直未成功则通知管理员处理此信息。

3、数据库与redis缓存的数据一致性

问题

在使用了缓存的业务场景中,例如查询用户的可访问资源,在修改数据库中的这些数据时,可能导致用户查出的缓存数据还是旧数据。

解决方式

设置redis缓存数据过期时间,修改数据时清除对应的缓存,使用户下次查询直接使用数据库的数据。

4、缓存穿透

问题

恶意用户发起攻击,查询一个缓存和数据库中都不存在的数据,造成一直查询数据库导致数据库压力飙升甚至垮掉。

解决方案

1) 接口增加用户权限校验,id做校验,例如 id<0 的直接拦截。

2) 在数据库中取不到的数据存一个空值到redis,设置缓存有效时间较短,例如30秒后过期。

3) 使用布隆过滤器,布隆过滤器可以做到的效果:一个一定不存在的数据会被拦截掉,可能存在的数据才会去查数据库。因为这个特性,只要设置合理的参数就可以极大的缓解缓存穿透问题。

了解更多:缓存穿透、缓存击穿、缓存雪崩区别和解决方案

5、分布式锁

问题

本系统功能允许一个家庭组中存在多名管理员,所以存在多名管理员同时操作一条数据的可能性,为保证数据的一致性,需要对操作进行加锁处理,微服务中每个服务可能有多个实例,所以存在多个进程的线程操作同一条数据的情况,于是普通单机系统的应用使用的java内存锁不再可靠。

解决方案

分布式锁提供了分布式系统中跨JVM的互斥机制的实现,常用的分布式锁的实现方式有三种:

1、基于数据库实现分布式锁

2、基于缓存(Reids等)实现分布式锁

3、基于Zookeeper实现分布式锁

其中基于数据库的分布式锁实现方式最为简单,但是太过依赖数据库。Redis和Zookeeper中,因为Redis已在本系统中有集成,而且实现起来简单,只要注意redis实现分布式锁的方式中的几个问题就能做出来一个相对完善的方案。PS:SpringBoot中使用Redis实现分布式锁

6、消息的延迟推送

问题

系统中一条消息推送给客户之后,如果客户没有及时处理需要在间隔一段时间后再发送一次。

解决方案

使用RabbitMQ的死信队列实现消息的延迟发送,其实现方式是设置第一个队列的消息存活时间(TTL),此队列不设置消费者,配置交换机,将过期的消息交换(死信交换DLX)到另一个队列,消费者消费此队列,此时距离消息产生就已经过了一段时间,实现了消息的延迟推送。

你可能感兴趣的:(微服务,JAVA,项目总结)