orm 通过外链表查找数据_程序猿修仙之路数据结构之设计高性能访客记录系统...

ec71309fb9cf8044e02c2eac22fe2d42.gif

点击上方蓝色字体,关注我们

c09ec5651553a70963558b67fab89c4b.gif

菜菜呀,最近我有个想法呀!

e2f5cb8f6348f6cc6ff739ee2a972040.png 7a7786fd39fb2ecd8bc5e1406588648b.gif

(心想:又尼玛有折磨人的想法了。) X总,您说~

f3d4f3a6daf01c6311fc4754b0572065.png

803e7fc7997ccad050a30c24105ae959.png

我想给咱们的用户做个个人空间,目前先有访客记录就可以,最近访问的人显示在最上边,由于用户量有十几亿,可能对性能要求比较高,三天后上线,你做一下吧!

e2f5cb8f6348f6cc6ff739ee2a972040.png 7a7786fd39fb2ecd8bc5e1406588648b.gif

(心想:一万头羊驼飘过!!)  但是X总,个人空间访问量比较大,需要设计,测试等环节,三天不够呀!~

f3d4f3a6daf01c6311fc4754b0572065.png 803e7fc7997ccad050a30c24105ae959.png

这个关系到公司的生死存亡,你加加班就行了```

e2f5cb8f6348f6cc6ff739ee2a972040.png 7a7786fd39fb2ecd8bc5e1406588648b.gif

(心想:一亿头羊驼!!) 好吧,X总,我尽最大努力! 苦笑中。。。。~

f3d4f3a6daf01c6311fc4754b0572065.png 803e7fc7997ccad050a30c24105ae959.png a6ec979295628899400d502a060d2dde.gif

需求要点

        每个用户都有自己的个人空间,当有其他用户来访问的时候,需要添加访客记录,并且更新为最新的访客,这里设计到一个坑,如果存在这个用户的访问记录需要更新用户的最后访问时间。那这个需求在技术维度来说,有什么特点吗?

先想10秒钟,在接着往下看!!!

有什么设计要点呢?

用户的访客记录一定要缓存,要不然怎么抗住大并发呢?

由于最新的访客记录变化非常快,要有一种能快速添加新数据,删除老数据的数据结构。

缓存的篇章今日暂且不说,说一下以上的第二点,也就引出了今日数据结构主角:链表

链表

链表百科:链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表属于线性结构

adf5280fb058ca3f5c637f114dce6a56.png链表分类

1. 单链表:链表中的元素的指向只能指向链表中的下一个元素或者为空,元素之间不能相互指向。也就是一种线性链表。

2c7e12a19ea88303f8f2e3ea2480d16c.png

public class Node

    {

        //当前节点的数据元素

        public T Data { get; set; }

        //当前节点的下一个元素

        public Node NextNode { get; set; }

    }

2. 双向链表:每个链表元素既有指向下一个元素的指针,又有指向前一个元素的指针,其中每个结点都有两种指针。

90ba0f182215a66c972fffef8c1aed4c.png

public class Node

    {

        //当前节点的前一个节点

        public Node PreNode { get; set; }

        //当前节点的数据元素

        public T Data { get; set; }

        //当前节点的下一个元素

        public Node NextNode { get; set; }

    }

3. 循环链表:指的是在单向链表和双向链表的基础上,将两种链表的最后一个结点指向第一个结点从而实现循环。

fe2ca63a01f1f90b59411e8ad5895b0c.png

844fb6e960bd954965a6cc246fcb253f.png

adf5280fb058ca3f5c637f114dce6a56.png特性

1. 元素的数量可以随时扩充。由于链表在物理的存储单元上是非连续的,这就早就了它天生的优势,我的节点可以在任意符合要求的地方分配内存。

2. 添加元素:

单链表:

        当在一个位置N之后插入新元素的时候,单链表首先把当前位置N的元素的Next指针指向新的元素,然后新的元素的Next指针指向N+1位置的元素。当然如果是在首位置插入新元素,只需要把新元素的Next指针指向链表的首元素即可,同理,如果要在单链表尾部插入新元素,只需要把单链表的尾部元素的Next指针指向新元素。至于循环单链表,无所谓首元素和尾元素之分。

482a38a180f0be14f939145ec6b18b81.png

双向链表:

        在位置N之后添加新元素和单链表原理类似,原理也是修改元素的指针指向。但是这里有一个不同,双向链表要修改前后元素(N位置和N+1位置)和新元素三个Node的指针,所以略微麻烦一点。

c0ab51bd9334a998ef0ac52967c20fd9.png

3. 删除元素:

单链表:

        当要删除位置N的元素的时候,只需要把N-1位置元素的Next指针指向N+1即可。

668d42399596649ebc43453f3c1bcd39.png

双向链表:

        当要删除位置N的元素的时候,需要修改N-1位置元素的Next指针指向N+1元素,同时还要修改N+1位置元素的Pre指针指向N-1元素。

39cf52b45cb967cc7165324650dc258d.png

4. 查找元素:

由于链表的元素在内存中并非连续,所以不能像数组那样拥有O(1)的查找时间复杂度,只能是通过首元素去遍历链表,所以时间复杂度为O(n)

程序设计

        给你10秒回到X总的需求中来。通过对链表的介绍,我们该选择哪种链表呢?这里我先说一下我的思路,如有错误请指正:

1. 当一个访客进入个人空间的首页时,大多数情况下,访客记录只需要缓存前100条或者200条即可,也就是说这个场景是存在热点数据的,80%(甚至更高)的请求命中在最近100条访客数据上,很少人会去查看很久以前的记录。所以基于占用内存空间上的考虑,我决定缓存最近的100条访客数据。

2. 假设我用链表缓存了前100条数据,其中在非首位置有一条访客A的记录,此时A又访问的这个用户空间,我需要把A的记录移到首位置,这个过程经历了删除A数据,在首位置添加A数据。假如A开始的位置是N,我在删除N位置数据的时候,需要查找N-1的位置元素修改其指针指向,如果是单链表由于当前位置N的元素中没有N-1位置元素的信息,所有需要重新遍历链表。如果是双向链表呢,位置N的元素中保存了位置N-1的元素,所以没有必要在重新遍历链表了,这也是双向链表对比单链表的优势,虽然内存占用上多了一个指针的内存大小,但是在实际的应用场景中更为常用。所以我选择双向链表。删除操作和添加操作时间复杂度都是O(1).

3.     对同一个空间的访问,必然存在锁和多线程的问题。所以我在选择框架的时候优先选择了基于Actor模型的框架。避免了在同一个用户空间上加锁的操作。

4. 由于基于Actor模型的框架,所以我没有采用类似Redis这样的进程外缓存,而是采用了进程内缓存,毕竟网络传输的速度再快也比内存操作要慢的多。应用层的Actor服务天然支持分布式。如果对actor 不太了解的同学可以度娘一下。

10319dbf2d7545d46412ca13ee2d85a1.gif

优化

1. 阅读到这里你是否感觉哪里有问题呢?是的,就是链表元素的查找,由于只能是遍历,所有链表查找元素的时间复杂度为O(n),那有没有办法优化呢?那就是我们以后要讲的另外一种数据结构了。

2. 空间的访客记录是以时间为维度的倒序排列,所以业务以及DB时间列的设计类型推荐为UTC时间戳long类型,毕竟long类型在多数语言中比datetime类型占用内存要小很多。

3. 无论是否使用缓存,用户的访问记录都是需要DB来持久化的,当有大量的请求的时候,我们可以利用某种机制来批量持久化到DB,而不是一个请求就访问数据库一次。

4. 当对空间的访客记录实时性要求不是很高的时候,我们可以每10秒或者5秒更新缓存,也就是批量更新缓存,这比单条加锁更新缓存效果更好。

X总的个人空间需求并没有结束,菜菜仍然在持续优化中,欢迎大佬指正

51cad667034c3dbfd8dd6c3a0194d092.png c24631d527b4bce5f75234573bbaef5b.gif ●程序猿修仙之路--算法之快速排序到底有多快 ●程序猿修仙之路--数据结构之你是否真的懂数组?

●程序猿修仙之路--算法之希尔排序!

●程序员修仙之路--算法之插入排序!

●程序员修仙之路--算法之选择排序!

a13f27e8bd8a5566442eee1ac0e4ec19.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值