#276 几个小脚本

2018-12-05

随便翻一下谷歌浏览器调试工具(F12)执行过的脚本,摘几个贴一下。
1. Gitee GVP
2. API 测试时先调登录接口
3. heidiSQL 找回数据库密码
4. 列出 Python 文档中的章节
5. 自动删除网易邮箱的邮件

#275 OneTab 快速删除所有 URL 的方法

2018-12-05
function confirm() { return true; } // 覆盖 confirm 方法,一直返回确认
nodelist = document.querySelectorAll('#contentAreaDiv > div > div:nth-child(1) > div > div:nth-child(5) > div:nth-child(3)');
nodelist.forEach(function(ele, index, list) { setTimeout(function() { ele.click(); }, 1000 * index); });

#274 PEP

2018-11-22

主要是了解一下 PEP(Python Enhancement Proposal)的状态和类型。

#273 PHP 5.2 与 PHP 5.3+ 的几处差异

2018-11-22

修改一个我之前开发的一个 Discuz 插件对于 PHP 5.2 的支持(当时插件开发环境是 PHP 5.6.37),发现以下几处需要注意的地方:

#272 Web 保存数据的特殊方案

2018-11-08

将数据通过编码存在图片里面,实现导出导入功能。
虽然我不知道什么场景下需要使用这个方案,但这个想法特有意思。

#271 程序员字体

2018-11-01

纯英文:

  • Apple Monaco
  • Courier New
  • Consolas
  • DejaVu Sans Mono <>
  • JetBrains Mono
  • Source Code Pro
  • Ubuntu Mono
  • Inconsolata
  • Fira Code

中文:

  • 思源黑体(Source Han Sans)
  • YaHei Consolas Hybrid
  • Google Noto Mono

#270 Mongo 基础

2018-09-05

版本

以下是几个大版本和发布时间,作为一个大概的时间线吧:

2009/12 1.2
2010/03 1.4
2010/08 1.6
2011/03 1.8
2011/09 2.0
2012/08 2.2
2013/03 2.4
2014/04 2.6
2015/03 3.0
2015/12 3.2
2016/11 3.4
2017/11 3.6
2018/06 4.0

当前最新版本 8 月发布的 4.0.2

Update @ 2021/06/07:
之后主版本号就一直停在了 4,2020 年之后甚至一直停在了 4.4(2019 年 4.2,2020 年 4.4),这也意味着功能组件稳定下来了。

概念

在 Mongo 中,有一些名词变了,看文档的时候需要注意。

  1. 表 Table -> Collection 集合
  2. 行 Row -> Document 文档
  3. 列 Column -> Field 字段(其实 RDB 中的 Column 也经常说成字段)

数据库 Database,索引 Index 不变。

Collection

Document

  1. BSON
  2. 字段名是字符串类型(UTF-8)
  3. 字段有序
  4. 值的类型:
  5. String UTF-8 类型
  6. Int32
  7. Long
  8. Double
  9. Boolean
  10. Object
  11. Array
  12. Date
  13. ObjectId
  14. Null
  15. Date
  16. Timestamp
  17. Decimal128
  18. MinKey
  19. MaxKey
  20. Binary data
  21. JavaScript

废弃:

  1. Undefined
  2. DBPointer
  3. Symbol
  4. JavaScript code with scope

ObjectID

所有 Document 必须有一个 _id 键,没有类型限制,默认是 ObjectID 类型。
PS:所有 Document(BSON)中还包含一个时间戳,4B 时间戳 + 4B 自增数

  • 4B Unix 时间戳
  • 3B 机器标识符
  • 2B 进程号
  • 3B 随机数

关于 NoSQL

在大数据时代,传统 RDB 十分严谨的同时,效率也十分低下。
有人创造了 NoSQL 这个词,表示 Non-SQL,即不支持 SQL 的数据库。
后来部分产品添加了 SQL 支持,含义又演化成 Not Only SQL。
再后来又有人提出 NewSQL 概念,还是差不多的意思。

实现方式:

  1. 键值存储 Key-value store
  2. 文档存储 Document store
  3. 图数据库 Graph
  4. 对象数据库 Object database
  5. Tabular
  6. Tuple store
  7. Triple/quad store (RDF) database
  8. 主机式服务 Hosted
  9. 多数据库 Multivalue Database
  10. Multimodel Database

MongoDB 解决了什么问题

什么事情是 MongoDB 可以做,而 MySQL / PostgreSQL 不能做的?

特点

  • C++ 开发
  • 文档存储(JSON)
  • No Schema
  • 可以为任意属性建立索引
  • 灵活的查询语法
  • 内置小文件存储(GridFS)
  • 服务器端脚本
  • 分布式
  • 基于 AGPLv3 发布

PS:由于和云服务提供商的斗争,4.1.4 之后的所有版本(还有老版本的 BUG 修复版本)全部改用 SSPL (Server Side Public License,服务器端公共许可证) 。
该协议要求云服务提供商必须使用相同协议开放代码(之前所有主要的开源协议都没有对云服务提供商做任何限制),但 OSI 拒绝承认这是开源协议,部分 GNU/Linux 发行版将其从软件源移除。
再后来,其他开源项目,比如 Redis,Elastic,Graylog,也相继采用了和 MongoDB 相同的策略,改用了新的协议分发代码以对抗云服务提供商。

安装

sudo apt install -y mongodb
sudo systemctl disable mongodb
sudo systemctl restart mongodb
sudo systemctl status mongodb

