且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

第二十一周微职位

更新时间:2022-09-12 14:51:01

1、概述redis的应用场景、redis的架构及实现。

1)Redis最为常用的数据类型主要有以下:

  • String

  • Hash

  • List

  • Set

  • Sorted set

  • pub/sub

  • Transactions

在具体描述这几种数据类型之前,我们先通过一张图了解下Redis内部内存管理中是如何描述这些不同数据类型的:

第二十一周微职位

首先Redis内部使用一个redisObject对象来表示所有的key和value,redisObject最主要的信息如上图所示:

         type代表一个value对象具体是何种数据类型,

         encoding是不同数据类型在redis内部的存储方式,

         比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:"123" "456"这样的字符串。

       这里需要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的,该功能会在后面具体描述。通过上图我们可以发现Redis使用redisObject来表示所有的key/value数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给Redis不同数据类型提供一个统一的管理接口,实际作者也提供了多种方法帮助我们尽量节省内存使用,我们随后会具体讨论。

2)各种数据类型应用和实现方式

下面我们先来逐一的分析下这7种数据类型的使用和内部实现方式:


String:


Strings 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字.

常用命令:  set,get,decr,incr,mget 等。

1
2
3
4
5
6
7
8
9
10
11
12
应用场景:String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类.即可以完全实现目前 Memcached 的功能,并且效率更高。还可以享受Redis的定时持久化,操作日志及 Replication等功能。除了提供与 Memcached 一样的get、set、incr、decr 等操作外,Redis还提供了下面一些操作:
获取字符串长度
往字符串append内容
设置和获取字符串的某一段内容
设置及获取字符串的某一位(bit)
批量设置一系列字符串的内容
实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int
Hash
常用命令:hget,hset,hgetall 等。
应用场景:在Memcached中,我们经常将一些结构化的信息打包成HashMap,在客户端序列化后存储为一个字符串的值,比如用户的昵称、年龄、性别、积分等,这时候在需要修改其中某一项时,通常需要将所有值取出反序列化后,修改某一项的值,再序列化存储回去。这样不仅增大了开销,也不适用于一些可能并发操作的场合(比如两个并发的操作都需要修改积分)。而Redis的Hash结构可以使你像在数据库中Update一个属性一样只修改某一项属性值。
        我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:
用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:

第二十一周微职位


第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。

第二十一周微职位

第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口,如下图:

第二十一周微职位

也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。

这里同时需要注意,Redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部Map的操作,由于Redis单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。

实现方式:

上面已经说到Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。


List


常用命令:lpush,rpush,lpop,rpop,lrange等。

应用场景:

Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。

Lists 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用Lists结构,我们可以轻松地实现最新消息排行等功能。Lists的另一个应用就是消息队列,
可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作Lists中某一段的api,你可以直接查询,删除Lists中某一段的元素。

实现方式:

Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。


Set


常用命令:

sadd,spop,smembers,sunion 等。

应用场景:

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

Sets 集合的概念就是一堆不重复值的组合。利用Redis提供的Sets数据结构,可以存储一些集合性的数据,比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。

实现方式:

set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。


Sorted Set


常用命令:

zadd,zrange,zrem,zcard等

使用场景:

Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。

另外还可以用Sorted Sets来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。

实现方式:

Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。



Pub/Sub

Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。



Transactions

谁说NoSQL都不支持事务,虽然Redis的Transactions提供的并不是严格的ACID的事务(比如一串用EXEC提交执行的命令,在执行中服务器宕机,那么会有一部分命令执行了,剩下的没执行),但是这个Transactions还是提供了基本的命令打包执行的功能(在服务器不出问题的情况下,可以保证一连串的命令是顺序在一起执行的,中间有会有其它客户端命令插进来执行)。Redis还提供了一个Watch功能,你可以对一个key进行Watch,然后再执行Transactions,在这过程中,如果这个Watched的值进行了修改,那么这个Transactions会发现并拒绝执行。


3)Redis实际应用场景

Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储;它的数据模型非常独特,用的是单线程。另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不需要转到Redis。

