原文
下面是我学习比特币过程中针对比特币白皮书的翻译,重点放在内容上,不会一字不差的翻译。

Bitcoin:点对点电子现金系统

摘要

一个纯粹点对点版本的电子现金,允许在线交易直接在交易者之间进行,不需要经过金融系统。
数字签名提供了部分解决方案,但是如果仍然需要第三方信任机构来防止重复交易 (double-spending) ,那么就丧失了最大的好处。
我们提出一个解决方案,使用点对点网络来解决重复交易问题。
网络对每笔交易通过计算 hash 打时间戳,然后连接到一个基于 hash 的工作量证明 (proof-of-work) 的不断增长的链中。
增加的记录必须通过工作量证明才能够修改。最长的链不仅作为一系列已发生事件的鉴证,还证明他来自最强大的 CPU 算力池。
只要大多数的 CPU 算力是由节点控制,并且不会联合起来攻击网络,就会产生最长的链并且超过攻击者。
网络本身需要最小化的结构。
节点会尽最大的可能广播信息,同时节点可以自由离开或加入网络,接受最长的 proof-of-work 链,作为离线时的证明。

1 介绍

在这里我们提出一个解决方案,使用点对点分布式时间戳服务来生成交易的时间顺序的计算证明,来解决重复交易问题。
整个系统的安全依赖于诚实的节点控制的 CPU 算力,比攻击者的节点多。

我们所需要的是一个使用密码证明代替信任证明的电子交易系统。允许任意两个节点直接自由交易,而不需要第三方信任机构。
交易在计算上保证不可回退,可以保护卖方不被欺骗,并且为了保护买方实现第三方托管处理机制也很容易。

2 交易

我们定义了一个电子货币作为数字签名的链

white papper

FlatBuffers 是一个开源的、跨平台的、高效的、提供了 C++/Java 接口的序列化工具库。它是 Google 专门为游戏开发或其他性能敏感的应用程序需求而创建。尤其更适用于移动平台,这些平台上内存大小及带宽相比桌面系统都是受限的,而应用程序比如游戏又有更高的性能要求。它将序列化数据存储在缓存中,这些数据既可以存储在文件中,又可以通过网络原样传输,而不需要任何解析开销。

github

为什么要使用 Google FlatBuffers

  • 对序列化数据的访问不需要打包和拆包——它将序列化数据存储在缓存中,这些数据既可以存储在文件中,又可以通过网络原样传输,而没有任何解析开销;
  • 内存效率和速度——访问数据时的唯一内存需求就是缓冲区,不需要额外的内存分配。 这里可查看详细的基准测试;
  • 扩展性、灵活性——它支持的可选字段意味着不仅能获得很好的前向/后向兼容性(对于长生命周期的游戏来说尤其重要,因为不需要每个新版本都更新所有数据);
  • 最小代码依赖——仅仅需要自动生成的少量代码和一个单一的头文件依赖,很容易集成到现有系统中。再次,看基准部分细节;
  • 强类型设计——尽可能使错误出现在编译期,而不是等到运行期才手动检查和修正;
  • 使用简单——生成的 C++代码提供了简单的访问和构造接口;而且如果需要,通过一个可选功能可以用来在运行时高效解析 Schema 和类 JSON 格式的文本;
  • 跨平台——支持 C++11、Java,而不需要任何依赖库;在最新的 gcc、clang、vs2010 等编译器上工作良好;

和 protocol buffer,json 区别

Protocol Buffers 的确和 FlatBuffers 比较类似,但其主要区别在于 FlatBuffers 在访问数据前不需要解析/拆包这一步。 而且 Protocol Buffers 既没有可选的文本导入/导出功能,也没有 Schemas 语法特性(比如 union)。

JSON 是非常可读的,而且当和动态类型语言(如 JavaScript)一起使用时非常方便。然而在静态类型语言中序列化数据时,JSON 不但具有运行效率低的明显缺点,而且会让你写更多的代码来访问数据(这个与直觉相反)。

20190719_211259.png 20190719_211310.png 20190719_211316.png

cereal github

cereal is a header-only C++11 serialization library.

碰巧找资料的时候发现的,先记录下来,后面有时间在学习,目前暂时用不上。

在 centos 里面搭建 ta-lib 分析环境

安装 ta-lib

多平台的市场分析库
下载
wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz

untar and cd
./configure --prefix=/usr
make
sudo make install
cd /usr
find -name libta_lib.so.0

添加 /usr/lib 路径到环境变量中
在 /etc/profile 文件内添加下列行
export LD_LIBRARY_PATH=/usr/lib
激活环境变量
source /etc/profile

python ta-lib 库

创建虚拟环境
py36
pip install TA-Lib

windows 环境

区块链能解决这些问题主要是基于4个特点:
去中心化
不可篡改
公开透明
可控匿名

智能合约

特点应用:公开透明、不可篡改
痛点:比如两家公司有业务往来。业务结算之后,可能会牵扯到业务对账,财务对账,老板审批,催款,出纳转账。流程并不复杂,但繁琐重复,还有最另双方头疼的催款环节。
解决方案:如果采用智能合约呢?大家事先把规则说清楚并写进程序里,一旦到了付款日期,程序自动转账,整个过程无需任何人参与,但人人对账目清清楚楚,简单而高效。

防伪溯源

特点应用:公开透明、不可篡改
痛点:大家都网购吗?网购奢侈品,烟酒,或者进口商品时,担心假货吗?连实体店都有几率遭遇假货,谁敢保证快递小哥送来的就绝对是正品呢!
解决方案:给每一件“正版商品”都打上唯一的标记,让买家能够查到从工厂到消费者手里的全部流通环节(就好像现在快递能查到所有过程是一样的)。这样是不是可以放心大胆购买了呢?

金融领域

特点应用:去中心化、不可篡改
痛点:金融领域涉及到很多支付,资产管理的业务。金融机构一旦被黑客攻击损失就很大了。
解决方案:区块链去中心化的特点让系统很难被攻击,不可篡改的特点又大大提高了数据的安全性。

公益

特点应用:公开透明、不可篡改
痛点:“郭美美事件”后,很多人说不敢捐钱了,因为不知道自己的钱会跑去谁的口袋里。
解决方案:蚂蚁金服下面的公益项目已经采用了区块链技术,大家的捐款可以清楚查到去向。让大家更加安心的做慈善。

隐私保护

特点应用:可控匿名
痛点:你网购几次,就有短信广告发给你。你在银行多存点钱,就有人给你推销理财产品。你在医院检查身体,就有人给你推销保健品。我们在必要的情况下留下一点信息,接下来就无法避免被骚扰,被追索更多的信息,被推销,被纠缠。
解决方案:银行、医院这些机构无非就是想让你证明“这个叫xx的人就是你本人”。而区块链是可以很好的解决这个问题的。让你即可证明“这个叫xx的人就是我”,还可以保护好你的隐私信息。

我们怎么样理解钱包呢?简单讲它是连接区块链的一个入口。目前比较成熟的公链,如比特币、以太坊都有很多钱包可以选择。一般钱包需要完全访问你的用户资产,也就是会要求你输入私钥。钱包的作恶成本极低,这也是笔者建议选择开源钱包的原因之一。

加密数字货币钱包提供钱包地址的创建、加密数字货币转账、每个钱包地址交易历史的查询等基础金融功能。

通信协议

RPC、JSON-RPC 以及 JSON

JSON-RPC,是一个无状态且轻量级的远程过程调用(RPC)传送协议,其传递内容通过 JSON 为主。相较于一般的 REST 通过网址(如 GET /user)调用远程服务器,JSON-RPC 直接在内容中定义了欲调用的函数名称(如 {“method”: “getUser”}),这也令开发者不会陷于该使用 PUT 或者 PATCH 的问题之中。 本规范主要定义了一些数据结构及其相关的处理规则。它允许运行在基于 Socket、HTTP 等诸多不同消息传输环境的同一进程中。其使用 JSON(RFC 4627)作为数据格式。[2]

我们以比特币为例,根据 Original Bitcoin client/API calls list 文档我们可以得到 RPC 接口提供的函数列表。

以 sendrawtransaction 为例,这个函数列表提供了四列(Command、Parameters、Description、Requires unlocked wallet? ),分别表示函数名、传入参数、描述、是否需要解锁钱包。

我们把这个函数列表掌握之后,可以选择某一种语言,然后进行区块链钱包相关的开发。
当然,你还需要知道怎么样去部署一个比特币的完全节点和测试网络,这样就可以利用 RPC 进行接口调用,来和区块链网络进行交互。