如果希望直接从官方安装最新版本(仅支持 Ubuntu LTS 版本):

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
echo "deb [arch=amd64] https://repo.mongodb.org/apt/ubuntu/dists/$(lsb_release -cs)/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb44.list
sudo apt update
sudo apt install -y mongodb-org
# sudo apt-mark hold mongodb-org # 避免随系统更新

配置

PS:较老的版本有一个自带的简易 Web UI,通过 httpinterface, 或者 rest 参数可以启动,3.2 之后去掉了。

配置文件

# 自带配置
dbpath=/var/lib/mongodb
logpath=/var/log/mongodb/mongodb.log
logappend=true
bind_ip = 127.0.0.1  # 修改为 0.0.0.0
# 端口是默认的 27017
journal=true

# 添加配置
replSet = markjour
# daemon 模式运行,如果用 systemd 就不需要这一行:
fork = true
sudo systemctl restart mongodb

sudo ps -ef | grep mongod
sudo netstat -antp | grep mongod

副本集

// 主节点初始化
rs.initiate();

// 查看副本集配置
cfg = rs.conf();

// 修改主节点 host 为 IP 形式
cfg.members[0].host = "<IP>:<Port>";
rs.reconfig(cfg);

// 添加从节点
rs.add("192.168.64.234");
// 如果是连接不上的节点:"Quorum check failed because not enough voting nodes responded; required 2 but only the following 1 voting nodes responded: 172.16.0.49:27017; the following nodes did not respond affirmatively: 192.168.64.234:27017 failed with Couldn't get a connection within the time limit"
rs.remove("192.168.64.234"); // 移除节点

使用

客户端 SHELL 是基于 JavaScript 的。

mongo
  • show dbs
  • db
  • use <dbName>
  • db.createCollection("s1", {capped:true, size:100000})

保留数据库名称:admin, config, local

连接字符串

https://www.mongodb.com/docs/manual/reference/connection-string/

mongodb://
[username:password@]
host1[:port1]
[,host2[:port2],...[,hostN[:portN]]]
[
    /[database]
    [?options]
]
  • 复制集(ReplicaSet)
  • replicaSet
  • 连接
  • ssl
  • connectTimeoutMS
  • socketTimeoutMS
  • 连接池
  • maxPoolSize
  • minPoolSize
  • maxIdleTimeMS
  • waitQueueMultiple
  • waitQueueTimeoutMS
  • Write Concern
  • w
  • wtimeoutMS
  • journal
  • Read Concern
  • readConcernLevel
  • Read Preference
  • readPreference
  • readPreferenceTags
  • 认证
  • authSource
  • authMedhanism
  • gssapiServiceName
  • 服务器选择与发现
  • localThresholdMS
  • serverSelectionTimeoutMS
  • serverSelectionTryOnce
  • heartbeatFrequencyMS
  • 其他
  • uuidRepresentation

参考资料与拓展阅读

#269 短信的原理

2018-09-04
  • Short Message, 短信
  • SMS, Short Message Service, 短信服务
  • MO, Mobile Originate, 发短信
  • MT, Mobile Terminate, 收短信
Terminal 终端
SMC      短信中心
SMS GW   短信网关

重要协议

编码方案

  • 7bit ASCII
  • 8bit ASCII
  • UCS2 (早期的 Unicode 方案,2 Bytes 表示一个字)

长度

受协议限制,短信内容最大 140 字节,所以:

采用 8bit 编码的话,最长 140 字符。
采用 7bit 编码的话,最长 160 字符(正好)。
采用 UCS2 编码的话,最长 70 字符。

如果涉及长短信切割,根据通行的拓展协议,需要采用头三个字节存储相关信息。

采用 8bit 编码的话,每段最长 137 字符。
采用 7bit 编码的话,每段最长 156 字符(最后剩余 4 bits 空着)。
采用 UCS2 编码的话,每段最长 67 字符。

长短信分割

参考 GSM 03.40 9.2.3.24 TP-User Data (TP-UD) 部分,一般有两种方案:

\x05        剩余协议头长度
\x00        短信标识 GSM 03.40
\x03        剩余短信标识长度
随机字节(1 字节)
总包数
包序号(1 开始)

还有一种没有怎么见过的方案,就是采用两个字节做随机标识,然后头三字节改成 \x06\x08\x04

第二字节叫做 The Information Element Identifier(信息元素标识符),上面的 \x00\x08 分别标识 1 字节,2 字节随机标识方案。其他值可以参考文档。

#268 tornado: yield

2018-08-05
from tornado import gen, ioloop

@gen.coroutine
def dosth():
    yield gen.sleep(1)
    print('slept for 1 second')

ioloop.IOLoop.current().run_sync(dosth)
from tornado import gen, ioloop

@gen.coroutine
def dosth():
    print('dosth 222222222222222222222')
    yield gen.sleep(1)
    print('slept for 1 second 22222222')
    print('dosth over 2222222222222222')

@gen.coroutine
def test():
    print('test 111111111111111')
    dosth()
    print('test over 1111111111')

print('start')
ioloop.IOLoop.current().run_sync(test)
print('over')

# start
# test 111111111111111
# dosth 222222222222222222222
# test over 1111111111
# over

# start
# test 111111111111111
# dosth 222222222222222222222
# test over 1111111111
# slept for 1 second 22222222
# dosth over 2222222222222222
# over