踩了 MongoDB 的一个小坑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
sing1ee
V2EX    程序员

踩了 MongoDB 的一个小坑

  •  1
     
  •   sing1ee 2015-05-15 14:51:19 +08:00 5776 次点击
    这是一个创建于 3806 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先了解几个基本点:
    1. MongoDB默认生成的ObjectId是在客户端完成的,时间戳+host+进程id等,详情见文档
    2. ObjectId生成的时候,是根据当期那服务器时间所在的时区
    3. 从collection中读出ObjectId,读取generation_time属性,默认是UTC
    4. 北京时间比UTC时间早了八个小时

    我们两台服务器,一个是北京时间,一个比北京时间早了八个小时。。。从这两个服务器入库MongoDB,并且根据generation_time读,就彻底乱了,结果
    1. 北京时间的服务器,得到的generation_time时间比北京时间晚了八个小时
    2. 比北京早了的服务器,得到的generation_time时间和北京时间相同

    我们以为2是正确的。。。

    我们用的是pymongo

    21 条回复    2015-05-17 17:00:57 +08:00
    ZackYang
        1
    ZackYang  
       2015-05-15 15:13:35 +08:00
    我都是用 uuid 改写...
    jiangzhuo
        2
    jiangzhuo  
       2015-05-15 15:14:25 +08:00
    做集 肯定要集使用的一的,特是生成唯一性和有序的id的候
    yueyoum
        3
    yueyoum  
       2015-05-15 15:19:23 +08:00   2
    这点还真没注意。

    我现在基本都用 UUID 做主键。 无论是 mysql, postgresql 还是 mongodb

    简单,方便。 uuid4 冲突几率是有, 如果你能碰到, 也算是你的运气。

    什么 分布式, 唯一ID生成, 数据库合并, 瞬间解决。



    特别方便的一个使用例子是 django orm 的 bulk_create, 如果你的主键是 自增长 int
    那么 返回的 列表中 对象是没有 id 属性的。

    这时候用UUID 先给对象赋予ID, bulk_create 返回的对象就是带有ID属性的。

    这在 bulk_create后, 需要这些新增加对象ID 的情况 特别有用。


    再说一个场景吧。

    曾经有个项目, 一个server 对应一个 db, 用的 mongodb,

    因为担心效率问题,没有上全局ID生成服务。

    是每个server自己算的, 算法大概是 PARAM * NEWID + SERVER_ID

    param 是一个定义好的数值,比如 1024,
    newid 是这个server 自己生成的唯一自增长ID, 比如 1,2,3,4...
    server_id 就是这个 server 的 id, 不同server 的 id 不一样。

    这样生成好处是 方便,快速
    但缺点也很明显

    能开多少server 是由 param 来决定的, 最多 param 个



    所以,上UUID, 上面问题一锅端。


    有同学会说 INT ID 好啊, 数字的,自然就排序了,
    mongo 的 objectid 好啊, 还带有时间戳, 也可以排序。


    大不了在记录中增加一个 create_at 字段就行,
    相比上面的问题, 增加一个带索引的列,根本不是问题
    kslr
        4
    kslr  
       2015-05-15 16:09:02 +08:00
    这不是mongodb的坑,这么多机器时间还不统一,另外 create_at和update_at
    cloudzhou
        5
    cloudzhou  
       2015-05-15 19:38:12 +08:00
    @yueyoum 但是使用 uuid 会不会引起性能的减退呢,字段这么长
        6
    sing1ee  
    OP
       2015-05-15 19:48:06 +08:00 via iPhone
    @kslr 时间同步,有什么好方案么
    sing1ee
    likuku
        7
    likuku  
       2015-05-15 20:21:16 +08:00   1
    @sing1ee 配置好 ntpd 服务啊,每台服务器都运行它。ntpd 是渐进式校准服务器时钟,不会引起时钟误差颠簸(有些服务/软件假若侦测到时钟颠簸,可能会终止运行/运行不正常)。
    likuku
        8
    likuku  
       2015-05-15 20:22:45 +08:00
    @sing1ee 关于时钟颠簸/跃变 会引起问题,参考:

    AsiaBSDCon上说OpenBSD的sensor framework的时候的一个观点 - delphij's Chaos : https://blog.delphij.net/2007/03/asiabsdconopenb.html
    mko0okmko0
        9
    mko0okmko0  
       2015-05-15 22:08:26 +08:00
    统一使用格林威治时间.直接存成秒数字.一般索引提速.需要时间索引则另用函数生成索引.
    springwarm
        10
    springwarm  
       2015-05-15 23:20:41 +08:00
    楼主给出的基本点,"北京时间比UTC时间早了八个小时",会不会有问题

    UTC 和本地时间的换算公式是:
    UTC + 时区差 = 本地时间

    北京是东八区,对应的公式应该是:
    UTC + (+0800) = 北京时间

    以此推断,是UTC 时间比北京时间早了八个小时吧
    sing1ee
        11
    sing1ee  
    OP
       2015-05-15 23:54:36 +08:00
    @springwarm 这个应该是北京早吧=;=
    Landarky
        12
    Landarky  
       2015-05-16 09:31:43 +08:00 via iPad
    不仅是时区问题 机器时间也可能差几分钟 修改到一致就好
    likuku
        13
    likuku  
       2015-05-16 11:11:00 +08:00
    @Landarky 修改机器时间...都21世纪了,没啥理由不用ntpd吧。如今桌面的 ubuntu/osx/windows都默认安装并开启ntpd服务的了。
    xiaogui
        14
    xiaogui  
       2015-05-16 12:42:09 +08:00
    UTC 并不是问题,都采用 UTC 最好了。
    whatisnew
        15
    whatisnew  
       2015-05-16 13:13:12 +08:00
    我用 mongodb 试着删除 where asc 顺序的前 30 行记录,折腾了半小时 remove findandmodify 都没搞定,然后,我就撤退了。。。
    makuta
        16
    makuta  
       2015-05-16 17:31:13 +08:00
    做Mongo集群
    ddou
        17
    ddou  
       2015-05-16 18:57:37 +08:00
    个人觉得是使用方式不对,ObjectId当ID用就行了,其他时间的话应该是CreatedAt和UpdatedAt
    Cu635
        18
    Cu635  
       2015-05-16 21:55:13 +08:00
    @springwarm 北京时间比UTC早。UTC的1:00am是北京时间当天的9:00am。
    Cu635
        19
    Cu635  
       2015-05-16 21:57:00 +08:00
    @springwarm 计算公式是
    1:00am(UTC)+(+0800)(东八区)=9:00am(北京时间,东八区时间)
    VirgilMing
        20
    VirgilMing  
       2015-05-17 01:27:20 +08:00 via iPhone
    我很好奇哪个时区比 UTC+8 还 +8?
    springwarm
        21
    springwarm  
       2015-05-17 17:00:57 +08:00
    @Cu635 @sing1ee
    知道我的问题出在哪了,我自行换做另外一种说法来理解:同一个时刻,用UTC表示比用北京时间表示,数值“小” (无所谓早晚之分,只是表示法不同)
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3895 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 04:13 PVG 12:13 LAX 21:13 JFK 00:13
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86