安全

通常意义上的数字资产安全其实就是私钥的安全,
一个钱包是不是安全主要看它能否安全的管理和使用私钥。
助记词是明文私钥的另一种表现形式,其目的是为了帮助用户记忆复杂的私钥。
因此能否安全的管理助记词也是区别钱包是否安全的重要条件。

360的安全白皮书

Wallet

钱包里只含有钥匙,比特币钱包是密钥链。
Bitcoin Address + Private key = Bitcoin Wallet

比特币的所有权是通过数字密钥、比特币地址和数字签名来确立的。数字密钥实际上并不是存储在网络中,而是由用户生成并存储在一个文件或简单的数据库中,称为钱包。存储在用户钱包中的数字密钥完全独立于比特币协议,可由用户的钱包软件生成并管理,而无需区块链或网络连接。

有两种主要类型的钱包,区别在于它们包含的多个密钥是否相互关联。

第一种类型是非确定性钱包(nondeterministic wallet),其中每个密钥都是从随机数独立生成的。密钥彼此无关。这种钱包也被称为“Just a Bunch Of Keys(一堆密钥)”,简称JBOK钱包。

第二种类型是确定性钱包(deterministic wallet),其中所有的密钥都是从一个主密钥派生出来,这个主密钥即为种子(seed)。该类型钱包中所有密钥都相互关联,如果有原始种子,则可以再次生成全部密钥。确定性钱包中使用了许多不同的密钥推导方法。最常用的推导方法是使用树状结构,称为分级确定性钱包或HD钱包。

根据区块链数据的维护方式,我们可以把钱包分为

  1. 全节点(如 bitcoin-core 核心钱包),维护着全部的区块链数据(当前在50GB以上),完全去中心化,同步所有数据;
  2. SPV轻钱包(如比太),只维护与自己相关的区块链数据,基本上去中心化(要依赖比特币网络上的其他全节点),仅同步与自己相关的数据;
  3. 中心化钱包,不依赖比特币网络,只依赖自己的中心化服务器,不同步数据,所有的数据均从自己的中心化服务器中获得;

根据所使用的硬件设备,我们可以把钱包分为:

  1. 电脑钱包,钱包软件运行于桌面操作系统(Windows、MacOS、Linux等);
  2. 手机钱包,安卓、iOS等;
  3. 在线钱包(如 blockchain.info ),运行与云服务,私钥加密存储于服务器上,通过浏览器访问;
  4. 硬件钱包,运行与专门定制的硬件上,可能需要与电脑或手机配合使用;

比太钱包
HD钱包,可以用种子助记词进行备份

钱包最佳实践

助记码,基于BIP-39
BIP39 标准定义了钱包助记词和种子生成规则
HD钱包,基于BIP-32
多用途HD钱包结构,基于BIP-43
多币种和多帐户钱包,基于BIP-44

多重签名

普通钱包:A想转给X一个比特币,A只需要自己的签名(使用私钥)就可以完成交易

多重签名钱包:A想转给X一个比特币,设置了一个多重签名(ABC3个人需要2个签名才能转账),那么A想给X转账的时候需要B或C也完成签名(使用私钥)。

如果设置了多重签名,那么任何一个私钥泄露都不会损失你的数字资产。
可以大大保证资产的安全性。

UTXO 代表 Unspent Transaction Output, 表示未花费的输出。

特点:

  1. 每个UTXO都是独一无二的,就好像带有编码的钞票一样
  2. 相比钞票来说,UTXO更灵活,并没有固定面额的限制,任意数额都可以
  3. UTXO是不能分割的,只能被消耗掉
  4. 在交易前后,UTXO的数量可能增多,也可能减少
  5. 每笔交易的输入和输出都是有关系的,可以通过UTXO不停往前追溯,直到挖矿

优势

  1. UTXO具备天然的匿名性
  2. UTXO是独立的数据结构,可以更好的并行处理。
  3. 长期来看,UTXO的数据占用更小,而余额系统会越来越臃肿。
  4. UTXO的结构更不容易被篡改,每个UTXO都追根溯源,很难伪造。

HD钱包(Hierarchical Deterministic)

e4a76de6.png HD钱包根据“种子”(种子密钥)按顺序导出未来的地址,每个新地址相当于“种子+计数器”。通过这种方式,你只用一个种子就可以恢复所有的私钥和地址。