转向Redis当然也是可取的,许多开发者从一开始就把Redis作为首选数据库;但设想如果你的开发环境已经搭建好,应用已经在上面运行了,那么更换数据库框架显然不那么容易。另外在一些需要大容量数据集的应用,Redis也并不适合,因为它的数据集不会超过系统可用的内存。所以如果你有大数据应用,而且主要是读取访问模式,那么Redis并不是正确的选择。

        然而我喜欢Redis的一点就是你可以把它融入到你的系统中来,这就能够解决很多问题,比如那些你现有的数据库处理起来感到缓慢的任务。这些你就可以通过Redis来进行优化,或者为应用创建些新的功能。在本文中,我就想探讨一些怎样将Redis加入到现有的环境中,并利用它的原语命令等功能来解决 传统环境中碰到的一些常见问题。在这些例子中,Redis都不是作为首选数据库。

(1)显示最新的项目列表

下面这个语句常用来显示最新项目,随着数据多了,查询毫无疑问会越来越慢。

1
SELECT * FROM foo WHERE ... ORDER BY time DESC LIMIT 10

在Web应用中,“列出最新的回复”之类的查询非常普遍,这通常会带来可扩展性问题。这令人沮丧,因为项目本来就是按这个顺序被创建的,但要输出这个顺序却不得不进行排序操作。

        类似的问题就可以用Redis来解决。比如说,我们的一个Web应用想要列出用户贴出的最新20条评论。在最新的评论边上我们有一个“显示全部”的链接,点击后就可以获得更多的评论。

        我们假设数据库中的每条评论都有一个唯一的递增的ID字段。

        我们可以使用分页来制作主页和评论页,使用Redis的模板,每次新评论发表时,我们会将它的ID添加到一个Redis列表:

1
LPUSH latest.comments <ID>

       我们将列表裁剪为指定长度,因此Redis只需要保存最新的5000条评论:

       LTRIM latest.comments 0 5000 

      每次我们需要获取最新评论的项目范围时,我们调用一个函数来完成(使用伪代码):

1
2
3
4
5
6
7
FUNCTION get_latest_comments(start, num_items):  
    id_list = redis.lrange("latest.comments",start,start+num_items - 1)  
    IF id_list.length < num_items  
        id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")  
    END  
    RETURN id_list  
END

 这里我们做的很简单。在Redis中我们的最新ID使用了常驻缓存,这是一直更新的。但是我们做了限制不能超过5000个ID,因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。

        我们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。

(2)删除与过滤

      我们可以使用LREM来删除评论。如果删除操作非常少,另一个选择是直接跳过评论条目的入口,报告说该评论已经不存在。

       有些时候你想要给不同的列表附加上不同的过滤器。如果过滤器的数量受到限制,你可以简单的为每个不同的过滤器使用不同的Redis列表。毕竟每个列表只有5000条项目,但Redis却能够使用非常少的内存来处理几百万条项目。

(3)排行榜相关

      另一个很普遍的需求是各种数据库的数据并非存储在内存中,因此在按得分排序以及实时更新这些几乎每秒钟都需要更新的功能上数据库的性能不够理想。

      典型的比如那些在线游戏的排行榜,比如一个Facebook的游戏,根据得分你通常想要:

         - 列出前100名高分选手

         - 列出某用户当前的全球排名

      这些操作对于Redis来说小菜一碟,即使你有几百万个用户,每分钟都会有几百万个新的得分。

      模式是这样的,每次获得新得分时,我们用这样的代码:

      ZADD leaderboard  <score>  <username> 

     你可能用userID来取代username,这取决于你是怎么设计的。

      得到前100名高分用户很简单:ZREVRANGE leaderboard 0 99。

      用户的全球排名也相似,只需要:ZRANK leaderboard <username>。

