#143 MongoDB 聚集(数据表)中的 ID

2016-06-01

默认是一个 ObjectId 对象,也可以手动设置。

举个栗子

使用 PyMongo:

# -*- coding: utf-8 -*-

from pymongo import MongoClient

client = MongoClient()  # 连接到默认主机的默认端口:localhost:27017
db = client.test_db
collection = db.test_collection
collection.insert({"Hu" : "Ang", "Love" : [5, 'Sun', 'Xiu']})
collection.insert({"And" : 20, "Daughter" : True})
collection.insert({"GIRL": ',', "IS": "A GIRL", '_id': 123})

如果是 MongoDB 数据库操作,就应该是这样:

$ mongo
> use test_db
> db.test_collection.insert({"Hu" : "Ang", "Love" : [5, 'Sun', 'Xiu']})
> db.test_collection.insert({"And" : 20, "Daughter" : True})
> db.test_collection.insert({"GIRL": ',', "IS": "A GIRL", '_id': 123})

最后查到的结果显示如下:

> db.test_collection.find()
{ "_id" : ObjectId("5746c0f900e0990cfc600938"), "Love" : [ 5, "Sun", "Xiu" ], "Hu" : "Ang" }
{ "_id" : ObjectId("5746c0f900e0990cfc600939"), "And" : 20, "Daughter" : true }
{ "_id" : 123, "GIRL" : ",", "IS" : "A GIRL" }

_id

如果自己往里面传 _id 的话,要注意唯一性约束,如果里面存在这个 _id 值,那么就会报错:E11000 duplicate key error index

为什么没有采用像其他数据库一样的主键自增机制?

可能是因为 MongoDB 天生的分布式属性,导致其不愿耗费精力来处理自增主键的同步问题。

ObjectId

关于 ObjectId 字段,官方文档中对每个字节所表示内容的说明:

ObjectId is a 12-byte BSON type, constructed using:

  • a 4-byte value representing the seconds since the Unix epoch,
  • a 3-byte machine identifier,
  • a 2-byte process id, and
  • a 3-byte counter, starting with a random value.

ObjectId 占 12 个字节,其中:

  • 第 1、2、3、4 个字节用来存 Unix 时间戳
  • 第 5、6、7 个字节用来存机器标识
  • 第 8、9 个字节用来存客户端进程编号
    时间戳 + 机器标识 + 客户端进程编号 保证 “机器 + 进程 + 时间” 的一致性。
  • 第 10、11、12 个字节用来存随机字符串
    保证同一台机器,同一个客户端进程,在一秒种之内创建的记录的一致性。
    2 *_ (8 _ 3) = 16777216,也就是说,理论上,同一台机器,同一个客户端进程,在一秒种之内可以创建 1677 万多条记录。

举个例子,比如在 ObjectId("5746c0f900e0990cfc600939")5746c0f9 就是时间戳,00e099 就是机器标识,0cfc 就是客户端进程编号,600939 就是随机字符串。

通过这个设计,保证不同机器的 mongod 服务、同一个机器上的不同 mongod 服务进程之间都不出现重复值的情况(可能性极低,如果出现,可能也有后续的处理办法)。

重点:ObjectId 在客户端生成!!!

我个人也觉得 ObjectId 在客户端生成比服务器端要好:

  1. 更加容易根据机器标识 + 进程编号保证记录的唯一性
  2. 将生成 ObjectId 的这一部分计算转移出去,也能略微减轻 MongoDB 服务的计算压力。
  3. 客户端插入记录的时候,自己就知道 ID,不需要服务器端的反馈,针对这个设计可以设计出一些不需要返回的 insert 方法,给服务器减少一些查询带来的压力。

PyMongo 中就是使用 bson.objectid.ObjectId 生成的。可以阅读一下相关代码,了解这个 ID 的生成方法。
PS:比如,在我的 Ubuntu 环境中,代码文件就是 /usr/local/lib/python2.7/dist-packages/bson/objectid.py