目前很多钱包都是HD钱包,只需要备份助记词即可,简化了创建新私钥和备份私钥的方式。

f35cad88.png

大家都知道,一个私钥对应一个地址,每个地址类似你的银行卡,私钥类似你的银行卡密码。

比特币也是同样的道理,如果比特币数量较大,不建议大家把所有比特币放在一个地址里。这个时候你就有几个痛点:

  1. 每次生成一个新地址都需要备份一遍私钥,操作麻烦
  2. 生成了一堆私钥,管理起来很不方便
2a6ed72d.png HD钱包可以快速方便的生成多个地址,并且不需要备份对应的私钥。你只需要一个种子密钥就可以把所有的私钥和地址全部恢复。 但是也有一个巨大的风险——种子丢了相当于丢了一堆钱包的私钥

HD钱包的优缺点

参考

  • 优点
  1. 您只需要备份一个种子(种子密钥),不需要备份私钥
  2. 可以快速生成很多地址
  3. 有效保护财务隐私
  • 缺点
  1. 种子丢失或被盗,种子下生成的所有地址都丢失或被盗

BIP32 (Bitcoin Improvement Proposal 32)
通过一个共同的种子维护 n 多私钥,种子推导私钥采用不可逆哈希算法,在需要备份钱包私钥时,只备份这个种子即可(大多数情况下的种子是通过 BIP44 生成了助记词,方便抄写),在支持 BIP32, BIP44 标准的钱包只需导入助记词即可导入全部的私钥。

符合 BIP-32/BIP-44 标准的 HD 钱包

BIP39 标准就是为了解决助记词的需求,通过随机生成 12 ~ 24 个容易记住的单词,单词序列通过 PBKDF2 与 HMAC-SHA512 函数创建出随机种子作为 BIP32 的种子
BIP32 标准的种子是一个随机 16 字节的 16 进制的字符串。如果能够适用英文单词作为助记词无疑会降低种子备份及恢复钱包难度,

BIP39-go
testify

BIP39 标准定义了钱包助记词和种子生成规则。

通过九个步骤即可生成钱包助记词和种子:
步骤 16 生成助记词
步骤 7
9 把前六步生成的助记词转化为 BIP32 种子

生成助记词

  1. 规定熵的位数必须是 32 的整数倍,所以熵的长度取值位 128 到 256 之间取 32 的整数倍的值,分别为 128, 160, 192, 224, 256;
  2. 校验和的长度为熵的长度/32 位, 所以校验和长度可为 4,5,6,7,8 位;
  3. 助记词库有 2048 个词,用 11 位可全部定位词库中所有的词,作为词的索引,故一个词用 11 位表示,助记词的个数可为 (熵+校验和)/11,值为 12,15,18,21,24
熵(bits) 校验和(bits) 熵 + 校验和 (bits) 助记词长度
128 4 132 12
160 5 165 15
192 6 198 18
224 7 231 21
256 8 264 24
  1. 生成一个长度为 128~256 位 (bits) 的随机序列(熵)
  2. 取熵哈希后的前 n 位作为校验和 (n= 熵长度/32)
  3. 随机序列 + 校验和
  4. 把步骤三得到的结果每 11 位切割
  5. 步骤四得到的每 11 位字节匹配词库的一个词
  6. 步骤五得到的结果就是助记词串
50387664.png

通过助记词生成种子
助记词由长度为 128 到 256 位的随机序列(熵)匹配词库而来,随后采用 PBKDF2 function 推导出更长的种子(seed)。生成的种子被用来生成构建 deterministic Wallet 和推导钱包密钥。

为了从助记词中生成二进制种子,BIP39 采用 PBKDF2 函数推算种子,其参数如下:

  • 助记词句子作为密码
  • “mnemonic” + passphrase 作为盐
  • 2048 作为重复计算的次数
  • HMAC-SHA512 作为随机算法
  • 512 位(64 字节)是期望得到的密钥长度
077b8287.png BIP32 标准定义了 HD 钱包的生成规则。HD 钱包中的所有层级密钥都是由根种子推导而来,通常根种子由上述步骤 BIP39 生成。所以只需通过助记词就能备份和恢复钱包,这也是 HD 钱包的缺陷,如果你的根种子泄漏,那么全部密钥随之都泄漏。