(4)按照用户投票和时间排序

      排行榜的一种常见变体模式就像Reddit或Hacker News用的那样,新闻按照类似下面的公式根据得分来排序:

       score = points / time^alpha 

      因此用户的投票会相应的把新闻挖出来,但时间会按照一定的指数将新闻埋下去。下面是我们的模式,当然算法由你决定。

      模式是这样的,开始时先观察那些可能是最新的项目,例如首页上的1000条新闻都是候选者,因此我们先忽视掉其他的,这实现起来很简单。

      每次新的新闻贴上来后,我们将ID添加到列表中,使用LPUSH + LTRIM,确保只取出最新的1000条项目。

      有一项后台任务获取这个列表,并且持续的计算这1000条新闻中每条新闻的最终得分。计算结果由ZADD命令按照新的顺序填充生成列表,老新闻则被清除。这里的关键思路是排序工作是由后台任务来完成的。

(5)处理过期项目

      另一种常用的项目排序是按照时间排序。我们使用unix时间作为得分即可。

      模式如下:

       - 每次有新项目添加到我们的非Redis数据库时,我们把它加入到排序集合中。这时我们用的是时间属性,current_time和time_to_live。

       - 另一项后台任务使用ZRANGE…SCORES查询排序集合,取出最新的10个项目。如果发现unix时间已经过期,则在数据库中删除条目。

(6)计数

       Redis是一个很好的计数器,这要感谢INCRBY和其他相似命令。

       我相信你曾许多次想要给数据库加上新的计数器,用来获取统计或显示新信息,但是最后却由于写入敏感而不得不放弃它们。

       好了,现在使用Redis就不需要再担心了。有了原子递增(atomic increment),你可以放心的加上各种计数,用GETSET重置,或者是让它们过期。

       例如这样操作:

         INCR user:<id> EXPIRE 

         user:<id> 60 

       你可以计算出最近用户在页面间停顿不超过60秒的页面浏览量,当计数达到比如20时,就可以显示出某些条幅提示,或是其它你想显示的东西。

(7)特定时间内的特定项目

        另一项对于其他数据库很难,但Redis做起来却轻而易举的事就是统计在某段特点时间里有多少特定用户访问了某个特定资源。比如我想要知道某些特定的注册用户或IP地址,他们到底有多少访问了某篇文章。

      每次我获得一次新的页面浏览时我只需要这样做:

       SADD page:day1:<page_id> <user_id> 

      当然你可能想用unix时间替换day1,比如time()-(time()%3600*24)等等。

      想知道特定用户的数量吗?只需要使用SCARD page:day1:<page_id>。

       需要测试某个特定用户是否访问了这个页面?SISMEMBER page:day1:<page_id>。

(8)实时分析正在发生的情况,用于数据统计与防止垃圾邮件等

        我们只做了几个例子,但如果你研究Redis的命令集,并且组合一下,就能获得大量的实时分析方法,有效而且非常省力。使用Redis原语命令,更容易实施垃圾邮件过滤系统或其他实时跟踪系统。

(9)Pub/Sub

       Redis的Pub/Sub非常非常简单,运行稳定并且快速。支持模式匹配,能够实时订阅与取消频道。

(10)队列

        你应该已经注意到像list push和list pop这样的Redis命令能够很方便的执行队列操作了,但能做的可不止这些:比如Redis还有list pop的变体命令,能够在列表为空时阻塞队列。

       现代的互联网应用大量地使用了消息队列(Messaging)。消息队列不仅被用于系统内部组件之间的通信,同时也被用于系统跟其它服务之间的交互。消息队列的使用可以增加系统的可扩展性、灵活性和用户体验。非基于消息队列的系统,其运行速度取决于系统中最慢的组件的速度(注:短板效应)。而基于消息队列可以将系统中各组件解除耦合,这样系统就不再受最慢组件的束缚,各组件可以异步运行从而得以更快的速度完成各自的工作。

    此外,当服务器处在高并发操作的时候,比如频繁地写入日志文件。可以利用消息队列实现异步处理。从而实现高性能的并发操作。



