标签 MongoDB 下的文章

Apex 是一个将开发和部署 AWS Lambda 函数的过程打包了的工具。它提供了一个本地命令行工具来创建安全上下文、部署函数,甚至追踪云端日志。由于 AWS Lambda 服务将函数看成独立的单元,Apex 提供了一个框架层将一系列函数作为一个项目。另外,它将服务拓展到不仅仅是 Java,Javascript 和 Ptyhon 语言,甚至包括 Go 语言。

两年前 Express (基本上是 NodeJS 事实标准上的网络框架层)的作者,离开了 Node 社区,而将其注意力转向 Go (谷歌创造的后端服务语言),以及 Lambda(由 AWS 提供的函数即服务)。尽管一个开发者的行为无法引领一股潮流,但是来看看他正在做的名叫 Apex 项目会很有趣,因为它可能预示着未来很大一部分网络开发的改变。

什么是 Lambda?

如今,人们如果不能使用自己的硬件,他们会选择付费使用一些云端的虚拟服务器。在云上,他们会部署一个完整的协议栈如 Node、Express,和一个自定义应用。或者如果他们更进一步使用了诸如 Heroku 或者 Bluemix 之类的新玩意,也可能在某些已经预配置好 Node 的容器中仅仅通过部署应用代码来部署他们完整的应用。

在这个抽象的阶梯上的下一步是单独部署函数到云端而不是一个完整的应用。这些函数之后可以被一大堆外部事件触发。例如,AWS 的 API 网关服务可以将代理 HTTP 请求作为触发函数的事件,而函数即服务(FaaS)的供应方根据要求执行匹配的函数。

Apex 起步

Apex 是一个将 AWS 命令行接口封装起来的命令行工具。因此,开始使用 Apex 的第一步就是确保你已经安装和配置了从 AWS 获取的命令行工具(详情请查看 AWS CLI Getting Started 或者 Apex documentation)。

接下来,安装 Apex:

curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sh

然后为你的新项目创建一个目录并运行:

apex init

apexInit

这步会配置好一些必须的安全策略,并且将项目名字附在函数名后,因为 Lambda 使用扁平化的命名空间。同时它也会创建一些配置文件和默认的 “Hello World" 风格的 Javascript 函数的 functions 目录。

tree

Apex/Lambda 一个非常友好的特性是创建函数非常直观。创建一个以你函数名为名的新目录,然后在其中创建项目。如果想要使用 Go 语言,你可以创建一个叫 simpleGo 的目录然后在其中创建一个小型的 main 函数:

//  serverless/functions/simpleGo/main.go
package main

import (  
    "encoding/json"
    "github.com/apex/go-apex"
    "log"
)

type helloEvent struct {  
    Hello string `json:"hello"`
}

func main() {  
    apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
        var h helloEvent
        if err := json.Unmarshal(event, &h); err != nil {
            return nil, err
        }
        log.Print("event.hello:", h.Hello)
        return h, nil
    })
}

Node 是 Lambda 所支持的运行环境,Apex 使用 NodeJS shim 来调用由上述程序产生的二进制文件。它将 event 传入二进制文件的 STDIN,将从二进制返回的 STDOUT 作为 value。通过 STDERR 来显示日志。apex.HandleFunc 用来为你管理所有的管道。事实上在 Unix 惯例里这是一个非常简单的解决方案。你甚至可以通过在本地命令行执行 go run main.go 来测试它。

goRun

通过 Apex 向云端部署稍显琐碎:

apexDeploy

注意,这将会对你的函数指定命名空间,控制版本,甚至为其他多开发环境如 stagingproduction配置env

通过 apex invoke 在云端执行也比较琐碎:

apexInvoke

当然我们也可以追踪一些日志:

apexLog

这些是从 AWS CloudWatch 返回的结果。它们都在 AWS 的 UI 中可见,但是当在另一个终端参照此结果来署它会更快。

窥探内部的秘密

来看看它内部到底部署了什么很具有指导性。Apex 将 shim 和所有需要用来运行函数的东西打包起来。另外,它会提前做好配置如入口与安全条例:

lambdaConfig

Lambda 服务实际上接受一个包含所有依赖的 zip 压缩包,它会被部署到服务器来执行指定的函数。我们可以使用 apex build <functionName> 在本地创建一个压缩包用来在以后解压以探索。

apexBuild

这里的 _apex_index.js handle 函数是原始的入口。它会配置好一些环境变量然后进入 index.js

index.js 孕育一个 main Go 的二进制文件的子进程并且将所有关联联结在一起。

使用 mgo 继续深入

mgo 是 Go 语言的 MongoDB 驱动。使用 Apex 来创建一个函数来连接到 Compose 的 MongoDB 就如同我们已经学习过的 simpleGo 函数一样直观。这里我们会通过增加一个 mgoGo 目录和另一个 main.go 来创建一个新函数。

// serverless/functions/mgoGo/main.go

package main

import (  
    "crypto/tls"
    "encoding/json"
    "github.com/apex/go-apex"
    "gopkg.in/mgo.v2"
    "log"
    "net"
)

type person struct {  
  Name  string `json:"name"`
  Email string `json:"email"`
}

func main() {  
    apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
        tlsConfig := &tls.Config{}
        tlsConfig.InsecureSkipVerify = true

        //connect URL:
        // "mongodb://<username>:<password>@<hostname>:<port>,<hostname>:<port>/<db-name>
        dialInfo, err := mgo.ParseURL("mongodb://apex:[email protected]:15188, aws-us-west-2-portal.1.dblayer.com:15188/signups")
        dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
            conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
            return conn, err
        }
        session, err := mgo.DialWithInfo(dialInfo)
        if err != nil {
            log.Fatal("uh oh. bad Dial.")
            panic(err)
        }
        defer session.Close()
        log.Print("Connected!")

    var p person
    if err := json.Unmarshal(event, &p); err != nil {
            log.Fatal(err)
    }

        c := session.DB("signups").C("people")
        err = c.Insert(&p) 
        if err != nil {
            log.Fatal(err)
        }

    log.Print("Created: ", p.Name," - ", p.Email)
        return p, nil
    })
}

发布部署,我们可以通过使用正确类型的事件来模拟调用了一个 API:

apexMgo

最终结果是 insert 到在 Compose 之上 的 MongoDB 中。

composeDeploy

还有更多……

尽管目前我们已经涉及了 Apex 的方方面面,但是仍然有很多值得我们去探索的东西。它还和 Terraform 进行了整合。如果你真的希望,你可以发布一个多语言项目包括 Javascript、Java、Python 以及 Go。你也可以为开发、演示以及产品环境配置多种环境。你可以调整运行资源如调整存储大小和运行时间来调整成本。而且你可以把函数勾连到 API 网关上来传输一个 HTTP API 或者使用一些类似 SNS (简单通知服务)来为云端的函数创建管道。

和大多数事物一样,Apex 和 Lambda 并不是在所有场景下都完美。 但是,在你的工具箱中增加一个完全不需要你来管理底层建设的工具完全没有坏处。


作者简介:

Hays Hutton 喜欢写代码并写一些与其相关的东西。喜欢这篇文章?请前往Hays Hutton’s author page 继续阅读其他文章。


via: https://www.compose.com/articles/go-serverless-with-apex-and-composes-mongodb/

作者:Hays Hutton 译者:xiaow6 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

MongoDB 已经成为市面上最知名的 NoSQL 数据库。MongoDB 是面向文档的,它的无模式设计使得它在各种各样的WEB 应用当中广受欢迎。最让我喜欢的特性之一是它的副本集(Replica Set),副本集将同一数据的多份拷贝放在一组 mongod 节点上,从而实现数据的冗余以及高可用性。

这篇教程将向你介绍如何配置一个 MongoDB 副本集。

副本集的最常见配置需要一个主节点以及多个副节点。这之后启动的复制行为会从这个主节点到其他副节点。副本集不止可以针对意外的硬件故障和停机事件对数据库提供保护,同时也因为提供了更多的节点从而提高了数据库客户端数据读取的吞吐量。

配置环境

这个教程里,我们会配置一个包括一个主节点以及两个副节点的副本集。

为了达到这个目的,我们使用了3个运行在 VirtualBox 上的虚拟机。我会在这些虚拟机上安装 Ubuntu 14.04,并且安装 MongoDB 官方包。

我会在一个虚拟机实例上配置好所需的环境,然后将它克隆到其他的虚拟机实例上。因此,选择一个名为 master 的虚拟机,执行以下安装过程。

首先,我们需要给 apt 增加一个 MongoDB 密钥:

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10

然后,将官方的 MongoDB 仓库添加到 source.list 中:

$ sudo su
# echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.0.list

接下来更新 apt 仓库并且安装 MongoDB。

$ sudo apt-get update
$ sudo apt-get install -y mongodb-org

现在对 /etc/mongodb.conf 做一些更改

auth = true
dbpath=/var/lib/mongodb
logpath=/var/log/mongodb/mongod.log
logappend=true
keyFile=/var/lib/mongodb/keyFile
replSet=myReplica

第一行的作用是表明我们的数据库需要验证才可以使用。keyfile 配置用于 MongoDB 节点间复制行为的密钥文件。replSet 为副本集设置一个名称。

接下来我们创建一个用于所有实例的密钥文件。