主私钥和主链码
首先是从根种子生成主密钥 (master key) 和主链码 (master chain code)
7eed3201.png
上图中根种子通过不可逆 HMAC-SHA512 算法推算出 512 位的哈希串,左 256 位是 Master Private key(m), 右 256 位是 master chain code, 通过 m 结合推导公钥的椭圆曲线算法能推导出与之对应的 264 位 master public Key (M)。chain code 作为推导下级密钥的熵。
子私钥推导
HD 钱包使用 CKD(child key derivation) 函数从父密钥(parent keys)推导子密钥(child keys),CKD 由下列三个要素做单向散列哈希(one way hash function) 。

  • 父密钥 (没有压缩过的椭圆曲线推导的私钥或公钥 ECDSA uncompressed key)
  • 链码作为熵 (chain code 256 bits)
  • 子代索引序号 (index 32 bits)
87926d89.png

索引号个数为 2 的 32 次方,每个父级密钥能推导出该数目一半的子密钥 (
索引号从 0x00 到 0x7fffffff (0 to 2 的 21 次方减 1) 会生成正常的密钥;索引号从 0x80000000 到 0xffffffff 会生成增强密钥)。CKD 采用不可逆的 HMAC-SHA512 不可逆加密算法,子密钥不能向上推导出父密钥、同时也不能水平推导出同一级的密钥。

钱包地址生成

参考

比特币地址由一个公钥生成并对应于这个公钥。地址与公钥之间的关系,如下图所示:
67ff7631.png
8d537b52.png

这里用(RIPEMD16(SHA256(PubKey))算法
RipeMD算法:针对MD4和MD5算法缺陷分析提出的算法。这些算法主要是针对摘要值得长度进行了区分
Base58Check 编码
将密钥从字节码转化成 ASCII 码,
比特币公私钥和地址各种格式前缀和 Base58Check 编码如下表 2
58fea837.png

  • 获取公钥,用 RIPEMD160(SHA256(PubKey)) 的哈希算法哈希两次。
  • 准备转哈希地址生成算法的版本
  • 通过用 SHA256(SHA256(payload)) 哈希步骤 2 的结果计算 checksum。这个 checksum 是哈希结果的头四个字节。
  • 准备 checksum 到 version+PubKeyHash 的组合。
  • 用 Base58 编码 version+PubKeyHash+checksum 的组合。

base58校验
替换钱包地址,就可以查余额了
https://blockchain.info/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa

00d296d3a4f2307fe17e2e51398f03a8dcc998e1d67f38858d
Mnemonic: toilet bottom much member impact film tornado used dinner shove aware bamboo work sustain ticket yellow stem guess story friend virtual elevator fiber pig
Master private key: xprv9s21ZrQH143K3wBFoUh64FXLnZwGr9S5v1GprnkBHzms5xNZDHnbcucE5Y9BUo1FoE45pMCzxbr3xmduC8HWpmMQEg3FLUbzV7XuxUGxqXj
Master public key: xpub661MyMwAqRbcGRFiuWE6RPU5LbmmFc9wHECRfB9nrLJqxkhhkq6rAhvhvpcv1pWdNtF8H61am1vvi5iq8NLejVo6pcvAqGeACDe7XSoZjLa
wallet address: 1LCVaumEKaxAC2htJDnbDPNotexEpLoi6g

Lambda的语法如下:
[函数对象参数](操作符重载函数参数)->返回值类型{函数体}

vector<int> iv{5, 4, 3, 2, 1};
int a = 2, b = 1;

for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;}); // (1)
for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);}); // (2)
for_each(iv.begin(), iv.end(), [&](int &x)->int{return x * (a + b);});// (3)
  • []内的参数指的是Lambda表达式可以取得的全局变量。
    (1)函数中的b就是指函数可以得到在Lambda表达式外的全局变量,如果在[]中传入=或者&的话,即是可以取得所有的外部变量,如(2)和(3)Lambda表达式,& 表示传引用
  • ()内的参数是每次调用函数时传入的参数。
  • ->后加上的是Lambda表达式返回值的类型,如(3)中返回了一个int类型的变量
& captures by reference
= captures by value

int x = 1;
auto valueLambda = [=]() { cout << x << endl; };
auto refLambda = [&]() { cout << x << endl; };
x = 13;
valueLambda();
refLambda();

This code will print
1
13