2、搭建一套mongodb分布式集群系统。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
目标:
搭建带有安全认证的mongodb集群准生产环境。
    一共3个shard,每一个shard有3个replica set,replicat set采用primary、secondary、secondary方式。9个mongod实例,另外,3个config server,3个mongod实例,3个mongos实例。
        mongodb版本 3.2.9 社区版本
        Cores 4
        OS Name CentOS release 6.6 (Final)
        OS Version Linux version 2.6.32-504.3.3.el6.x86_64 RAM (MB) 3729
注意:关闭SELINUX注意:服务器时间同步,比如用ntpdate,可以暂时略过不管。
最后会有核武。MongoDB Ops Manager
 
服务器准备:
服务器-ip
192.168.3.73    
192.168.3.74    
192.168.3.75    
另外准备一台192.168.3.81用作MongoDB Ops Manager。
访问互通
比如在192.168.3.73机器上修改
1
2
3
4
5
6
vi /etc/hosts
192.168.3.73 73.dooioo.org
192.168.3.74 74.dooioo.org
192.168.3.75 75.dooioo.org
192.168.3.76 76.dooioo.org
192.168.3.81 81.dooioo.org
1
2
vi /etc/sysconfig/network
HOSTNAME=73.dooioo.org

即刻生效可以使用在命令下执行即可,如下命令

1
hostname 73.dooioo.org

下载安装

登录到192.168.3.73

1
2
3
4
5
6
$ cd /root
$ wget https://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.2.9.tgz
$ scp mongodb-linux-x86_64-rhel62-3.2.9.tgz root@192.168.3.74:/root
$ scp mongodb-linux-x86_64-rhel62-3.2.9.tgz root@192.168.3.75:/root
$ scp mongodb-linux-x86_64-rhel62-3.2.9.tgz root@192.168.3.76:/root
$ tar zxvf mongodb-linux-x86_64-rhel62-3.2.9.tgz

规划集群和分片

规划3个shard * 3个replicat set + 配置服务

shard rs name Primary Secondary Secondary port
fang-s-a a1 a2 a3 28111
fang-s-b b2 b1 b3 28112
fang-s-c c3 c1 c2 28113
fang-cs configserver1 configserver2 configserver3 28200

规划3个config server的mongod实例configserver1、configserver2、configserver3

hostname 实例
73.dooioo.org a1 b1 c1 configserver1
74.dooioo.org a2 b2 c2 configserver2
75.dooioo.org a3 b3 c3 configserver3

规划目录和配置文件

创建必要的目录和文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/env bash
# 登录到192.168.3.73
# 创建db目录 日志目录 mongod配置文件
mkdir -/mongodb/a1
mkdir -/home/log/mongodb/a1
mkdir -/mongodb/b1
mkdir -/home/log/mongodb/b1
mkdir -/mongodb/c1
mkdir -/home/log/mongodb/c1
  
mkdir -/mongodb/configserver1
mkdir -/home/log/mongodb/configserver1
  
touch /mongodb/mongod-a1-config.yml
touch /mongodb/mongod-b1-config.yml
touch /mongodb/mongod-c1-config.yml
touch /mongodb/mongod-configserver1.yml
 
# 登录到192.168.3.74
mkdir -/mongodb/a2
mkdir -/home/log/mongodb/a2
mkdir -/mongodb/b2
mkdir -/home/log/mongodb/b2
mkdir -/mongodb/c2
mkdir -/home/log/mongodb/c2
  
mkdir -/mongodb/configserver2
mkdir -/home/log/mongodb/configserver2
  
touch /mongodb/mongod-a2-config.yml
touch /mongodb/mongod-b2-config.yml
touch /mongodb/mongod-c2-config.yml
touch /mongodb/mongod-configserver2.yml
 
# 登录到192.168.3.75
mkdir -/mongodb/a3
mkdir -/home/log/mongodb/a3
mkdir -/mongodb/b3
mkdir -/home/log/mongodb/b3
mkdir -/mongodb/c3
mkdir -/home/log/mongodb/c3
  
mkdir -/mongodb/configserver3
mkdir -/home/log/mongodb/configserver3
  
touch /mongodb/mongod-a3-config.yml
touch /mongodb/mongod-b3-config.yml
touch /mongodb/mongod-c3-config.yml
touch /mongodb/mongod-configserver3.yml
 