参考

#141 修改 Grub 系统菜单等待时间

2016-05-27

GRUB: GRand Unified Bootloader 统一引导程序

sudo vim /etc/default/grub
# 注释:GRUB_HIDDEN_TIMEOUT
# 修改:GRUB_HIDDEN_TIMEOUT= 秒数
sudo update-grub

#139 安装 Ubuntu 16.04 LTS 笔记

2016-05-17

重装系统,记录安装过程,留给日后重建同样的开发环境作参考。
其实还有好多细节没有记录,日后慢慢补充完整。

#138 Python bytes 类型

2016-05-16
  1. bytes 按索引取值得到的是整数。

    b'abc'[0]
    97
    
  2. strbytes 只需要编码一下就行了。反过来就是解码一下。

    s = '你好'
    b = bytes(s, 'utf-8')
    # b'\xe4\xbd\xa0\xe5\xa5\xbd'
    assert b.decode('utf-8') == s
    
    bytes('hello')
    TypeError: string argument without an encoding
    
    bytes('hello', 'ascii')
    b'hello'
    
    'hello'.encode()
    b'hello'
    
    bytes('hello', 'utf-16')
    b'\xff\xfeh\x00e\x00l\x00l\x00o\x00'
    
    bytes('hello', 'utf-32')
    b'\xff\xfe\x00\x00h\x00\x00\x00e\x00\x00\x00l\x00\x00\x00l\x00\x00\x00o\x00\x00\x00'
    
  3. bytesint 列表的转换。

    list(b'abc')
    [97, 98, 99]
    
    bytes([97, 98, 99])
    b'abc'
    
    bytes([256])
    ValueError: bytes must be in range(0, 256)
    
    # 大端序
    (2008).to_bytes(length=4, byteorder='big', signed=False)
    b'\x00\x00\x07\xd8'
    # 小端序
    (2008).to_bytes(length=4, byteorder='little', signed=False)
    b'\xd8\x07\x00\x00'
    struct.pack('<I', 2008)
    b'\xd8\x07\x00\x00'
    
    int.from_bytes(b'\x00\x00\x07\xd8', 'big')
    2008
    int.from_bytes(b'\xd8\x07\x00\x00', 'little')
    2008
    
    int.from_bytes(b'abc', 'little')
    6513249
    int.from_bytes(b'cba', 'big')
    6513249
    

    PS:2020/11/02, 字节顺序(大端序、小端序)

  4. Python2 字符串

    # python2
    print(repr('你好'))
    '\xc4\xe3\xba\xc3'
    print('\xc4\xe3\xba\xc3')
    你好
    
    # python3
    print('\xc4\xe3\xba\xc3')
    'ÄãºÃ'
    print('\xc4\xe3\xba\xc3'.encode('latin-1'))
    b'\xc4\xe3\xba\xc3'
    print('\xc4\xe3\xba\xc3'.encode('latin-1').decode('gbk'))
    '你好'
    

#137 Linux 分区方案(Partition Scheme)

2016-05-14

安装 Ubuntu 16.04 时选择的分区方案。

挂载点 大小 意义
/ 50GB 根目录
/boot 10GB 启动目录
/home 150GB 用户主目录
/usr 100GB 程序分区
/var 50GB 变量文件目录
/tmp 50GB 临时文件目录
SWAP 20GB 交换分区

#135 yum 包管理系统

2016-05-02

关于 DNF 的更多信息,参考:2016/05/03 CentOS DNF

介绍

  1. .rpm 包,和 .deb 包是 Linux 生态中两种最主要的包格式。
  2. yum:
  3. 较新版本提供了 dnf 工具,改善 yum

包名

bash-4.2.46-35.el7_9.x86_64.rpm

其中:

  • bash 是名称
  • 4.2.46 是版本
  • 35.el7_9 是构建版本
  • x86_64 是服务器架构
  • rpm 是文件后缀
