当前用户信息该不该缓存?

2014-04-24 16:15:47 +08:00
 gaicitadie
就是当前登录的个人信息,比如在v2ex,你的用户名,头像地址,账户余额(铜币银币之类的个数),最常用的做法,把用户的userid加密后保存在cookies中,每次用户访问网页的时候解密userid,然后

select * from Users where userid=xxxx

从用户表中获取用户的个人信息,用户名、头像、账户余额。。。等等。

这样每次打开一个网页,都要查询一次用户信息,于是为了减少数据库查询,把select出来的用户信息保存在session中,以后每次用户信息从session里面取(session用memcache实现,也就是每次到memcach里面取)。


我现在的疑问是,真的需要缓存用户信息吗?select * from Users where userid=xxxx 语句本身已经很高效,userid是索引字段,现在服务器内存这么大,数据库几乎都可以完全跑在内存中了。我不喜欢用缓存,是因为一旦用了缓存,原本清晰的思路变得复杂,并且控制不好命中率的话,反而会加重系统负担。
9834 次点击
所在节点    程序员
33 条回复
nigelvon
2014-04-24 16:33:24 +08:00
单从你说的这个需求来说会有思路变复杂,和命中率的问题么?
vietor
2014-04-24 16:35:17 +08:00
得看并发是多少
gaicitadie
2014-04-24 16:42:53 +08:00
@vietor discuz搭建的论坛,有的访问量挺大,貌似discuz没有缓存用户信息,直接每个页面都 select * from Users where userid=xxxx
heiher
2014-04-24 16:43:00 +08:00
关键是瓶颈在哪里
anheiyouxia
2014-04-24 16:45:44 +08:00
我觉得应该看情况,并发大的时候应该缓存最经常用的数据。如果本来流浪不大,这类基本信息可以缓存的,当然也可以不缓存。
说一个以前公司遇到的:
以前我工作的一家公司做的夜游,也是有类似情况,一开始设计的时候认为效率第一,就在用户登录的时候将用户大多数的常用信息以及为数不少的关联信息都加载到内存了。一开始没有什么问题,直到后来合服,一开始合服几次没问题,最后大服合并后,内存不足了。
gaicitadie
2014-04-24 16:48:27 +08:00
我个人的习惯是缓存能不用则不用,只有比较复杂的查询计算的出来的结果,并且实时性要求不高的才使用缓存,比如v2ex右侧的“今日热议主题”、“最热节点”这些东西,计算出来这些东西需要的时间多一些,并且实时性要求不高,仅仅为了展示,不会利用缓存里面的东西进行业务逻辑计算。

能直接select ... where id=xxx 的绝对不缓存
gaicitadie
2014-04-24 16:52:15 +08:00
感觉对缓存的迷信,就像前几年迷信windows系统下的各种优化大师,一个操作系统同时开N个优化大师,结果本来很快的系统变得巨卡。
alex321
2014-04-24 16:59:21 +08:00
仅缓存必须缓存的东西。比如频繁调用的,而且更新频率相对低的。
用户名这些信息第一次查询了,无非就是头像、个性签名、昵称、性别、积分、各种统计的总数什么的,直接丢到 session 去,怕 session 过大的话 base64 下,注销就销毁。
anheiyouxia
2014-04-24 17:01:49 +08:00
@anheiyouxia 靠,没打完就被发出来了。
然后我们一开始排查了日志并没有发现问题出现在哪里,只看到内存一直飙升,直到崩溃。最后忘记怎么发现这个问题了,当时都惊讶了,怎么把所有数据都加进去了。然后修改程序,把绝大多数的缓存都去掉了。后来发现去掉太多,数据量读取很频繁,玩家等待数据加载的过程多了几秒。几经修改,才将数据优化到比较稳定的状态。
gaicitadie
2014-04-24 17:06:04 +08:00
@anheiyouxia 发现瓶颈以后再根据实际情况加缓存比较靠谱
gaicitadie
2014-04-24 17:08:20 +08:00
@alex321 取session也需要耗费资源,如果是php默认的文件存储,还不一定有查询数据库效率高。如果session放在memcache,能比数据库的 select ... where id=xxx 高多少呢?一直认为 mysql 根据 id 查询单条记录的效率很高很高
xiawinter
2014-04-24 17:10:23 +08:00
@gaicitadie 这个太夸张了。 对 v2ex 来说, thread 也是 select * from thread where id = 109856, 难道这个 thread 不缓存么?