# 登录到192.168.3.73
# 生产和copy秘钥用户实例内部认证
  
openssl rand -base64 755 /mongodb/keyfile
chmod 400 /mongodb/keyfile
  
scp /mongodb/keyfile root@192.168.3.74:/mongodb/
scp /mongodb/keyfile root@192.168.3.75:/mongodb/

列举mongod-a1-config.yml文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# yml
# mongod config
# 日志位置
systemLog:
  destination: file
  logAppend: true
  path: /home/log/mongodb/a1/mongodb.log
# Where and how to store data.
# db存储位置
storage:
  dbPath: /mongodb/a1
  journal:
    enabled: true
#  engine:
#  mmapv1:
#  wiredTiger:
 
# how the process runs
# fork : fork and run in background  后台运行
# pidFilePath:location of pidfile 
processManagement:
  fork: true
  pidFilePath: /var/run/mongod-a1.pid
  
# network interfaces
# Listen to local interface only, comment to listen on all interfaces.
net:
  port: 28111
  bindIp: 0.0.0.0
  
#security:  enabled  disabled
#security:
#  keyFile: /mongodb/keyfile
#  clusterAuthMode: keyFile
  
#operationProfiling:
operationProfiling:
   slowOpThresholdMs: 1000
   mode: slowOp
  
#replication:
  
replication:
  replSetName: fang-s-a
  
#sharding:
  
sharding:
  clusterRole: shardsvr
  
## Enterprise-Only Options
  
#auditLog:
  
#snmp:

刚才touch的文件按照名称修改配置,比如mongod-b1-config.yml需要修改的内容:a1全部替换问b1, fang-s-a替换为fang-s-b,端口按照规划的28111改为28112

configserver稍微有点不一样的是clusterRole,注意修改,一个为shardsvr,一个为configsvr,其他同理,不同服务器修改数据和配置。按照前面创建的文件名称,目录名称修改。也给出一个配置服务的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# yml
# mongod config
  
systemLog:
  destination: file
  logAppend: true
  path: /home/log/mongodb/configserver1/mongodb.log
  
  
# Where and how to store data.
storage:
  dbPath: /mongodb/configserver1
  journal:
    enabled: true
#  engine:
#  mmapv1:
#  wiredTiger:
 
# how the process runs
# fork : fork and run in background
# pidFilePath:location of pidfile
processManagement:
  fork: true
  pidFilePath: /var/run/mongod-configserver1.pid
  
# network interfaces
# Listen to local interface only, comment to listen on all interfaces.
net:
  port: 28200
  bindIp: 0.0.0.0
  
  
#security:  enabled  disabled
#security:
#  keyFile: /mongodb/keyfile
#  clusterAuthMode: keyFile
  
#operationProfiling:
operationProfiling:
   slowOpThresholdMs: 1000
   mode: slowOp
  
#replication:
  
replication:
  replSetName: fang-cs
  
#sharding:
  
sharding:
  clusterRole: configsvr
  
## Enterprise-Only Options
  
#auditLog:
  
#snmp:


启动所有实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#  登录到192.168.3.73
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongod -/mongodb/mongod-a1-config.yml
./mongod -/mongodb/mongod-b1-config.yml
./mongod -/mongodb/mongod-c1-config.yml
./mongod -/mongodb/mongod-configserver1.yml
 
# 其他两台类似,启动其他8个实例
#  登录到192.168.3.74
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongod -/mongodb/mongod-a2-config.yml
./mongod -/mongodb/mongod-b2-config.yml
./mongod -/mongodb/mongod-c2-config.yml
./mongod -/mongodb/mongod-configserver2.yml
  
#  登录到192.168.3.75
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongod -/mongodb/mongod-a3-config.yml
./mongod -/mongodb/mongod-b3-config.yml
./mongod -/mongodb/mongod-c3-config.yml
./mongod -/mongodb/mongod-configserver3.yml

创建replicat set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# 登录到192.168.3.73
  
./mongo 127.0.0.1:28111/admin
  
