一、背景说明
最近一公司在做权限服务,其中的设计可以作为反面案例好好学习下。
大概背景是这样的,公司有大几十部分,员工大概有1W人,因为每个部门都要用到权限,因此准备做一个权限的服务,封装权限的相关功能。
相关数据库设计如下(不是所有字段):
用户权限表
userId, roleId
资源表
resourceId, resourceUrl, resourceName
角色表
roldId, roleName
角色权限表
roldId, resourceId
这是一个标准的权限模型,用户和角色绑定,角色和权限绑定。
前面说了这个服务是给整个公司所有人员用的,为了解决性能问题,设计的同学憋了个大招,每个业务系统把上述表自己同步回去,然后通过MQ发送数据的修改情况。
看完这个设计,瞬间晕倒。
二、什么是服务,如何做服务化
先抛开上述设计的分析,我们看什么是一个服务,在我看来一个服务应该包含几点:
1、有自己的数据,对整个数据的生命周期进行管理,像订单中心,要对订单的创建、支付、发货,甚至包括逆向的售后都需要参与管理;
2、和其它系统交互主要通过接口交互,当然也有一些异步交互,像发送MQ,但主要还是通过接口交互,因为你要控制业务的逻辑,才能做到高内聚;
3、独立的部署;
4、做的比大的服务还有自己的后台,可以对业务进行配置,查看业务相关的数据,及进行业务流程的周转;
做服务的目的是提高系统/业务的可重用性,快速响应业务。所以一个好的服务应该是高内聚的,如果做的不好,一个表象就是如果要加点功能,各业务系统都要修改,系统响应慢,交互效率 低。
如何做服务化呢,没有严格的标准,在我看来有些可以参考:
1、分清哪些是服务该做的,哪些是不该做的
这个要结合业务讨论,理清业务边界,即要对系统的职责进行准确的定位;
2、对外一定是以接口提供服务为主
因为你是一个服务,需要做业务的控制,要管控业务流程,让调用方都不关心业务的具体设计,只关心结果就行了;
像上面的权限服务,应该提供判断用户是否有权限的接口,入参为userId和resourceId,只有这样,你才是高内聚的,因为中间的复杂逻辑都收拢在服务内。
3、业务闭环
服务所管理的业务的整个生命周期的应该是在服务内闭环的;
就像权限服务,核心应该是管理权限,那么权限的添加、修改、判断用户是否有权限都应该是在权限服务里完成的。
三、案例分析
再回到案例里,这么设计本身是为了解决性能问题,其实解决性能问题有很好方案,如缓存,即将权限数据保存到分布式缓存或本地JVM缓存,则TPS上到6,7K应该问题不大。
像上面这样设计为带来很多问题:
1、复杂的数据同步机制
消息的顺序性如何保证,实际情况可能是先将一个用户的权限添加,后来发现加错了需要删除,可能要发送2条消息,如果消息中间件无法保证顺序性,这个将会加大工程量。
2、逻辑的分散
因为权限服务没有对业务逻辑收拢,导致逻辑由每个业务系统自己实现,后续如果要做些调整,需要和每个业务系统调整逻辑并且上线,即因为权限服务的变化导致调用方的修改,估计每一次上线都是恶梦。
3、数据的安全性
因为权限数据到处复制,所以所有人的权限都可以看到,这个包括一些BOSS级别,如果数据库相关流程设计不好,每个业务系统都可以看到所有人的权限,很有可能泄漏敏感数据。