@IT·互联网

关于冗余设计的一点思考

2022-03-18  本文已影响0人  Roy1989

模型设计,消除冗余

首先简单介绍一下数据库结构设计的范式:

可以见得数据库范式的制定一直依赖追求的是在关系型结构下对空间的最优利用。

反模式,制造冗余

而空间和性能往往是相对,在实际的开发中,我们却经常特意制造一些冗余,以取得更好的性能。
接下来探讨下面的案例:一个聊天工具中的用户表,和用户的好友表。
用户表(用户ID,名称,头像,邮箱,手机号......)
好友表(用户ID,好友的用户ID,好友的名称,好友的头像)
这里的好友表是不符合第二范式的,因为我冗余了好友的名称、头像。这样当我在查询本人通讯录中的好友的时候就不需要连接用户表,甚至于我会将整个好友组缓存在一个内存的集合数据结构中。
而冗余带来的问题是数据同步问题。即“当好友修改了他的头像之后需要将好友表中的好友头像字段进行更新。”这里的同步仅仅是主从数据同步,冗余数据相当于缓存,因为无法依赖数据库完成数据同步,就用程序设计来处理,这里通常的解决方法是使用面向对象中的订阅模式。当好友对象产生的时候订阅用户的属性变更,于是当变更发生的时候可以响应处理数据同步。大多数消息队列都对该模式提供了很好的服务。这里的“数据同步”中的同步并不是“异步编程”中的同步的意思,冗余数据的同步实质上是异步进行的,需要允许一定程度上的实时性、可靠性缺失。
行到这里,我们的聊天工具已经可以很好地响应通讯录上小伙伴们的头像、名称修改了。梳理一下做法,首先是使用面向对象方法,将表转化为实体类,数据行转化为实例对象,列作为对象的属性,属性的修改即“写”权仅掌握在该实例对象手中,而其被其他实体的引用作为冗余副本通过订阅来更新。

回归现实,接受冗余

继续上面的好友表例子。
是的,我拥有了一个能及时响应好友变化的通讯录。而且我还有一个很喜欢换头像以及名字的好友,所以我经常会认不出我的好友究竟谁是谁。
于是我的产品经理提议增加一个备注的功能,多么妙的设定!于是我头脑中的好友画像通过备注,这个美妙的功能,跟通讯录中常常变换的头像建立了联系。
然而,剧情推进,在第二个大版本更新的时候我们的聊天工具加入了群聊,于是陌生人出现了。那些群友,并不在我的通讯录中,他们的头像也是常常变化的,OMG。那些陌生的群友就好像柯南中的黑影,我根本放弃了去取分谁是谁是谁在发言。
于是我天才的产品经理说:需要给群成员增加一个备注功能!
“異議あり!”
我马上反对了这个提议,一般的群成员名主键应该是(群ID+用户ID),而我对群成员备注的话主键则是(我的用户ID+群ID+群成员的用户ID),可是我的需求是对陌生人增加备注,主键是(我的用户ID+陌生人的用户ID)。一般做法中的群成员名只有在群规严格的群中才有用,而后两者基本可以说离谱了,无论哪一种其实都不好满足我的需求。
那么,我们现实中是怎么面对陌生人的呢?还是得对陌生人在脑中建立画像吧,这画像就像是对陌生人的部分信息的浅拷贝,就是冗余。而冗余的更新不是被动的订阅响应,是由我主动观察所得。此时,冗余副本的更新即“写”的主动权掌握在了“我”这个实例手中。
回到对陌生群友的处理。先增加一份陌生人数据实体类型(或者说表),与好友表冗余的用户基本信息相同,不同的是并不订阅其用户基本信息的变更而且不展示在通讯录上。于是,作为用户的我,就能看到一个头像、名字并不乱变的陌生人。那么什么时候应该同步呢,就是在“我”下次决定好好观察下这个陌生人的时候,也就是当我下次点开陌生人的名片的时候。由于是用户的主动行为,陌生人在用户脑中的画像能很好地更新与陌生人新头像之间的关联。
我的产品经理似乎快被我说服了,但他还是有点不服气。
好吧,系统设计的系统分析中有一个环节是对现有系统的分析,包括当前同类产品尤其龙头的分析。我们一起来看看张小龙是怎么做的吧。

上一篇下一篇

猜你喜欢

热点阅读