> use admin
switched to db admin
  
# 初始化fang-s-a的副本集
> rs.initiate()
{
        "info2" "no configuration specified. Using a default configuration for the set",
        "me" "73.dooioo.org:28111",
        "ok" 1
}
  
# 添加到副本集
fang-s-a:OTHER> rs.add("74.dooioo.org:28111")
"ok" 1 }
fang-s-a:PRIMARY> rs.add("75.dooioo.org:28111")
"ok" 1 }
  
# 看下副本集配置情况
fang-s-a:PRIMARY> rs.conf()
{
        "_id" "fang-s-a",
        "version" 3,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" 0,
                        "host" "73.dooioo.org:28111",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" 1,
                        "tags" : {
  
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" 1
                },
                {
                        "_id" 1,
                        "host" "74.dooioo.org:28111",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" 1,
                        "tags" : {
  
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" 1
                },
                {
                        "_id" 2,
                        "host" "75.dooioo.org:28111",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" 1,
                        "tags" : {
  
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" 2000,
                "heartbeatTimeoutSecs" 10,
                "electionTimeoutMillis" 10000,
                "getLastErrorModes" : {
  
                },
                "getLastErrorDefaults" : {
                        "w" 1,
                        "wtimeout" 0
                },
                "replicaSetId" : ObjectId("57c00e2b9f6b9f6453c488c3")
        }
}

可以自行插入记录看看同步效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 登录到192.168.3.74  初始化fang-s-b 添加副本集
./mongo 127.0.0.1:28112/admin
rs.initiate()
rs.add("73.dooioo.org:28112")
rs.add("75.dooioo.org:28112")
# 登录到192.168.3.75  初始化fang-s-c 添加副本集
./mongo 127.0.0.1:28113/admin
rs.initiate()
rs.add("73.dooioo.org:28113")
rs.add("74.dooioo.org:28113")
  
# 登录到192.168.3.74  初始化fang-cs添加副本集
./mongo 127.0.0.1:28200/admin
rs.initiate()
rs.add("74.dooioo.org:28200")
rs.add("75.dooioo.org:28200")

添加分片集群:

1
2
3
# 登录到192.168.3.73
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongos --port 28300 --configdb fang-cs/73.dooioo.org:28200,74.dooioo.org:28200,75.dooioo.org:28200 --fork --logpath /home/log/mongodb/mongos.log --bind_ip 0.0.0.0

通过mongos来登录:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 登录到192.168.3.73
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongo 127.0.0.1:28300/admin
 
mongos> use admin
switched to db admin
mongos> sh.addShard("fang-s-a/73.dooioo.org:28111,74.dooioo.org:28111,75.dooioo.org:28111")
"shardAdded" "fang-s-a""ok" 1 }
mongos> sh.addShard("fang-s-b/73.dooioo.org:28112,74.dooioo.org:28112,75.dooioo.org:28112")
"shardAdded" "fang-s-b""ok" 1 }
mongos> sh.addShard("fang-s-c/73.dooioo.org:28113,74.dooioo.org:28113,75.dooioo.org:28113")
"shardAdded" "fang-s-c""ok" 1 }
mongos>

没有安全认证的集群就搭建好了,下面是关于安全认证的。

建立安全

秘钥文件keyfile

   生成秘钥文件

1
2
3
4
openssl rand -base64 755 > /mongodb/keyfile
chmod 400 /mongodb/keyfile
scp keyfile root@192.168.3.74:/mongodb/
scp keyfile root@192.168.3.75:/mongodb/

创建用户,登录到一个mongos实例,为集群创建root用户

1
db.createUser({ user: "root******",pwd: "**************",roles: [ "root""userAdminAnyDatabase""userAdmin""dbOwner" ]})

所有实例全部停止,使用

1
./mongod -/mongodb/mongod-a1-config.yml --shutdown

mongod实例启动添加参数 --keyFile /mongodb/keyfile --auth

启动时可以不使用 --auth参数,因为使用了 --keyFile就必须验证,也就是隐含了 --auth。但是--auth并不隐含 --keyFile。