我们缓存的对象是共用的,变化少的, 不容易计算出来的。

至于楼主说的情况,也需要看情况处理, 如果这一串信息很多, 而且可能在不同的表里,那么是需要缓存的, 如果他必须一次性取出来的话。

显然 账户余额和头像信息是不应当放在一个表里的, (如果是一张表的话, 那么我觉得这个设计本身有问题, 数据量大,存在更新平静, 不断刷 user 表), 那么为了获取用户信息,可能要查询很多表, 这就有效率问题。
waitgroup
2014-04-24 17:14:14 +08:00
@alex321 base64比单纯的序列化占用大, 而且你这个涉及到当前用户A的操作改变了当前在线的B的属性, 你还得去找到B的session更新, 只会比用cache更复杂.


@gaicitadie pk查询确实高效, 但是频繁查询要保证高效也得依赖querycache, 而mysql的querycache很废, 同样的一个查询涉及到读取columns不同甚至大小写不同都会导致cache命中失败, 这样还不如放弃querycache直接用第三方cache.
Mutoo
2014-04-24 17:16:55 +08:00
"最常用的做法,把用户的userid加密后保存在cookies中,每次用户访问网页的时候解密userid"

貌似不对哦。常用做法是给用户一个令牌(token)并绑定该用户,然后下次用户回来的时候,用这个令牌去查询用户。一段时间后令牌过期。
waitgroup
2014-04-24 17:18:51 +08:00
@Mutoo 你说的是传统session的实现, 他说的是拿secure cookie当session介质, 不冲突.
gaicitadie
2014-04-24 17:23:44 +08:00
@xiawinter v2ex的每个帖子都是缓存的吗,这个不清楚,不过有用discuz搭建的论坛比v2ex的访问量更大却没开缓存的。

discuz每次查询的账户信息,摘取的其中一个代码片段:m.uid AS discuz_uid, m.username AS discuz_user, m.password AS discuz_pw, m.secques AS discuz_secques,
m.adminid, m.groupid, m.groupexpiry, m.extgroupids, m.email, m.timeoffset, m.tpp, m.ppp, m.posts, m.digestposts,
m.oltime, m.pageviews, m.credits, m.extcredits1, m.extcredits2, m.extcredits3, m.extcredits4, m.extcredits5,
m.extcredits6, m.extcredits7, m.extcredits8, m.timeformat, m.dateformat, m.pmsound, m.sigstatus, m.invisible,
m.lastvisit, m.lastactivity, m.lastpost, m.newpm, m.accessmasks, m.editormode, m.customshow, m.customaddfeed
威望、积分、出现ucenter以前的头像。。。很多信息都是放在一个用户表的。

账户余额如果只在少数的页面显示,就没必要跟头像放在一个表了,但如果每个页面都显示呢,就没必要分两个表了
alex321
2014-04-24 17:31:02 +08:00
@waitgroup
@gaicitadie
session 相对零碎,放在内存中的呢,用户按照某个规则分为数个 block,便于索引和操作。
用户注销时,将用户资料 update 进库,并销毁 session。
base64 的是个性签名和头像地址,用于对付各种莫名其妙的非主流签名和需要分服务器分区块存储的零碎用户头像地址信息。
针对性别、数量什么的序列化到一个 info 中,取出时在前端解析。
akira
2014-04-24 17:40:39 +08:00
不要为了做缓存而做缓存
gaicitadie
2014-04-24 17:42:28 +08:00
@akira 握手,感觉项目一开始就强调缓存,有“医之好治不病以为功”的味道
cocalrush
2014-04-24 17:47:49 +08:00
这个问题正好是我遇到的问题,现在我负责我们系统的单点登录。单点登录和主系统是分开的,用户登录时单点登录验证成功后,在本地写下cookie信息。主系统拿到cookie中的token 再从单点登录的webservce去获取用户信息放在session里面.....感觉这样效率不高,而且好像还不是很安全呀。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/109856

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX