Title

MongoDB 主动复制

参考 http://www.lanceyan.com/tech/mongodb/mongodb_cluster_1.html
参考 MongoDB学习札记第六篇之主从复制
参考 高可用的MongoDB集群

在大数据的时代,传统的关系型数据库要能更高的服务必须要解决高并发读写. 海量数据高效存储. 高可扩展性和高可用性这些难题.不过就是因为这些问题Nosql诞生了.

NOSQL有这些优势:

大数据量,可以通过廉价服务器存储大量的数据,轻松摆脱传统mysql单表存储量级限制.

高扩展性,Nosql去掉了关系数据库的关系型特性,很容易横向扩展,摆脱了以往老是纵向扩展的诟病.

高性能,Nosql通过简单的key-value方式获取数据,非常快速.还有NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多.

灵活的数据模型,NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式.而在关系数据库里,增删字段是一件非常麻烦的事情.如果是非常大数据量的表,增加字段简直就是一个噩梦.

高可用,NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构.比如mongodb通过mongos. mongo分片就可以快速配置出高可用配置.

在nosql数据库里,大部分的查询都是键值对(key. value)的方式.MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中最像关系数据库的.支持类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引.所以这个非常方便,我们可以用sql操作MongoDB,从关系型数据库迁移过来,开发人员学习成本会大大减少.如果再对底层的sql API做一层封装,开发基本可以感觉不到mongodb和关系型数据库的区别.同样MongoDB也是号称自己能够快速搭建一个高可用可扩展的的分布式集群,网上有很多搭建的文章,在我们搭建的时候还需要查找修改很多东西,所以把自己实战的步骤记录下来以备忘.我们看看如何一步一步搭建这个东东.

一. mongodb单实例.这种配置只适合简易开发时使用,生产使用不行,因为单节点挂掉整个数据业务全挂,如下图.
虽然不能生产使用,但这个模式可以快速搭建启动,并且能够用mongodb的命令操作数据库.下面列出在linux下安装单节点mongodb的步骤

二. 主从模式.使用mysql数据库时大家广泛用到,采用双机备份后主节点挂掉了后从节点可以接替主机继续服务.所以这种模式比单节点的高可用性要好很多.
下面看一下怎么一步步搭建一个mongodb的主从复制节点:

  1. 准备两台机器 43.241.222.110 和 42.96.194.60. 43.241.222.110 当作主节点, 42.96.194.60作为从节点.
  2. 分别下载 mongodb 安装程序包.在 43.241.222.110 上建立文件夹 /home/data/mongodb,42.96.194.60 建立文件夹 /home/data/mongodb
    两台MongoDB服务器的配置文件均为 /etc/mongod.cnf

    storage:

    dbPath: "/data/home/data/mongodb"
    engine: wiredTiger
    wiredTiger:
        engineConfig:
            cacheSizeGB: 20
        collectionConfig:
            blockCompressor: snappy
    

    systemLog:

    destination: file
    path: "/var/log/mongodb/mongod.log"
    logAppend: true
    

    processManagement:

    fork: true
    

    net:

    #bindIp: 127.0.0.1,43.241.222.110,42.96.194.60  不能绑定外网访问ip,局域网的貌似可以,只能在iptable设定允许指定ip访问27017
    #bindIp: 0.0.0.0
    port: 27017
    # Enable the HTTP interface (Defaults to port 28017).
    http:
        enabled: false
    
  3. 在43.241.222.110启动mongodb主节点程序.注意后面的这个 “-master”参数,标示主节点.启动主节点

    sudo mongod -f /etc/mongod.cnf -master

  4. 在42.96.194.60启动 mongodb 从节点程序.关键配置,指定主节点ip地址和端口 -source 43.241.222.110:27017 和 标示从节点 -slave 参数.

    sudo mongod -f /etc/mongod.cnf -slave -source 43.241.222.110:27017

输出日志如下,成功!

#日志显示从节点 从主节点同步复制数据

[replslave] repl: from host:43.241.222.110:27017

配置完Mongo主从复制后开始测试主从复制.

在主节点上连接到终端:

mongo 127.0.0.1

#建立test 数据库.

use test;

往testdb表插入数据.

> db.testdb.insert({"test1":"testval1"})

查询testdb数据看看是否成功.

> db.testdb.find();
{ "_id" : ObjectId("5284e5cb1f4eb215b2ecc463"), "test1" : "testval1" }

检查从主机的数据.

mongo 127.0.0.1

查看当前数据库.

> show dbs;
  local   0.203125GB
  test    0.203125GB

use test;
db.testdb.find();
{ "_id" : ObjectId("5284e5cb1f4eb215b2ecc463"), "test1" : "testval1" }

查询后数据已经同步过来了.再看看日志,发现从主机确实从主机同步了数据.

查看服务状态

> db.printReplicationInfo();
this is a slave, printing slave replication info.
source:   43.241.222.110:27017
  syncedTo: Sun Nov 17 2013 16:04:02 GMT+0800 (CST) = -54 secs ago (-0.01hrs)

到此主从结构的mongodb搭建好了.

参考 MongoDB学习札记第六篇之主从复制

MongoDB 3.0 复制集升级操作以及坑


问题分析

进入MongoShell执行以下命令

>show dbs

提示以下错误

E QUERY Error: listDatabases failed: 
        { "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" }
at Error (<anonymous>)

查看mongo状态

> rs.status()
{ "ok" : 0, "errmsg" : "not running with --replSet", "code" : 76 }

每次登陆mongoShell后都需要执行以下命令

> rs.slaveOK()
2015-09-24T17:03:16.528+0800 E QUERY    TypeError: Object function () { return "try rs.help()"; } has no method 'slaveOK'    at (shell):1:4

参考 MongoDB 3.0 复制集升级操作以及坑 http://dev.guanghe.tv/2015/05/mongdb3-upgrade-bug.html

//查看状态

> rs.status()
{ "ok" : 0, "errmsg" : "not running with --replSet", "code" : 76 }

查看运行时配置

> use admin
switched to db admin
> db.runCommand("getCmdLineOpts")
{
    "argv" : [
        "mongod",
        "-f",
        "/etc/mongod.cnf",
        "-slave",
        "-source",
        "43.241.222.110:27017"
    ],
    "parsed" : {
        "config" : "/etc/mongod.cnf",
        "net" : {
            "http" : {
                "enabled" : false
            },
            "port" : 27017
        },
        "processManagement" : {
            "fork" : true
        },
        "slave" : true,
        "source" : "43.241.222.110:27017",
        "storage" : {
            "dbPath" : "/data/home/data/mongodb",
            "engine" : "wiredTiger",
            "wiredTiger" : {
                "collectionConfig" : {
                    "blockCompressor" : "snappy"
                },
                "engineConfig" : {
                    "cacheSizeGB" : 20
                }
            }
        },
        "systemLog" : {
            "destination" : "file",
            "logAppend" : true,
            "path" : "/var/log/mongodb/mongod.log"
        }
    },
    "ok" : 1
}

ErlangNote

Erlang 研究相关

比较好的 Erlang 开发者博客及文档

木头人 - erlang use
Erlang 中文教程Erlang中文教程,欢迎广大Erlang爱好者加入
Simple - liangjingyang 博客
Erlang 教程中文版
Erlang并发编程
Erlang并发编程-新版
erl命令和参数
元气糯米团子的Coding Blog
wudaijun’s blog

关于erlang作用域

Erlang 相关


系统预定义的宏:
1
2
3
4
5
?MODULE 表示当前模块名
?MODULE_STRING 同上,但是以字符串形式
?FILE 当前模块的文件名
?LINE 调用的当前代码行数
?MACHINE 机器名

Erlang 语言学习笔记 / Home

要知道一个节点ping通么:
net_adm:ping(Nodes).-> pong |pang
node() 返回本节点名
nodes() 返回所有其它节点名.