[&epsilon] capture by reference
[&] captures all variables used in the lambda by reference
[=] captures all variables used in the lambda by value
[&, epsilon] captures variables like with [&], but epsilon by value
[=, &epsilon] captures variables like with [=], but epsilon by reference

原文

每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。例:

2a5e08e4.png
  1. B的虚函数表中存放着B::foo和B::bar两个函数指针。
  2. D的虚函数表中存放的既有继承自B的虚函数B::foo,又有重写(override)了基类虚函数B::bar的D::bar,还有新增的虚函数D::quz。

构造虚函数表是由编译器完成的,因此也可以说:虚函数替换过程发生在编译时。

调用过程

4ccf6afb.png

编译器只知道pb是B*类型的指针,并不知道它指向的具体对象类型 :pb可能指向的是B的对象,也可能指向的是D的对象。

但对于“pb->bar()”,编译时能够确定的是:此处operator->的另一个参数是B::bar(因为pb是B*类型的,编译器认为bar是B::bar),而B::bar和D::bar在各自虚函数表中的偏移位置是相等的。

无论pb指向哪种类型的对象,只要能够确定被调函数在虚函数中的偏移值,待运行时,能够确定具体类型,并能找到相应vptr了,就能找出真正应该调用的函数。

多重继承

当一个类继承多个类,且多个基类都有虚函数时,子类对象中将包含多个虚函数表的指针(即多个vptr)

87fba906.png

调用
acfcada6.png

Kafka使用Scala和Java进行编写。Apache Kafka是一个快速、可扩展的、高吞吐、可容错的分布式发布订阅消息系统。Kafka具有高吞吐量、内置分区、支持数据副本和容错的特性,适合在大规模消息处理场景中使用。

Kafka 专用术语

Broker:Kafka 集群包含一个或多个服务器,这种服务器被称为 broker。
Topic:每条发布到 Kafka 集群的消息都有一个类别,这个类别被称为 Topic。(物理上不同 Topic 的消息分开存储,逻辑上一个 Topic 的消息虽然保存于一个或多个 broker 上,但用户只需指定消息的 Topic 即可生产或消费数据而不必关心数据存于何处)。

Topic:每条发布到 Kafka 集群的消息都有一个类别,这个类别被称为 Topic。(物理上不同 Topic 的消息分开存储,逻辑上一个 Topic 的消息虽然保存于一个或多个 broker 上,但用户只需指定消息的 Topic 即可生产或消费数据而不必关心数据存于何处)。

Partition:Partition 是物理上的概念,每个 Topic 包含一个或多个 Partition。

Producer:负责发布消息到 Kafka broker。

Consumer:消息消费者,向 Kafka broker 读取消息的客户端。

Consumer Group:每个 Consumer 属于一个特定的 Consumer Group(可为每个 Consumer 指定 group name,若不指定 group name 则属于默认的 group)。

windows 下安装

下载安装程序,选择自定义安装, 去掉 compass 选项,否则会卡住很久. 这是个 gui 访问界面,收费的.

mongod –dbpath D:\backup\mongoDb\stock

centos 下安装

install version: mongodb-org.x86_64 0:4.0.9-1.el7

  1. Configure the package management system (yum).
    Create a /etc/yum.repos.d/mongodb-org-4.0.repo file so that you can install MongoDB directly using yum:
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
  1. Install the MongoDB packages.
    sudo yum install -y mongodb-org

  2. Run MongoDB

  • To Use Default Directories
/var/lib/mongo (the data directory)
/var/log/mongodb (the log directory)

By default, MongoDB runs using the mongod user account.
用户和用户组都是 mongod

  • To Use Non-Default Directories
    太复杂,要改一些东西。用默认的就可以了

sudo service mongod start

随系统启动
sudo chkconfig mongod on

sudo service mongod stop
sudo service mongod restart

查看日志
sudo tail /var/log/mongodb/mongod.log

命令行

mongo

mac 下的安装

brew update
brew install mongodb
// 作为后台服务随系统自动启动
brew services start mongodb
// 不作为后台服务
mongod --config /usr/local/etc/mongod.conf
// 运行
mongod --dbpath ~zhengjun/project/mongodb/stock
// 下面输出表示启动ok
[initandlisten] waiting for connections on port 27017

配置

配置文件

配置文件位置
/etc/mongod.conf

修改
将 net:bindIp: 127.0.0.1 改为 0.0.0.0