名称    :bash
架构    :x86_64
版本    :4.2.46
发布    :31.el7
大小    :3.5 M
源    :installed
来自源:anaconda
简介    : The GNU Bourne Again shell
网址    :http://www.gnu.org/software/bash
协议    : GPLv3+
描述    : The GNU Bourne Again shell (Bash) is a shell or command language
         : interpreter that is compatible with the Bourne shell (sh). Bash
         : incorporates useful features from the Korn shell (ksh) and the C shell
         : (csh). Most sh scripts can be run by bash without modification.

基本用法

yum help list # 查看帮助

yum search <package> # 搜索包

yum list
yum list installed
rpm -qa
yum list --upgradable

yum info <package>
rpm -qi <package>

rpm -ql <package> # 已安装包的文件列表
rpm -qd <package> # 已安装包的文件列表中的文档部分
rpm -qc <package> # 已安装包的文件列表中的配置部分

yum repolist

# repoquery 是 yum-utils 包提供的命令
repoquery -l <package> # 文件列表
repoquery -f <filepath> # 查看文件属于哪个包, 比如: `repoquery -f "*/repoquery"`
repoquery --location <package> # 查看包的下载地址

yum deplist <package> # 依赖
rpm -qR <package> # 已安装包的依赖
rpm -q --whatrequires <package> # 反向依赖
rpm -q --whatprovides <filepath>
rpm -qf <filepath>

yum provides <pattern>
yum whatprovides <patter>

yum check-update
yum updateinfo
yum update [package]
yum upgrade [package]
yum update-minimal
yum upgrade-minimal # 和 yum update-minimal 相同
yum downgrade <package>

yum install <package>
yum install <package-rpm-filepath>
yum reinstall

yum makecache
yum clean

yum erase
yum remove
yum autoremove

# list, info, summary, repeat, redo, undo, new, rollback, addon, addon-info, stats, statistics, sync, synchronizepkg, pkgs, pkg-list, pkgs-list, package, package-list, packages, packages-list, pkg-info, pkgs-info, package-info, packages-info
yum history
yum history list
yum history list all

yum versionlock <package>

安装组

RedHat 系列提供的,安装组(Group)的概念非常好。

安装组就是为了某一个目的需要的一组包,比如 gnome-desktop 组是安装一个完整的 gnome 桌面环境,web-server 组是安装 apache 和相关的几个包。

  1. 安装组中有必须安装的包(Mandatory Packages),默认安装的包(Default Packages),也有可选的包(Optional Packages)。
  2. 按我的理解,安装组分成三类:
  3. 可用组 Available Group,就是普通的安装组,包含部分包,可以 install。
  4. 环境组 Environment Group,就是安装组的组,group of goups,比如 minimal 环境组包含必须的 core 组和可选的 debugging 组。也可以 install。
  5. 基础组,比如 core,比如 php,是隐藏的,不可直接 install,用于构建环境组设计的。
    我实在想不到为什么这些组不直接暴露出来,这个设计有什么别的原因。
$ yum help groups
groups [list|info|summary|install|upgrade|remove|mark] [GROUP]

显示或使用、组信息

别名:group, grouplist, groupinfo, groupinstall, groupupdate, groupremove, grouperase
  • yum grouplist
  • yum group list ids 附带组 ID
  • yum group list hidden 列出所有组
  • yum groupinfo
  • yum groupinstall <group>
  • yum install @<group>
  • yum install @^<environment-group>
  • yum --setopt=group_package_types=mandatory,default,optional groupinstall "Web Server"
  • yum groupupdate
  • yum groupremove
  • yum grouperase

相关文件

  • /etc/yum.conf
  • /etc/yum.repos.d/
  • /etc/yum/

/etc/rpm 目录不知道是干什么的。

yum 插件

比如最常见的 fastestmirror,用于自动选择最快的镜像源。所以我们使用 CentOS 时,一般不需要去配置镜像源。