前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用户系统设计

用户系统设计

作者头像
JavaEdge
发布2022-03-15 14:27:06
7600
发布2022-03-15 14:27:06
举报
文章被收录于专栏:JavaEdgeJavaEdgeJavaEdge

1 系统分析

1.1 Scenario 场景

注册、登录、查询、用户信息修改,哪个需求量最大?

支持100M DAU。注册,登录,信息修改 QPS 约:

  • 100M * 0.1 / 86400 ~ 100
  • 0.1 = 平均每个用户每天登录+注册+信息修改
  • Peak = 100 * 3 = 300

查询QPS约

  • 100 M * 100 / 86400 ~ 100k
  • 100 = 平均每个用户每天与查询用户信息相关的操作次数(查看好友,发信息,更新消息主页)
  • Peak = 100k * 3 = 300 k

1.2 Service 服务

  • AuthenticationService 负责登录注册
  • UserService 负责用户信息存储与查询
  • FriendshipService 负责好友关系存储

1.3 Storage

QPS 与 常用数据存储系统。

  • MySQL、PosgreSQL 等 SQL 数据库性能约 1k QPS
  • MongoDB、Cassandra 等硬盘型NoSQL数据库性能约 10k QPS
  • Redis / Memcached 等内存型NoSQL数据库性能约100k ~ 1m QPS (根据机器性能和硬盘数量及硬盘读写速度会有区别)

用户系统特点:读非常多,写非常少。读多写少的系统一定要使用 Cache 进行优化。

使用缓存,也就会带来数据不一致问题,数据库和缓存是两台机器,两套系统,并不支持加锁。如果是用一些第三方分布式锁,会导致存取效率降低,得不偿失。业界最常用的方法:

database.set(key, user);
cache.delete(key)
class UserService {

  def getUser(self, user_id):
  	key = 'user::%s' % user_id
  	user = cache.get(user)
  	if user:
  		return user
  
  	user = db.get(user_id)
  	cache.set(key, user)
  	return user
  
  def setUser(self, user):
    key = 'user::%s' % user.id
    db.set(user)
    cache.delete(key)
}

并发情况下依旧会出问题,在getUser执行到如下两行之间时:

另一个进程执行setUser(),cache 里会放入旧数据

问题2:db set 成功,cache delete 失败

但这两种情况发生概率<< cache.delete + db.set。

解决一致性问题?

利用 cache 的 TTL。

任何一个 cache 中的 key 都不要永久有效,设置一个短暂有效时间,如 7 天。则即便在极低概率下出现数据不一致,也就最多不一致7天。即允许数据库和缓存有“短时”不一致,但最终一致。

如果写很多,咋办?

在每次数据修改的时候,会在 cache 中 delete 这个数据。若写多读少,则此时 cache 没有任何优化效果。

Authentication Service 登录系统

Session 会话

  • 用户 Login 后,为之创建一个 session 对象
  • 并把 session_key 返回给浏览器,让浏览器存储起来
  • 浏览器将该值记录在浏览器的 cookie 中
  • 用户每次向服务器发送的访问,都会自动带上该网站所有的 cookie
  • 此时服务器拿到 cookie 中的 session_key,在 Session Table 中检测是否存在,是否过期

Cookie

HTTP 协议中浏览器和服务器的沟通机制,服务器把一些用于标记用户身份的信息,传递给浏览器,浏览器每次访问任何网页链接的时候,都会在 HTTP 请求中带上所有的该网站相关的Cookie 信息。Cookie 可理解为一个 Client 端的 hash table。

  • Session 记录过期以后,服务器会主动删除么?
  • 只支持在一台机器登陆和在多台机器同时登陆的区别是什么?
  • Session 适合存在什么数据存储系统中

Friendship Service

好友关系的存储与查询

双向好友关系

单向好友关系

Twitter、Instagram、微博

存在 SQL 数据库时

  • 查询x所有的关注对象
 select * from friendship where from_user_id=x 

查询x所有的粉丝:

select * from friendship where to_user_id=x;

存在 NoSQL 数据库时:

Friendship:

双向好友关系

微信,Facebook,WhatsApp

方案一:存储为一条数据
select * from friendship where smaller_user_id = x or bigger_user_id=x  

为何区分 smaller / bigger? SQL 可以按照这种方案,但NoSQL 很多不支持 Multi-index 不能使用这种方案。

方案二:存储为两条数据
select * from friendship where from_user_id=x 

NoSQL 和 SQL 都可按照这种方案

你觉得哪种更好呢?

Cassandra

三层结构的 NoSQL 数据库

• http://www.lintcode.com/problem/mini-cassandra/

  • 第一层:row_key
  • 第二层:column_key
  • 第三层:value

Cassandra 的 Key = row_key + column_key,同一个 Key只对应一个 value

结构化信息如何存储?

将其他需要同时存储的数据,序列化(Serialize)到 value 里进行存储。

Serialization:把一个 object / hash 序列化为一个 string,比如把一棵二叉树序列化

• http://www.lintcode.com/problem/binary-tree-serialization/

row_key

又称为 Hash Key, Partition Key。Cassandra 会根据这个 key 算一个 hash 值,然后决定整条数据存储在哪儿。无法 Range Query

常用:user_id

Column Key

insert(row_key, column_key, value)

任何一条数据,都包含上面三个部分。可指定 column_key 按何排序。

Cassandra 支持这样的“范围查询”:

query(row_key, column_start, column_end) 

可以是复合值,如 timestamp + user_id

SQL vs NoSQL

  • SQL的column是在Schema中预先指定好的,不能随意添加
  • 一条数据一般以 row 为单位(取出整个row作为一条数据)

NoSQL的column是动态的,无限大,可以随意添加

  • 一条数据一般以 grid 为单位,row_key + column_key + value = 一条数据
  • 只需要提前定义好 column_key 本身的格式(是一个 int 还是一个 int+string)

Cassandra 存储Friendship表

Cassandra 存储 NewsFeed

Friendship Table适合什么数据库?

SQL 和 NoSQL 的选择标准

原则1 大部分情况,都能用

原则2 需要支持事务,则禁选 NoSQL

原则3 想在什么地方偷懒,很大程度决定选什么数据库

  • SQL 结构化数据,自由创建索引
  • NoSQL 分布式,Auto-scale,Replica

原则4 一般一个网站会同时用多种数据库系统

不同的表单放在不同的数据库。

User Table 存在哪儿?

大部分公司选择了 SQL,因为信任度,Multi-Index!

Friendship 存在哪儿?

大部分公司选择了 NoSQL,因为数据结构简单,都是 key-value 的查询/存储需求,NoSQL效率更高!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-03-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 系统分析
    • 1.1 Scenario 场景
      • 1.2 Service 服务
        • 1.3 Storage
          • 解决一致性问题?
            • 如果写很多,咋办?
        • Authentication Service 登录系统
          • Session 会话
            • Cookie
            • Friendship Service
              • 单向好友关系
                • 双向好友关系
                  • 方案一:存储为一条数据
                  • 方案二:存储为两条数据
              • Cassandra
                • 结构化信息如何存储?
                  • row_key
                    • Column Key
                    • SQL vs NoSQL
                    • SQL 和 NoSQL 的选择标准
                      • 原则1 大部分情况,都能用
                        • 原则2 需要支持事务,则禁选 NoSQL
                          • 原则3 想在什么地方偷懒,很大程度决定选什么数据库
                            • 原则4 一般一个网站会同时用多种数据库系统
                              • User Table 存在哪儿?
                                • Friendship 存在哪儿?
                                相关产品与服务
                                对象存储
                                对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档