打开认证
第一种方法:
mongod –auth –port 27017

第二种方法:使用配置文件:
security:
authorization: enabled //冒号后面需要空一格

开放 27017 端口

  1. SElinux

semanage port -a -t mongod_port_t -p tcp 27017

  1. 防火墙

firewall-cmd –zone=public –add-port=27017/tcp –permanent
firewall-cmd –reload

查看用户

#查看当前库下的用户
show users;

新建用户

先创建管理员,用来创建其他用户。 用户所属范围是数据库。
所以要先建数据库然后在数据库里面建用户。否则无法在使用的数据库里面认证用户

db.createUser(
{
user: “stock”,
pwd: “stock”,
roles: [ { role: “readWrite”, db: “stock” } ]
}
)

db.createUser({
user:"admin",
pwd:"admin",
roles:[{
role:"root",
db:"mongoTest"
}]
});

Built-In Roles(内置角色):

  1. 数据库用户角色:read、readWrite;
  2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
  3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
  4. 备份恢复角色:backup、restore;
  5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
  6. 超级用户角色:root
    // 这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)
  7. 内部角色:__system

Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问 system.profile
userAdmin:允许用户向 system.users 集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在 admin 数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的 userAdmin 权限
dbAdminAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的 dbAdmin 权限。
root:只在 admin 数据库中可用。超级账号,超级权限

删除用户

先要认证管理员,在切换数据库,在删除用户

use testDB
db.dropUser('test')

卸载

1.关闭mongod
sudo service mongod stop
2.删除安装包
sudo yum erase $(rpm -qa | grep mongodb-org)
3.删除数据文件
sudo rm -r /var/log/mongodb
sudo rm -r /var/lib/mongo

问题

  1. 启动 MongoDB 提示报警信息:“WARNING: Access control is not enabled for the database.”
    新版本的 MongDB 增加了安全性设计,推荐用户创建使用数据库时进行验证。如果用户想建立简单连接,则会提示警示信息。
    创建管理员并设置密码
>use admin
>db.createUser(
{
user: "admin", //用户名
pwd: "admin", //密码
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] //设置权限
}
)

使用

// mongo shell
mongo --host 127.0.0.1:27017
// stop mongoDb
Control+C

重启数据库服务器

mongod --auth --port 27017 --dbpath D:\MongoDB\Data\db

查询操作

查看版本

mongod -version

db version v3.6.5

查询数据库

show dbs

停止

//查看进程并kill
ps aux|grep mongod
kill -9 pid

//在客户端中使用shutdown命令
use admin
db.shutdownServer()

创建数据库

use stock
from pymongo import MongoClient
Client = MongoClient()

db = Client['test_database']

创建集合,相当于表

# 返回、创建集合
collection = db['test_collection']

创建索引

db.collection.createIndex(keys, options)

语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。
也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。

db.col.createIndex({"title":1})
db.col.createIndex({"title":1,"description":-1})

降序,唯一索引
db.collection.createIndex({a:-1},{unique:true})

options:
unique Boolean 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.

db.values.createIndex({open: 1, close: 1}, {background: true})

查看索引

查看集合索引
db.col.getIndexes()

查看集合索引大小
db.col.totalIndexSize()

删除集合所有索引
db.col.dropIndexes()

删除集合指定索引
db.col.dropIndex("索引名称")

插入

collection.insert({'code': code, 'startDate': start_date, 'endDate': end_date, 'klines': dates})

获取所有集合

list_collection_names()

更新数据

其中传入的第一个参数是你想要更新的数据,第二个是你想要更新的最新数据。其中$set部分是必要元素,如果没有会报出错误。除了$set 外还有很多其它的比如$inc,对应着不同的功能,在此先不赘述。

上面只是更新匹配到的第一个数据,同样地,也可以用 update_many()一次更新多个值。

>>>posts.update_one({'x':4},{'$set':{'x':3}})

查询

for x in mycol.find({},{ "_id": 0, "name": 1, "alexa": 1 }):
print(x)

ret = stockCodes.find({"ts_code": {"$regex": ".{}".format(market)}},
{"_id": 0, "ts_code": 1, "symbol": 1, "name": 1,"list_date":1})

最后 N 条记录

results = collection.find().sort('trade_date', pymongo.DESCENDING).limit(1)
if results:
# exist
startDateStr = results[0]['trade_date']