V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sing1ee
V2EX  ›  程序员

踩了 MongoDB 的一个小坑

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

    先了解几个基本点:
    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 会不会引起性能的减退呢,字段这么长
    sing1ee
        6
    sing1ee  
    OP
       2015-05-15 19:48:06 +08:00 via iPhone
    @kslr 时间同步,有什么好方案么
    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   ·   实用小工具   ·   3470 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:45 · PVG 18:45 · LAX 02:45 · JFK 05:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.