测试,iostat,观察使用情况

例如,以下命令会每隔一秒展示额外的统计数据和每次展示报表的时间(以MB/s为流量单位):

1
iostat -xmt 1

Key fields from iostat:

%util: 这对快速查看来说是最有用的字段,它指明了设备/驱动器使用时间的百分比。
avgrq-sz:平均请求大小。该值较小的数字反映了更多的随机IO操作。

核武MongoDB Ops Manager


下面介绍下核武MongoDB Ops Manager。

安装:

机器同上(CentOS release 6.6)。官方推荐要求15 GB memory and 50 GB disk space。df -h校验。测试用,少一些没关系。这里测试机器30G硬盘空间,4G内存。需要有root账号。首先安装一个mongod实例,作为ops的db。到官网上下载Ops Manager包,我这里下载的是mongodb-mms-2.0.5.358-1.x86_64.rpm。

执行

1
2
3
sudo rpm -ivh mongodb-mms-2.0.5.358-1.x86_64.rpm
  
sudo service mongodb-mms start

配置文件位置/opt/mongodb/mms/conf/conf-mms.properties
默认访问8080端口,https://192.168.3.81:8080/.

账号配置

略,比如修改时区为北京时间。

新的部署

登录,可以选择部署新的集群和,管理手动创建的集群

第二十一周微职位选择Build New Deployment Where would you like to deploy MongoDB?
选择 Deployment in other remote. What type of MongoDB deployment would you like to build?
选择 Sharded Cluster Provide details fZ喎"/kf/ware/vc/" target="_blank" class="keylink">vciB5b3VyIHNoYXJkZWQgY2x1c3RlciC55ruuxOO1xLyvyLrF5NbDPGJyIC8+DQpDbHVzdGVyIE5hbWUgOiBtZGItdGVzdC1jbHVzdGVyIFNoYXJkIENvdW50IDogNCBOb2RlcyBQZXIgU2hhcmQgOiAzIFNoYXJkIE5hbWUgUHJlZml4IDogbWRiLXRlc3QgRGF0YSBEaXJlY3RvcnkgUHJlZml4IDogL2RhdGEgSW5zdGFsbCBhbiBBdXRvbWF0aW9uIEFnZW50IG9uIGVhY2ggc2VydmVyLiDU2sO/uPa3/s7xxvewstew19S2r7T6wO23/s7xoaMgxKzIz9Do0qoxMrj2t/7O8cb3o6zS8s6qIDQqIDOjrNXiwO+3/s7xxvfJ2aOs0aHU8TTMqLf+zvHG96GjPGJyIC8+DQrRodTxz8LU2LCy17DF5NbDtPrA7bf+zvHG96O6ILv5sb7Kx9K7sr3Su7K9ytaw0crWwcujrA0KPHA+z8LU2LT6wO2w/DwvcD4NCjxwcmUgY2xhc3M9"brush:sql;"> curl -OL https://192.168.3.81:8080/download/agent/automation/mongodb-mms-automation-agent-manager-2.5.19.1732-1.x86_64.rpm

安装代理包

1
sudo rpm -U mongodb-mms-automation-agent-manager-2.5.19.1732-1.x86_64.rpm

打开配置文件,编辑配置,数据库指定了目录的,必须创建目录。

1
2
3
4
5
6
7
8
9
10
11
sudo vi /etc/mongodb-mms/automation-agent.config
 
 
mmsGroupId=57be67ffe4b09e1dfa498ee7
mmsApiKey=e5b83213955c886d0ef8ce3324cf8f30
mmsBaseUrl=
 
sudo mkdir -/data
sudo chown mongod:mongod /data
  
sudo service mongodb-mms-automation-agent start

验证通过后,下一步。初始了默认的一些实例:

你也可以移动。先按默认的下一步。

然后提示: We are deploying your changes. This might take a few minutes…






      本文转自xinrenbaodao  51CTO博客,原文链接:http://blog.51cto.com/11832904/1970645,如需转载请自行联系原作者