[pong:成功 |pang: 失败]


收藏
Erlang 与 WebSocket 之间的通讯交互
erlang 解析 xml 格式数据
Erlang 的 dict 模块函数方法介绍
用 rebar 来构建. 编译. 测试. 发布 Erlang 应用程序

Erlang不能错过的盛宴

40+行erlang代码实现一个简易分布式计算框架


dict() 弃用

1
/data/home/yzhang/CoamRunning/Erlang/ejabberd/deps/emysql/src/emysql_conn_mgr.erl:43: type dict() undefined

使用 Use dict:dict() instead of dict() #2

Use dict:dict() instead of dict() #2


Title

MongoDB 复制集

参考 MongoDB学习札记第八篇之Replica Set 实战
参考 MongoDB 3.0 复制集集群搭建及安全认证实践
参考 MongoDB 3.0 WT引擎参考配置文件
参考 MongoDB 副本集的原理. 搭建. 应用

准备三台mongo服务器 分别为 43.241.222.110 42.96.194.60 和 45.63.50.67 搭建复制集

如果对于怎么安装Mongodb还不清楚的同学可以查看我之前的学习札记

三台MongoDB服务器的配置文件均为 /etc/mongod.cnf

storage:
    dbPath: "/data/home/data/RSMongoDB"
    engine: wiredTiger
    wiredTiger:
        engineConfig:
            cacheSizeGB: 20
        collectionConfig:
            blockCompressor: snappy

systemLog:
   destination: file
   path: "/var/log/mongodb/mongod.log"
   logAppend: true

processManagement:
    fork: true

net:
    #bindIp: 127.0.0.1,43.241.222.110,42.96.194.60  不能绑定外网访问ip,局域网的貌似可以,只能在iptable设定允许指定ip访问27017
    #bindIp: 0.0.0.0
    port: 27017
    # Enable the HTTP interface (Defaults to port 28017).
    http:
        enabled: false

第一步:

在三台机器上分别运行(都要运行)

root@ubuntu:/usr/local/mongodb#mongod -f /etc/mongod.cnf --replSet CoamReSet

注意这里的 —replSet 参数指定了副本集的名称,每一个副本集都有一个唯一的名称.

等到三台机器都启动完了之后.使用mongo客户端登录其中一台mongod服务器.这里我登录到 43.241.222.110 这台机器

root@ubuntu:~# mongo

登录之后要切换到admin数据库,这样我们可以进行副本集的配置,具体怎么配置,代码如下:

> use admin
switched to db admin

定义副本集配置变量,这里的 _id:”repset” 和上面命令参数 “ –replSet repset” 要保持一样.

> config = {_id:"CoamReSet",members:[
         {_id:0,host:"43.241.222.110:27017","priority":1},
         {_id:1,host:"42.96.194.60:27017","priority":1},
         {_id:2,host:"45.63.50.67:27017","priority":0}]}

输出

{
    "_id" : "CoamReSet",
    "members" : [
        {
            "_id" : 0,
            "host" : "43.241.222.110:27017"
        },
        {
            "_id" : 1,
            "host" : "42.96.194.60:27017"
        },
        {
            "_id" : 2,
            "host" : "45.63.50.67:27017"
        }
    ]
}

初始化副本集配置

> rs.initiate(config);

输出成功

{ "ok" : 1 }

注意:新创建副本集必须要数据库没有数据,否则初始化会提示以下错误:

{
    "ok" : 0,
    "errmsg" : "'42.96.194.60:27017' has data already, cannot initiate set.",
    "code" : 110
}

先定义 config 的配置信息, 然后通过 rs.initiate(config) 方法,将配置信息初始化.这两个步骤完成之后就表示我们的副本集配置信息初始化完成了,在这个CoamReSet的副本集中我们定义了三台主机(注意在定义配置信息的时候指定的 _id 必须和我们启动mongod的时候指定的参数 —replSet 这个参数的值是一样的.)

过一会,mongodb就会帮我们选举出Primary节点和Secondary节点了.那在mongo客户端,我们可以通过 rs.status() 来查看副本集的状态信息

CoamReSet:SECONDARY> rs.status()
{
    "set" : "CoamReSet",
    "date" : ISODate("2015-10-01T09:45:34.924Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 0,
            "name" : "43.241.222.110:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 167,
            "optime" : Timestamp(1443692712, 1),
            "optimeDate" : ISODate("2015-10-01T09:45:12Z"),
            "electionTime" : Timestamp(1443692715, 1),
            "electionDate" : ISODate("2015-10-01T09:45:15Z"),
            "configVersion" : 1,
            "self" : true
        },
        {
            "_id" : 1,
            "name" : "42.96.194.60:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 21,
            "optime" : Timestamp(1443692712, 1),
            "optimeDate" : ISODate("2015-10-01T09:45:12Z"),
            "lastHeartbeat" : ISODate("2015-10-01T09:45:33.166Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T09:45:33.564Z"),
            "pingMs" : 16,
            "configVersion" : 1
        },
        {
            "_id" : 2,
            "name" : "45.63.50.67:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 21,
            "optime" : Timestamp(1443692712, 1),
            "optimeDate" : ISODate("2015-10-01T09:45:12Z"),
            "lastHeartbeat" : ISODate("2015-10-01T09:45:32.949Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T09:45:33.973Z"),
            "pingMs" : 183,
            "configVersion" : 1
        }
    ],
    "ok" : 1
}

其中name表示我么你的主机, health表示主机是否健康(0/1) , state(主节点(1)还是从节点(2),或者是不可达节点)

如果上面信息正常显示出来说明整个副本集群已经建立起来了.这时候我们来验证一下是否是真的能够自动备份数据,是否能够自动从失败中恢复,自动选举新的Primary节点.
这个实验我们这样来做:

先往 Primary 节点(43.241.222.110)插入数据,在 42.96.194.60 和 45.63.50.67 两台 Secondary 节点中查询数据,验证是否能够正常的同步机器.

先往 Primary 节点(43.241.222.110)插入数据

CoamReSet:PRIMARY> use test
switched to db test
CoamReSet:PRIMARY> show collections
CoamReSet:PRIMARY> db.guids.insert({"name":"replica set","author":"webinglin"})
WriteResult({ "nInserted" : 1 })
CoamReSet:PRIMARY> exit
bye

在 45.63.50.67 Secondary 节点中查询数据,验证是否能够正常的同步机器.