$ echo -n "MyRandomStringForReplicaSet" | md5sum > keyFile

这将会创建一个含有 MD5 字符串的密钥文件,但是由于其中包含了一些噪音,我们需要对他们清理后才能正式在 MongoDB 中使用。

$ echo -n "MyReplicaSetKey" | md5sum|grep -o "[0-9a-z]\+" > keyFile

grep 命令的作用的是把将空格等我们不想要的内容过滤掉之后的 MD5 字符串打印出来。

现在我们对密钥文件进行一些操作,让它真正可用。

$ sudo cp keyFile /var/lib/mongodb
$ sudo chown mongodb:nogroup keyFile
$ sudo chmod 400 keyFile

接下来,关闭此虚拟机。将其 Ubuntu 系统克隆到其他虚拟机上。

这是克隆后的副节点1和副节点2。确认你已经将它们的MAC地址重新初始化,并且克隆整个硬盘。

请注意,三个虚拟机示例需要在同一个网络中以便相互通讯。因此,我们需要它们弄到“互联网"上去。

这里推荐给每个虚拟机设置一个静态 IP 地址,而不是使用 DHCP。这样它们就不至于在 DHCP 分配IP地址给他们的时候失去连接。

像下面这样编辑每个虚拟机的 /etc/networks/interfaces 文件。

在主节点上:

auto eth1
    iface eth1 inet static
    address 192.168.50.2
    netmask 255.255.255.0

在副节点1上:

auto eth1
    iface eth1 inet static
    address 192.168.50.3
    netmask 255.255.255.0

在副节点2上:

auto eth1
    iface eth1 inet static
    address 192.168.50.4
    netmask 255.255.255.0

由于我们没有 DNS 服务,所以需要设置设置一下 /etc/hosts 这个文件,手工将主机名称放到此文件中。

在主节点上:

127.0.0.1 localhost primary
192.168.50.2 primary
192.168.50.3 secondary1
192.168.50.4 secondary2

在副节点1上:

127.0.0.1 localhost secondary1
192.168.50.2 primary
192.168.50.3 secondary1
192.168.50.4 secondary2

在副节点2上:

127.0.0.1 localhost secondary2
192.168.50.2 primary
192.168.50.3 secondary1
192.168.50.4 secondary2

使用 ping 命令检查各个节点之间的连接。

$ ping primary
$ ping secondary1
$ ping secondary2

配置副本集

验证各个节点可以正常连通后,我们就可以新建一个管理员用户,用于之后的副本集操作。

在主节点上,打开 /etc/mongodb.conf 文件,将 auth 和 replSet 两项注释掉。

dbpath=/var/lib/mongodb
logpath=/var/log/mongodb/mongod.log
logappend=true
#auth = true
keyFile=/var/lib/mongodb/keyFile
#replSet=myReplica

在一个新安装的 MongoDB 上配置任何用户或副本集之前,你需要注释掉 auth 行。默认情况下,MongoDB 并没有创建任何用户。而如果在你创建用户前启用了 auth,你就不能够做任何事情。你可以在创建一个用户后再次启用 auth。

修改 /etc/mongodb.conf 之后,重启 mongod 进程。

$ sudo service mongod restart

现在连接到 MongoDB master:

$ mongo <master-ip-address>:27017

连接 MongoDB 后,新建管理员用户。

> use admin
> db.createUser({
user:"admin",
pwd:"
})

重启 MongoDB:

$ sudo service mongod restart

再次连接到 MongoDB,用以下命令将 副节点1 和副节点2节点添加到我们的副本集中。

> use admin
> db.auth("admin","myreallyhardpassword")
> rs.initiate()
> rs.add ("secondary1:27017")
> rs.add("secondary2:27017")

现在副本集到手了,可以开始我们的项目了。参照 官方驱动文档 来了解如何连接到副本集。如果你想要用 Shell 来请求数据,那么你需要连接到主节点上来插入或者请求数据,副节点不行。如果你执意要尝试用副本集操作,那么以下错误信息就蹦出来招呼你了。

myReplica:SECONDARY>
myReplica:SECONDARY> show databases
2015-05-10T03:09:24.131+0000 E QUERY    Error: listDatabases failed:{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" }
    at Error ()
    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

如果你要从 shell 连接到整个副本集,你可以安装如下命令。在副本集中的失败切换是自动的。

$ mongo primary,secondary1,secondary2:27017/?replicaSet=myReplica

如果你使用其它驱动语言(例如,JavaScript、Ruby 等等),格式也许不同。

希望这篇教程能对你有所帮助。你可以使用Vagrant来自动完成你的本地环境配置,并且加速你的代码。


via: http://xmodulo.com/setup-replica-set-mongodb.html

作者:Christopher Valerio 译者:mr-ping 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出