root@ubuntu:~# mongo --host 45.63.50.67
MongoDB shell version: 3.0.3
connecting to: 45.63.50.67:27017/test
Server has startup warnings:
2015-06-09T17:03:27.744-0700 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not re                                      commended.
2015-06-09T17:03:27.744-0700 I CONTROL  [initandlisten]
2015-06-09T17:03:27.745-0700 I CONTROL  [initandlisten]
2015-06-09T17:03:27.745-0700 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2015-06-09T17:03:27.745-0700 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2015-06-09T17:03:27.745-0700 I CONTROL  [initandlisten]
CoamReSet:SECONDARY> show dbs
2015-06-09T17:13:49.138-0700 E QUERY    Error: listDatabases failed:{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" }
    at Error (<anonymous>)
    at Mongo.getDBs (src/mongo/shell/mongo.js:47:15)
    at shellHelper.show (src/mongo/shell/utils.js:630:33)
    at shellHelper (src/mongo/shell/utils.js:524:36)
    at (shellhelp2):1:1 at src/mongo/shell/mongo.js:47
CoamReSet:SECONDARY> use test
switched to db test
CoamReSet:SECONDARY> db.guids.find()
Error: error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
CoamReSet:SECONDARY> rs.slaveOk()
CoamReSet:SECONDARY> rs.slaveOk()
CoamReSet:SECONDARY> db.guids.find()
{ "_id" : ObjectId("557780ebd147e9391020860d"), "name" : "replica set", "author" : "webinglin" }
CoamReSet:SECONDARY> show collections()
2015-06-09T17:14:24.219-0700 E QUERY    Error: don't know how to show [collections()]
    at Error (<anonymous>)
    at shellHelper.show (src/mongo/shell/utils.js:733:11)
    at shellHelper (src/mongo/shell/utils.js:524:36)
    at (shellhelp2):1:1 at src/mongo/shell/utils.js:733
CoamReSet:SECONDARY> show collections
guids
system.indexes
CoamReSet:SECONDARY> exit
bye

在 42.96.194.60 Secondary 节点中查询数据,验证是否能够正常的同步机器.

root@ubuntu:~# mongo --host 42.96.194.60
MongoDB shell version: 3.0.3
connecting to: 42.96.194.60:27017/test
Server has startup warnings:
2015-06-09T17:03:11.647-0700 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not re                                      commended.
2015-06-09T17:03:11.647-0700 I CONTROL  [initandlisten]
2015-06-09T17:03:11.647-0700 I CONTROL  [initandlisten]
2015-06-09T17:03:11.648-0700 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2015-06-09T17:03:11.648-0700 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2015-06-09T17:03:11.648-0700 I CONTROL  [initandlisten]
CoamReSet:SECONDARY> rs.slaveOk()
CoamReSet:SECONDARY> show dbs
local  1.078GB
test   0.078GB
CoamReSet:SECONDARY> use test
switched to db test
CoamReSet:SECONDARY> show collections
guids
system.indexes
CoamReSet:SECONDARY> db.guids.find()
{ "_id" : ObjectId("557780ebd147e9391020860d"), "name" : "replica set", "author" : "webinglin" }
CoamReSet:SECONDARY> exit
bye

至此,整个验证过程说明了我们集群部署是成功的.数据能够正常同步了.
那么接下来我们还要验证另一种情况,Primary异常终止之后(43.241.222.110),另外两个Secondary节点会不会自动选举出新的Primary节点呢?
这个实验我们这样处理: 将 43.241.222.110 机器的mongod服务停止掉,然后再来连接 42.96.194.60 或者 45.63.50.67 任意一台机器,通过 rs.status() 查看集群状态.

在Primary节点(43.241.222.110)通过 ps -e | grep mongod 查看mongod服务是否开启,然后通过 killall mongod 或者 kill -15 <进程号> 来杀死mongod进程

root@ubuntu:~# ps -e | grep mongod
 3279 pts/0    00:00:19 mongod
root@ubuntu:~# killall mongod

登陆从节点 42.96.194.60 ,查看mongo服务器状态

root@ubuntu:~# mongo --host 42.96.194.60
MongoDB shell version: 3.0.3
connecting to: 42.96.194.60:27017/test
Server has startup warnings:
2015-06-09T17:03:11.647-0700 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2015-06-09T17:03:11.647-0700 I CONTROL  [initandlisten]
2015-06-09T17:03:11.647-0700 I CONTROL  [initandlisten]
2015-06-09T17:03:11.648-0700 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2015-06-09T17:03:11.648-0700 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2015-06-09T17:03:11.648-0700 I CONTROL  [initandlisten]
CoamReSet:SECONDARY> rs.status()
{
    "set" : "CoamReSet",
    "date" : ISODate("2015-10-01T10:09:57.981Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 0,
            "name" : "43.241.222.110:27017",
            "health" : 0,
            "state" : 8,
            "stateStr" : "(not reachable/healthy)",
            "uptime" : 0,
            "optime" : Timestamp(0, 0),
            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
            "lastHeartbeat" : ISODate("2015-10-01T10:09:56.226Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T10:07:54.850Z"),
            "pingMs" : 18,
            "lastHeartbeatMessage" : "Failed attempt to connect to 43.241.222.110:27017; couldn't connect to server 43.241.222.110:27017 (43.241.222.110), connection attempt failed",            "configVersion" : -1
        },
        {
            "_id" : 1,
            "name" : "42.96.194.60:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 1577,
            "optime" : Timestamp(1443693679, 1),
            "optimeDate" : ISODate("2015-10-01T10:01:19Z"),
            "electionTime" : Timestamp(1443694079, 1),
            "electionDate" : ISODate("2015-10-01T10:07:59Z"),
            "configVersion" : 1,
            "self" : true
        },
        {
            "_id" : 2,
            "name" : "45.63.50.67:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 1481,
            "optime" : Timestamp(1443693679, 1),
            "optimeDate" : ISODate("2015-10-01T10:01:19Z"),
            "lastHeartbeat" : ISODate("2015-10-01T10:09:56.891Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T10:09:57.259Z"),
            "pingMs" : 440,
            "configVersion" : 1
        }
    ],
    "ok" : 1
}
CoamReSet:SECONDARY> exit
bye

通过上面这段代码的观察,我们发现,当把原来的Primary节点停止掉后(43.241.222.110停止), 那么整个mongodb的副本集群会重新选举出新的Primary节点( 42.96.194.60 机器)

为了验证一下新选举的Primary是否正常,我们再次验证一把数据的同步情况,先连接到 42.96.194.60 主节点,将原来的数据删掉,再到 45.63.50.67 SECONDARY 进行验证,数据是否也被删除

连接到 42.96.194.60 主节点,将原来的数据删掉

root@ubuntu:~# mongo --host 42.96.194.60
CoamReSet:PRIMARY> use test
switched to db test
CoamReSet:PRIMARY> show collections
guids
CoamReSet:PRIMARY> db.guids.find()
{ "_id" : ObjectId("560d03099548a3e5bb8b03bf"), "name" : "replica set", "author" : "webinglin" }
{ "_id" : ObjectId("560d046f9548a3e5bb8b03c0"), "name" : "zhang", "author" : "yafei..." }
CoamReSet:PRIMARY> db.guids.remove({name:"zhang"})
WriteResult({ "nRemoved" : 1 })
CoamReSet:PRIMARY> db.guids.find()
{ "_id" : ObjectId("560d03099548a3e5bb8b03bf"), "name" : "replica set", "author" : "webinglin" }
CoamReSet:PRIMARY> exit
bye

再到 45.63.50.67 SECONDARY 进行验证,数据是否也被删除

root@ubuntu:~# mongo --host 45.63.50.67
CoamReSet:SECONDARY> rs.slaveOk()
CoamReSet:SECONDARY> db.guids.find()
{ "_id" : ObjectId("557780ebd147e9391020860d"), "name" : "replica set", "author" : "webinglin" }
CoamReSet:SECONDARY> exit
bye

实践后发现,先选举的Primary节点也正常工作.我们的整个Mongodb副本集群测试完成.

动态添加节点,删除节点.

在开始这个实验之前,先把 43.241.222.110 的机器重新启动,然后用mongo客户端连到 43.241.222.110 进行验证数据是否也同步了.
登录 43.241.222.110 之后,我们发现数据也同步了,然后43.241.222.110节点变成了 Secondary 节点了.

root@ubuntu:~# mongo
CoamReSet:SECONDARY> rs.slaveOk()
CoamReSet:SECONDARY> show dbs
local   0.000GB
syData  0.000GB
test    0.000GB
CoamReSet:SECONDARY> use test
switched to db test
CoamReSet:SECONDARY> show collections
guids
CoamReSet:SECONDARY> db.guids.find()
{ "_id" : ObjectId("560d03099548a3e5bb8b03bf"), "name" : "replica set", "author" : "webinglin" }
CoamReSet:SECONDARY> rs.status()
{
    "set" : "CoamReSet",
    "date" : ISODate("2015-10-01T10:21:53.366Z"),
    "myState" : 2,
    "syncingTo" : "42.96.194.60:27017",
    "members" : [
        {
            "_id" : 0,
            "name" : "43.241.222.110:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 68,
            "optime" : Timestamp(1443694583, 1),
            "optimeDate" : ISODate("2015-10-01T10:16:23Z"),
            "syncingTo" : "42.96.194.60:27017",
            "configVersion" : 1,
            "self" : true
        },
        {
            "_id" : 1,
            "name" : "42.96.194.60:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 66,
            "optime" : Timestamp(1443694583, 1),
            "optimeDate" : ISODate("2015-10-01T10:16:23Z"),
            "lastHeartbeat" : ISODate("2015-10-01T10:21:53.026Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T10:21:52.588Z"),
            "pingMs" : 16,
            "electionTime" : Timestamp(1443694079, 1),
            "electionDate" : ISODate("2015-10-01T10:07:59Z"),
            "configVersion" : 1
        },
        {
            "_id" : 2,
            "name" : "45.63.50.67:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 66,
            "optime" : Timestamp(1443694583, 1),
            "optimeDate" : ISODate("2015-10-01T10:16:23Z"),
            "lastHeartbeat" : ISODate("2015-10-01T10:21:51.818Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T10:21:53.006Z"),
            "pingMs" : 311,
            "syncingTo" : "42.96.194.60:27017",
            "configVersion" : 1
        }
    ],
    "ok" : 1
}
CoamReSet:SECONDARY> exit
bye

登录到 42.96.194.60 Primary 节点,通过 rs.remove() 方法来删除副本集中的某一个节点,这里我们还是将 43.241.222.110 删除.删除之后我们还往 42.96.194.60 主节点中加入数据.

CoamReSet:PRIMARY> rs.remove("43.241.222.110:27017")
{ "ok" : 1 }
CoamReSet:PRIMARY> rs.status()
{
    "set" : "CoamReSet",
    "date" : ISODate("2015-10-01T10:24:35.061Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 1,
            "name" : "42.96.194.60:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 2455,
            "optime" : Timestamp(1443695065, 1),
            "optimeDate" : ISODate("2015-10-01T10:24:25Z"),
            "electionTime" : Timestamp(1443694079, 1),
            "electionDate" : ISODate("2015-10-01T10:07:59Z"),
            "configVersion" : 2,
            "self" : true
        },
        {
            "_id" : 2,
            "name" : "45.63.50.67:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 2358,
            "optime" : Timestamp(1443695065, 1),
            "optimeDate" : ISODate("2015-10-01T10:24:25Z"),
            "lastHeartbeat" : ISODate("2015-10-01T10:24:33.256Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T10:24:34.102Z"),
            "pingMs" : 334,
            "configVersion" : 2
        }
    ],
    "ok" : 1
}
CoamReSet:PRIMARY> db.guids.find()
{ "_id" : ObjectId("560d03099548a3e5bb8b03bf"), "name" : "replica set", "author" : "webinglin" }
CoamReSet:PRIMARY> db.guids.insert({"name":"remove one node dync"})
WriteResult({ "nInserted" : 1 })
CoamReSet:PRIMARY> db.guids.find()
{ "_id" : ObjectId("560d03099548a3e5bb8b03bf"), "name" : "replica set", "author" : "webinglin" }
{ "_id" : ObjectId("560d0a1d7d9deef6a0890b1f"), "name" : "remove one node dync" }
CoamReSet:PRIMARY> exit
bye

删除 43.241.222.110 节点后,我们往 Primary 节点中加入了新的数据,然后先不要将 43.241.222.110 的 mongod 服务停掉,我们通过mongo连接到 43.241.222.110 的mongod服务来查看数据

root@ubuntu:~# mongo --host 43.241.222.110
> db.guids.find()
{ "_id" : ObjectId("560d03099548a3e5bb8b03bf"), "name" : "replica set", "author" : "webinglin" }
> exit
bye

实验结果可以知道,我们在 45.63.50.67 新加入的数据 {name:”remove one node dync”} 并没有同步到43.241.222.110(已从副本集中删除).

为了让实验结果更加确切,我们查看 43.241.222.110 是否有同步了数据:

root@ubuntu:~# mongo –host 45.63.50.67
CoamReSet:SECONDARY> db.guids.find()
{ “_id” : ObjectId(“557780ebd147e9391020860d”), “name” : “replica set”, “author” : “webinglin” }
{ “_id” : ObjectId(“557785bcbb56172c8e069341”), “name” : “remove one node dync” }
CoamReSet:SECONDARY> exit
bye

实验数据可以看到, 45.63.50.67 同步了在 42.96.194.60 主节点中新增的文档 {“name”:”remove one node dync”},这样就证明了动态删除副本集中的某一个节点的实验成功了.那怎么动态添加节点到副本集中呢?

原理是一样的,但是调用的方法变成了 rs.add(“43.241.222.110:27017”)

CoamReSet:PRIMARY> rs.add("43.241.222.110:27017");
{ "ok" : 1 }
CoamReSet:PRIMARY> rs.status()
{
    "set" : "CoamReSet",
    "date" : ISODate("2015-10-01T10:32:45.284Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 1,
            "name" : "42.96.194.60:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 2945,
            "optime" : Timestamp(1443695560, 1),
            "optimeDate" : ISODate("2015-10-01T10:32:40Z"),
            "electionTime" : Timestamp(1443694079, 1),
            "electionDate" : ISODate("2015-10-01T10:07:59Z"),
            "configVersion" : 3,
            "self" : true
        },
        {
            "_id" : 2,
            "name" : "45.63.50.67:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 2849,
            "optime" : Timestamp(1443695560, 1),
            "optimeDate" : ISODate("2015-10-01T10:32:40Z"),
            "lastHeartbeat" : ISODate("2015-10-01T10:32:43.660Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T10:32:44.079Z"),
            "pingMs" : 452,
            "syncingTo" : "42.96.194.60:27017",
            "configVersion" : 2
        },
        {
            "_id" : 3,
            "name" : "43.241.222.110:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 2,
            "optime" : Timestamp(1443695560, 1),
            "optimeDate" : ISODate("2015-10-01T10:32:40Z"),
            "lastHeartbeat" : ISODate("2015-10-01T10:32:44.739Z"),
            "lastHeartbeatRecv" : ISODate("2015-10-01T10:32:43.300Z"),
            "pingMs" : 16,
            "syncingTo" : "42.96.194.60:27017",
            "configVersion" : 3
        }
    ],
    "ok" : 1
}
CoamReSet:PRIMARY> exit
bye

在rs.status()返回的结果中可以看到,43.241.222.110 节点已经成功加入副本集中了.加入之后,理论上应该会把在 43.241.222.110 主节点加入的数据同步过来,刚才删除之后是不会同步的.那这时候重新加入副本集,应该是要同步的.下面是实验结果:

root@ubuntu:~# mongo
CoamReSet:SECONDARY> db.guids.find()
{ "_id" : ObjectId("560d03099548a3e5bb8b03bf"), "name" : "replica set", "author" : "webinglin" }
{ "_id" : ObjectId("560d0a1d7d9deef6a0890b1f"), "name" : "remove one node dync" }
CoamReSet:SECONDARY> exit
bye

实验结果显示,动态添加操作也正常.动态的将 43.241.222.110 节点加入到副本集中能够保证数据同步成功.


注意

在调用 rs.add(“host:ip”) 或者 rs.remove(“host:ip”) 的时候,必须要在 Primary 节点中进行.

add方法可以加入一个document对象,这样就可以在指定具体的Secondary节点的更多的设置项了,比如指定为priority: 0 或 priority: 0,hidden: true 或 priority:0,hidden:true,arbiterOnly:true

{
  _id: <int>,
  host: <string>,
  arbiterOnly: <boolean>,
  buildIndexes: <boolean>,
  hidden: <boolean>,
  priority: <number>,
  tags: <document>,
  slaveDelay: <int>,
  votes: <number>
}

怎么对副本集进行权限验证,参考主从复制的安全部分,也是通过openssl来生成keyfile,然后再启动mongod的时候指定keyFile来设置安全的


也可以在三个主机的复制集添加以下配置

replication:
##oplog大小
 oplogSizeMB: 20
##复制集名称
 replSetName: CoamReSet

复制集优先级问题

默认设定节点 43.241.222.110 为Primary主节点,由于初始配置中没有设定,于是在主节点服务器重启后 43.241.222.110 自动切换成 从节点,而 42.96.194.60 切换成了主节点导致应用程序连接错误
于是在当前主节点 43.241.222.110 通过命令行手动切换主节点到 43.241.222.110

CoamReSet:PRIMARY> rs.status()
{
        "set" : "CoamReSet",
        "date" : ISODate("2015-10-09T11:28:28.585Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 1,
                        "name" : "42.96.194.60:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 614570,
                        "optime" : Timestamp(1444378212, 1),
                        "optimeDate" : ISODate("2015-10-09T08:10:12Z"),
                        "electionTime" : Timestamp(1444378334, 1),
                        "electionDate" : ISODate("2015-10-09T08:12:14Z"),
                        "configVersion" : 3,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "45.63.50.67:27017",
                        "health" : 0,
                        "state" : 8,
                        "stateStr" : "(not reachable/healthy)",
                        "uptime" : 0,
                        "optime" : Timestamp(0, 0),
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2015-10-09T11:28:27.754Z"),
                        "lastHeartbeatRecv" : ISODate("2015-10-06T08:52:51.239Z"),
                        "pingMs" : 406,
                        "lastHeartbeatMessage" : "Failed attempt to connect to 45.63.50.67:27017; couldn't connect to server 45.63.50.67:27017 (45.63.50.67), connection attempt failed",
                        "configVersion" : -1
                },
                {
                        "_id" : 3,
                        "name" : "43.241.222.110:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 90994,
                        "optime" : Timestamp(1444378212, 1),
                        "optimeDate" : ISODate("2015-10-09T08:10:12Z"),
                        "lastHeartbeat" : ISODate("2015-10-09T11:28:27.532Z"),
                        "lastHeartbeatRecv" : ISODate("2015-10-09T11:28:27.299Z"),
                        "pingMs" : 15,
                        "configVersion" : 3
                }
        ],
        "ok" : 1
}

CoamReSet:PRIMARY> config = rs.conf()
{
        "_id" : "CoamReSet",
        "version" : 3,
        "members" : [
                {
                        "_id" : 1,
                        "host" : "42.96.194.60:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : 0,
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "45.63.50.67:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : 0,
                        "votes" : 1
                },
                {
                        "_id" : 3,
                        "host" : "43.241.222.110:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : 0,
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatTimeoutSecs" : 10,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                }
        }
}

设置第一个节点 42.96.194.60 优先级为1,第二个节点 45.63.50.67 优先级为0,第三个节点 43.241.222.110 优先级为2;

CoamReSet:PRIMARY> config.members[0].priority = 1
1
CoamReSet:PRIMARY> config.members[1].priority = 0
0
CoamReSet:PRIMARY> config.members[2].priority = 2
2
CoamReSet:PRIMARY> rs.reconfig(config)
{ "ok" : 1 }
CoamReSet:PRIMARY> rs.status()
{
        "set" : "CoamReSet",
        "date" : ISODate("2015-10-09T12:03:37.679Z"),
        "myState" : 2,
        "syncingTo" : "43.241.222.110:27017",
        "members" : [
                {
                        "_id" : 1,
                        "name" : "42.96.194.60:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 616679,
                        "optime" : Timestamp(1444392119, 1),
                        "optimeDate" : ISODate("2015-10-09T12:01:59Z"),
                        "syncingTo" : "43.241.222.110:27017",
                        "configVersion" : 5,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "45.63.50.67:27017",
                        "health" : 0,
                        "state" : 8,
                        "stateStr" : "(not reachable/healthy)",
                        "uptime" : 0,
                        "optime" : Timestamp(0, 0),
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2015-10-09T12:03:35.875Z"),
                        "lastHeartbeatRecv" : ISODate("2015-10-06T08:52:51.239Z"),
                        "pingMs" : 406,
                        "lastHeartbeatMessage" : "Failed attempt to connect to 45.63.50.67:27017; couldn't connect to server 45.63.50.67:27017 (45.63.50.67), connection attempt failed",
                        "configVersion" : -1
                },
                {
                        "_id" : 3,
                        "name" : "43.241.222.110:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 93103,
                        "optime" : Timestamp(1444392119, 1),
                        "optimeDate" : ISODate("2015-10-09T12:01:59Z"),
                        "lastHeartbeat" : ISODate("2015-10-09T12:03:35.817Z"),
                        "lastHeartbeatRecv" : ISODate("2015-10-09T12:03:36.764Z"),
                        "pingMs" : 17,
                        "electionTime" : Timestamp(1444390463, 1),
                        "electionDate" : ISODate("2015-10-09T11:34:23Z"),
                        "configVersion" : 5
                }
        ],
        "ok" : 1
}

可以看到 43.241.222.110 已经成功切换成主节点了
关闭主节点 43.241.222.110 后,发现两个从节点没有自动切换成主节点,相当于关闭了 MongoDB 复制集功能
MongoDB RS优先级设置
http://docs.mongodb.org/manual/tutorial/force-member-to-be-primary/


问题解决

主节点 43.241.222.110 服务意外停止后,在从节点 42.96.194.60 修改优先级出现如下错误

1
2
3
4
5
6
7
8
9
10
CoamReSet:RECOVERING> config = rs.conf();
CoamReSet:RECOVERING> config.members[2].priority = 0;
CoamReSet:RECOVERING> rs.reconfig(config);
{
"ok" : 0,
"errmsg" : "replSetReconfig should only be run on PRIMARY, but my state is RECOVERING; use the \"force\" argument to override",
"code" : 10107
}
CoamReSet:RECOVERING> rs.reconfig(config,{force: true});
{ "ok" : 1 }

参考列表

高可用的MongoDB集群
MongoDB Replica Set 详细安装文档
rs.reconfig()

XMPPNote

关于 XMPP 协议

Jabber 是著名的即时通讯服务服务器,它是一个自由开源软件,能让用户自己架即时通讯服务器,可以在Internet上应用,也可以在局域网中应用.
XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测.它在促进服务器之间的准即时操作.
这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同.XMPP的技术来自于Jabber,其实它是 Jabber的核心协定,所以XMPP有时被误称为Jabber协议.
Jabber是一个基于XMPP协议的IM应用,除Jabber之外,XMPP还支持很多应用.

EjabberdNote

Ejabberd Note

Ejabberd Xamp 服务器搭建

[ejabberd官方文档] (http://docs.ejabberd.im/)
ejabberd github
Ejabberd2 中文翻译文档

Ejabberd - configuration 配置文件文档
Ejabberd XEP-* 支持列表

优秀 Ejabberd 开发者博客

木头人 ejabberd Modules development
元气糯米团子的Coding Blog
Ejabberd配置模块分析
zlx_star - Ejabberd 启动过程

收藏博客文章

Worktile中的实时消息推送服务实现


常见的 Ejabberd 服务器管理命令

1
2
3
4
5
6
7
8
9
10
sudo ejabberdctl live    # 调试 ejabberd 配置文件并打印日志信息
sudo ejabberdctl start # 启动 ejabberd 服务器
sudo ejabberdctl restart # 重启 ejabberd 服务器
#sudo ejabberdctl status # 查看 ejabberd 服务器运行状态
sudo ejabberdctl debug # 查看 ejabberd 服务器运行状态
ejabberdctl register zyfmix coam.co ****** # 添加注册新用户

ejabberdctl modules_update_specs # 更新所有模块
ejabberdctl modules_available # 查看可用安装模块
ejabberdctl module_install mod_mam # 安装模块 mod_mam

木头人 - ejabberd install
编译Ejabberd遇到的问题


XMPP协议的命名空间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
jabber:iq:private   -- 私有数据存储,用于本地用户私人设置信息,比如用户备注等.
jabber:iq:conference -- 一般会议,用于多个用户之间的信息共享
jabber:x:encrypted -- 加密的消息,用于发送加密消息
jabber:x:expire -- 消息终止
jabber:iq:time -- 客户端时间
jabber:iq:auth -- 简单用户认证,一般用于服务器之间或者服务器和客户端之间的认证
jabber:x:roster -- 内部花名册
jabber:x:signed -- 标记的在线状态
jabber:iq:search -- 用户数据库查询,用于向服务器发送查询请求
jabber:iq:register -- 注册请求,用于用户注册相关信息
jabber:x:iq:roster -- 花名册管理
jabber:x:conference -- 会议邀请,用于向参加会议用户发送开会通知
jabber:x:event -- 消息事件
vcard-temp -- 临时的vCard,用于设置用户的头像以及昵称等


模块化

只装在你想要的模块.
在你自己的自定义模块扩展ejabberd.
安全性
支持c2s和s2s连接的SASL和STARTTLS.
支持s2s连接的STARTTLS和Dialback.
可通过HTTPS安全访问的Web管理.
数据库
快速布署的内部数据库(Mnesia).
原生的MySQL支持.
原生的PostgreSQL支持.
支持ODBC数据存储.
支持Microsoft SQL Server.
验证
内部验证.
PAM, LDAP 和 ODBC.
外部验证脚本.
其他
支持虚拟主机.
XML流压缩 (XEP-0138).
统计 (XEP-0039).
支持IPv6的c2s和s2s连接.
支持集群和HTML日志的多用户聊天模块.
基于用户vCards的用户目录.
支持基于PubSub的个人事件的发行-订阅组件.
支持web客户端: HTTP轮询和HTTP绑定(BOSH)服务.
IRC网关.
组件支持: 安装特定网关之后和外部网络的接口,如 AIM, ICQ 和 MSN.

模块一览

下表列出ejabberd里的所有模块.

模块 功能 依赖
mod_adhoc 特定命令 (XEP-0050)

mod_announce 管理公告
推荐 mod_adhoc
mod_caps 实体能力 (XEP-0115)

mod_configure 使用特定命令配置服务器
mod_adhoc
mod_disco 服务发现 (XEP-0030)

mod_echo XMPP节回音

mod_irc IRC网关
mod_last 最后活动 (XEP-0012)

mod_last_odbc 最后活动 (XEP-0012)
支持的数据库 (*)
mod_muc 多用户聊天 (XEP-0045)

mod_muc_log 多用户聊天室记录
mod_muc
mod_offline 离线消息存储 (XEP-0160)

mod_offline_odbc 离线消息存储 (XEP-0160)
支持的数据库 (*)
mod_ping XMPP Ping 和定期保持连接 (XEP-0199)

mod_privacy 禁止通讯 (XMPP IM)

mod_privacy_odbc 禁止通讯 ((XMPP IM)
支持的数据库 (*)
mod_private 私有XML存储 (XEP-0049)

mod_private_odbc 私有XML存储 (XEP-0049)
支持的数据库 (*)
mod_proxy65 SOCKS5字节流 (XEP-0065)

mod_pubsub 发行-订阅 (XEP-0060), PEP (XEP-0163)
mod_caps
mod_pubsub_odbc 发行-订阅 (XEP-0060), PEP (XEP-0163)
支持的数据库 (*) 和 mod_caps
mod_register I带内注册 (XEP-0077)

mod_roster 名册管理 (XMPP IM)

mod_roster_odbc 名册管理 (XMPP IM)
支持的数据库 (*)
mod_service_log 拷贝用户消息到日志服务

mod_shared_roster 共享名册管理
mod_roster 或 mod_roster_odbc
mod_sic Server IP检查 (XEP-0279)

mod_stats 统计信息收集 (XEP-0039)

mod_time 实体时间 (XEP-0202)

mod_vcard 电子名片 (XEP-0054)

mod_vcard_ldap 电子名片 (XEP-0054)
LDAP服务器
mod_vcard_odbc 电子名片 (XEP-0054)
支持的数据库 (*)
mod_vcard_xupdate 基于vCard的头像 (XEP-0153)
mod_vcard 或 mod_vcard_odbc
mod_version 软件版本 (XEP-0092)


Ejabberd 修改列表

~/src/ejabberd_oauth.erl // 修改 301 问题 参见 https://github.com/barabansheg/ejabberd/blob/master/src/ejabberd_oauth.erl

~/src/mod_sunshine.erl // 增加,测试 参见 http://developerworks.github.io/2014/09/18/ejabberd-modules-presence-storms/

Title

Composer

Composer 中文网
使用GitHub. Composer. Packagist管理公开的PHP包(Step By Step)

Ubuntu 安装 Composer

Composer

  • 全局安装
1
2
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

Packagist / Composer 中国全量镜像

1
composer config -g repositories.packagist composer http://packagist.phpcomposer.com

##

1
2
sudo composer clearcache  # 清除缓存
sudo rm -r ~/.composer/cache # 清除缓存

不编辑 composer.json 的情况下安装库

1
composer require "foo/bar:1.0.0"

强制从 github 克隆源代码

1
composer update symfony/yaml --prefer-source

安装 Github phpMyAdmin 执行安装命令

1
2
cd phpMyAdmin
sudo composer install

出现如下错误

1
[Composer\Downloader\TransportException] Your configuration does not allow connection to http://packagist.com. See https://getcomposer.org/doc/06-config.md#secure-http for details
1
2
3
4
5
cd ~/.composer/config.json

"config": {
"secure-http": false
}

使用Composer安装Laravel项目

Title

letsencrypt 证书签发机构

官网
GitHub - letsencrypt/letsencrypt

letscrypt 证书签发及使用问题

1
2
3
$ git clone https://github.com/letsencrypt/letsencrypt.git
$ cd letsencrypt
$ sudo ./letsencrypt-auto --help

首先停止服务器正在运行的 nginx 服务器

  • To obtain a cert using a “standalone” webserver (you may need to temporarily stop your exising webserver) for example.com and www.example.com:

以下商运相关

  • # .coopens.com Certificate # sy.include.d/server_ssl_coopens_com.conf*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
./letsencrypt-auto certonly --standalone --email admin@coopens.com \
-d coopens.com \
-d www.coopens.com \
-d 56.coopens.com \
-d app.coopens.com \
-d gp.coopens.com \
-d dp.coopens.com \
-d cp.coopens.com \
-d lp.coopens.com \
-d pp.coopens.com \
-d mp.coopens.com \
-d im.coopens.com \
-d sns.coopens.com \
-d blog.coopens.com \
-d lw.coopens.com \
-d ma.coopens.com \
-d mirror.coopens.com \
-d open.coopens.com \
-d pay.coopens.com \
-d forum.coopens.com \
-d mas.coopens.com \
-d was.coopens.com \
-d gps.coopens.com
  • # .nocs.com Certificate # sy.include.d/server_ssl_nocs_cn.conf*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
./letsencrypt-auto certonly --standalone --email admin@nocs.cn \
-d nocs.cn \
-d www.nocs.cn \
-d 56.nocs.cn \
-d app.nocs.cn \
-d gp.nocs.cn \
-d dp.nocs.cn \
-d cp.nocs.cn \
-d lp.nocs.cn \
-d pp.nocs.cn \
-d mp.nocs.cn \
-d im.nocs.cn \
-d sns.nocs.cn \
-d blog.nocs.cn \
-d lw.nocs.cn \
-d ma.nocs.cn \
-d mirror.nocs.cn \
-d open.nocs.cn \
-d pay.nocs.cn \
-d forum.nocs.cn \
-d mas.nocs.cn \
-d was.nocs.cn \
-d gps.nocs.cn
  • # .coam.com Certificate # sy.include.d/server_ssl_coam_co.conf*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
./letsencrypt-auto certonly --standalone --email admin@coam.co \
-d coam.co \
-d www.coam.co \
-d 56.coam.co \
-d app.coam.co \
-d gp.coam.co \
-d dp.coam.co \
-d cp.coam.co \
-d lp.coam.co \
-d pp.coam.co \
-d mp.coam.co \
-d im.coam.co \
-d sns.coam.co \
-d blog.coam.co \
-d lw.coam.co \
-d ma.coam.co \
-d mirror.coam.co \
-d open.coam.co \
-d pay.coam.co \
-d forum.coam.co \
-d mas.coam.co \
-d was.coam.co \
-d gps.coam.co
  • # .syam.com Certificate # sy.include.d/server_ssl_syam_cc.conf*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
./letsencrypt-auto certonly --standalone --email admin@syam.cc \
-d syam.cc \
-d www.syam.cc \
-d 56.syam.cc \
-d app.syam.cc \
-d gp.syam.cc \
-d dp.syam.cc \
-d cp.syam.cc \
-d lp.syam.cc \
-d pp.syam.cc \
-d mp.syam.cc \
-d im.syam.cc \
-d sns.syam.cc \
-d blog.syam.cc \
-d lw.syam.cc \
-d ma.syam.cc \
-d mirror.syam.cc \
-d open.syam.cc \
-d pay.syam.cc \
-d forum.syam.cc \
-d mas.syam.cc \
-d was.syam.cc \
-d gps.syam.cc
  • # .lonal.com Certificate # sy.include.d/server_ssl_lonal_com.conf*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
./letsencrypt-auto certonly --standalone --email admin@lonal.com \
-d lonal.com \
-d www.lonal.com \
-d 56.lonal.com \
-d app.lonal.com \
-d gp.lonal.com \
-d dp.lonal.com \
-d cp.lonal.com \
-d lp.lonal.com \
-d pp.lonal.com \
-d mp.lonal.com \
-d im.lonal.com \
-d sns.lonal.com \
-d blog.lonal.com \
-d lw.lonal.com \
-d ma.lonal.com \
-d mirror.lonal.com \
-d open.lonal.com \
-d pay.lonal.com \
-d forum.lonal.com \
-d mas.lonal.com \
-d was.lonal.com \
-d gps.lonal.com
  • # .iirii.com Certificate # sy.include.d/server_ssl_iirii_com.conf*
1
2
3
4
5
6
./letsencrypt-auto certonly --standalone --email admin@iirii.com \
-d iirii.com \
-d www.iirii.com \
-d wp.iirii.com \
-d ftp.iirii.com \
-d sarah.iirii.com
  • # .iirii.com Certificate # sy.include.d/server_ssl_coopens_com_ali.conf*
1
2
3
4
5
./letsencrypt-auto certonly --standalone \
-d acw.iirii.com \
-d acs.iirii.com \
-d acr.iirii.com \
-d axp.iirii.com
  • # .iirii.com Certificate # sy.include.d/server_ssl_iirii_com_mos.conf*
1
2
3
4
5
./letsencrypt-auto certonly --standalone \
-d mcw.iirii.com \
-d mcs.iirii.com \
-d mcr.iirii.com \
-d mxp.iirii.com
  • # .iirii.com Certificate # sy.include.d/server_ssl_iirii_com_vultr.conf*
1
2
3
4
5
./letsencrypt-auto certonly --standalone \
-d vcw.iirii.com \
-d vcs.iirii.com \
-d vcr.iirii.com \
-d vxp.iirii.com

以下医院相关

  • # .apolloyl.com Certificate # sy.include.d/server_ssl_apolloyl_com.conf*
1
2
3
4
5
./letsencrypt-auto certonly --standalone \
-d apolloyl.com \
-d www.apolloyl.com \
-d mirror.apolloyl.com \
-d t.apolloyl.com
  • # .yntongji.com Certificate # sy.include.d/server_ssl_yntongji_com.conf*
1
2
3
4
5
./letsencrypt-auto certonly --standalone \
-d yntongji.com \
-d www.yntongji.com \
-d open.yntongji.com \
-d t.yntongji.com
  • # .hszhyy120.com Certificate # sy.include.d/server_ssl_hszhyy120_com.conf*
1
2
3
4
5
./letsencrypt-auto certonly --standalone \
-d hszhyy120.com \
-d www.hszhyy120.com \
-d open.hszhyy120.com \
-d t.hszhyy120.com

To obtain a cert using the “webroot” plugin, which can work with the webroot directory of any webserver software:

1
./letsencrypt-auto certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is
  • 完成以上命令 最后提示如下成功信息
1
2
3
4
5
6
7
8
9
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/coopens.com/fullchain.pem. Your cert will
expire on 2016-03-22. To obtain a new version of the certificate in
the future, simply run Let's Encrypt again.
- If you like Let's Encrypt, please consider supporting our work by:


Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

  • 按提示在 /etc/letsencrypt/live/coopens.com/fullchain.pem 四个文件
1
2
3
4
cert.pem 
chain.pem
fullchain.pem
privkey.pem

修改相应的 coopens.com 配置ssl证书指向

1
2
3
4
#ssl_certificate /data/home/yzhang/GlobalSign/SYAM/syam.crt;
#ssl_certificate_key /data/home/yzhang/GlobalSign/SYAM/syam.key;
ssl_certificate /etc/letsencrypt/live/coopens.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/coopens.com/privkey.pem;

最后重启 nginx 即可

  • 配置 ocsp 根证书
1
cat fullchain.pem /data/home/yzhang/CoamRunning/Documents/Server/ServiceConfig/Nginx/Certify/dst_root.pem > rootchain.pem

问题分析

在运行 sudo ./letsencrypt-auto certonly –standalone –email admin@iirii.com -d iirii.com 时频繁出现以下网络连接的错误:

1
2
3
4
5
6
7
8
9
10
11
Fri Feb 19 22:37:18 yzhang@coam:~/RunProject/letsencrypt$ sudo ./letsencrypt-auto certonly --standalone --email admin@iirii.com \
> -d iirii.com \
> -d www.iirii.com \
> -d wp.iirii.com \
> -d ftp.iirii.com \
> -d sarah.iirii.com \
> -d acs.iirii.com \
> -d acr.iirii.com
Checking for new version...
Upgrading letsencrypt-auto 0.5.0.dev0 to 0.4.0...
Couldn't download https://raw.githubusercontent.com/letsencrypt/letsencrypt/v0.4.0/letsencrypt-auto-source/letsencrypt-auto. <urlopen error [Errno -2] Name or service not known>

需要配合 ShadowSocks 代理翻墙,详细配置参见 Linux/ShadowSocks.md


参考列表

letsencrypt
使用 Let’s Encrypt 开源 SSL 证书
为Nginx手动获取Let’S Encrypt的免费SSL证书
Let’s Encrypt 试用记

Nginx下SSL配置解释
Configuring Let’s Encrypt for nginx with Automatic Renewal

Title

Android Studio 2.0-安装


Android Studio 更新 gradle

https://developer.android.com/tools/revisions/gradle-plugin.html
http://www.gradle.org/
如何用 Android Studio 导入开源项目以及常见错误的解决办法

Android Studio有哪些非常好用的插件?


Android Studio build.gradle 插件依赖更新自动检查

  • 添加以下部分到项目依赖
1
2
3
4
5
6
7
8
9
10
11
12
apply plugin: 'com.github.ben-manes.versions'

buildscript {
repositories {
jcenter()
}

dependencies {
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
// classpath 'org.codehaus.groovy:groovy-backports-compat23:2.3.5' // uncomment if you're using Gradle 1.x
}
}
  • 执行检查
1
gradlew dependencyUpdates -Drevision=release

How to check if gradle dependency has new version
ben-manes/gradle-versions-plugin



Android Studio Live Template

在Android Studio 中,我们会发现有时候我们有一些打出一些拼写就会出来一些东西.比如:psvm

Android Studio live templates 的使用


Android Studio 无线调试

pedrovgs/AndroidWiFiADB
Android wifi无线调试App新玩法ADB WIFI


Android Studio 加速

加速Android Studio/Gradle构建
Android Studio的Gradle的加速


Android Studio插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Markdown

.ignore
Genymotion
Lombok
Android ButterKnife Zelezny //
ADB WIFI
Android Parcelable code generator // https://github.com/mcharmas/android-parcelable-intellij-plugin
ideavim

GsonFormat //五颗星推荐,把json数据往粘贴板一贴,自动生成Bean有没有,显著提高生成力.
Android Methods Count // http://www.methodscount.com/plugins

android-material-design-icon-generator-plugin // https://github.com/konifar/android-material-design-icon-generator-plugin
...


Gsonformat
Android Postfix Completion
AndroidAccessors
Lifecycle Sorter

JsonOnlineViewer
CodeGlance
findBugs-IDEA

Android Studio插件
Java开发必装的IntelliJ IDEA插件


Android自动清理无用资源工具

lint-cleaner-plugin

1
2
3
4
5
6
7
8
9
10
11
12
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.+'
classpath 'com.droidtitan:lint-cleaner-plugin:0.3.0'
}
}

apply plugin: 'android'
apply plugin: 'com.droidtitan.lintcleaner'
  • 执行命令清理
1
gradle lintClean
  • 搜索 UnusedResources 手动删除未使用的资源文件

Android Studio 瘦身攻略清理无用的资源(Image. Layout. Strings. Color)
Android自动清理无用资源工具
清除Android工程中没用到的资源


常见问题

编译项目时,提示错误

Execution failed for task ':assetManager:processDebugResources'.
 > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'G:\Program Files\Android\sdk\build-tools\22.0.1\aapt.exe'' finished with non-zero exit value 1

执行 输出编译详情

./gradlew assembleDebug --info

在Win8下,若需要在命令行下使用gradlw命令,添加到系统环境变量 PATH 下 G:\Program Files\Android\Android Studio\gradle\gradle-2.4\bin

使用命令行编译打包android-gradle项目

1. 执行 ./gradlew -v 来查看下项目所用的Gradle版本
2. 接着执行 ./gradlew clean
3. 最后执行 ./gradlew build

紧接着在 9GAG/app/build/outputs/apk 目录下会看到类似于app-debug-unaligned.apk, app-release-unsigned.apk等,看名字应该能理解意思,unaligned代表没有进行zip优化的,unsigned代表没有签名的.然后就可以直接安装apk查看运行效果了.


编译项目时,提示错误

Error:Execution failed for task ':assetManager:dexDebug'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'G:\Program Files\Java\jdk8\bin\java.exe'' finished with non-zero exit value 2

肯定是哪里依赖有冲突重复的包了,将依赖注释掉即可

经验总结

清除不必要的/libs/.jar包,即使没用引入
尽量不要引入本地包,使用 compile ‘io.reactivex:rxjava:1.0.14’ 的形式引入包
把不需要的jar包给删除了就可以了,亲测有效,重点排查android.support:appcompat-v7和com.android.support:support-v4包这个得用compile方法导入
//有相同包了,注意finished这句话,删除包,就可以了
compile 包引入重复的其它关联包,(版本不同也会重复引入,比如 android 注解库),使用 exclude 去掉关联引用:

compile('io.reactivex:rxandroid:1.0.1') {
    exclude module: 'rxjava', group: 'io.reactivex'
}

参考 Error:Execution failed for task ‘:app:dexDebug’. > com.android.ide.common.process.ProcessException


Android API 22 以上已经弃用了 httpclient 支持,需要额外引入:

compile group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.5.1'

使用

useLibrary  'org.apache.http.legacy'

引入旧版支持,无代码提示
但是使用手动导包到 libs下引用,像下面这样,就会提示上面的错误

compile files('libs/org.apache.http.legacy.jar')

所有还是通过下面这种方式导包

android {
    ...
    useLibrary  'org.apache.http.legacy'
}

并且两种情况都不需要引入下面这两个依赖包

///compile "org.apache.httpcomponents:httpclient:4.+"
///compile "org.apache.httpcomponents:httpcore:4.+" //需要引入,否则会出现错误 Error:(250, 17) 错误: 找不到符号 符号: 类 NameValuePair

编译项目时,提示错误

Error:Execution failed for task ':assetManager:dexDebug'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'G:\Program Files\Java\jdk8\bin\java.exe'' finished with non-zero exit value 1

将 java 1.8 改成 java 1.7 即可

compileOptions {
    encoding "UTF-8" //手动添加的
    sourceCompatibility JavaVersion.VERSION_1_7
    targetCompatibility JavaVersion.VERSION_1_7
}

将 targetCompatibility JavaVersion.VERSION_1_7 改成 targetCompatibility JavaVersion.VERSION_1_8 后提示 lint * 错误,后参考项目 rxjava-webservice 的配置添加 retrolambda 解决


build.gradle 引入 compile ‘com.daimajia.easing:library:1.0.0@aar’ 后,出现以下错误

:app:processDebugManifest
F:\BaiDuCloud\StudioProjects\ShangYun\app\src\debug\AndroidManifest.xml:68:9-38 Error:
    Attribute application@icon value=(@drawable/logo) from AndroidManifest.xml:68:9-38
    is also present at [com.daimajia.easing:library:1.0.0] AndroidManifest.xml:13:9-45 value=(@drawable/ic_launcher)
    Suggestion: add 'tools:replace="android:icon"' to <application> element at AndroidManifest.xml:65:5-580:19 to override
Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : Attribute application@icon value=(@drawable/logo) from AndroidManifest.xml:68:9-38
    is also present at [com.daimajia.easing:library:1.0.0] AndroidManifest.xml:13:9-45 value=(@drawable/ic_launcher)
    Suggestion: add 'tools:replace="android:icon"' to <application> element at AndroidManifest.xml:65:5-580:19 to override

因为引入的库与当前主项目的logo有冲突,于是按以下修改:

在Manifest.xml的application标签下添加tools:replace=”android:icon, android:theme”(多个属性用,隔开,并且记住在manifest根标签上加入xmlns:tools=”http://schemas.android.com/tools",否则会找不到namespace哦)
参考 http://blog.csdn.net/codezjx/article/details/38669939


软件包引入依赖过多文件之后,起用 renderscriptTargetApi 19 和 renderscriptSupportModeEnabled true 后出现以下错误:

com.android.dex.DexIndexOverflowException: Cannot merge new index 65536 into a non-jumbo instruction!

添加如下配置后解决问题

android {
    ...
    dexOptions {
        jumboMode true
    }
}

但是在一些旧的Android机上可能不能安装, 还是要想办法控制包数量的大小,不用的包去掉 其中 lombok 占用 1323kb,注释掉后没有出现问题,参考:
DexIndexOverflowException: Cannot merge new index 65772 into a non-jumbo instruction!: Jumbo Mode? and/or Multi-Dex? What is behind the scene?
Android Studio ONLY! DexException: Cannot merge new index 65536 into a non-jumbo instruction
解决”Cannot merge new index 67208 into a non-jumbo instruction”的问题


参考

http://stackoverflow.com/questions/28640314/android-studio-fails-to-debug-with-error-org-gradle-process-internal-execexcepti