标签归档:nosql

Sphinx+Scws 搭建千万级准实时搜索&应用场景详解

目标:
一、搭建准确的千万级数据库的准实时搜索(见详情)
二、实现词语高亮(客户端JS渲染,服务器端渲染,详见7.3)
三、实现搜索联想(输入框onchange,ajax请求搜索,取10条在层上展示方可)
四、实现词库管理(仅需管理scws下的自定义词库dd.txt即可)
五、实现全文搜索(提供了两种方案,详见8)

案例:
本文第五部分,针对实际应用场景,典型案例分析。

软件:
sphinx: sphinx-2.0.2-beta
scws: scws-1.2.0
===========================================================================

一、Sphinx安装
1、安装

2、配置
见sphinx.conf
详见下文,多索引增量索引方案

3、php 扩展
性能方面,扩展和直接使用API文件,差别不大;可以做选择;都在源码API中;
个人建议使用API文件,系统更稳定

3.1 sphinx客户端libsphinxclient

3.2 扩展
下载 http://pecl.php.net/package/sphinx

使用手册
http://docs.php.net/manual/zh/book.sphinx.php

4、索引 启动服务

二、php 分词 scws
官网 http://www.ftphp.com/scws/
1、 安装

2、 词库
scws-dict-chs-utf8.tar.bz2 解压放入 /opt/server/scws/etc
词库 dict.utf-8.xdb
规则 rules.utf-8.ini

3、 php 扩展
源码在phpext下

4、 分词测试
http://www.ftphp.com/scws/docs.php
详见测试文件 test_all.php

三、 索引

1、 增量索引方案

索引策略
1、搜索时,同时从主索引和增量索引取数据
2、每5分钟,运行一次增量索引;满足新数据搜索需求
3、每晚,运行一次主索引,同时会更新索引标示;再运行增量索引,实质为清空增量索引,避免与主索引重复索引
4、好处:避免开合并索引,合并索引效率较差
5、如数据量特别大,可考虑合并索引的方案

索引策略shell

四、 多个表独立索引方案
场景:如有用户搜索、商品搜索等多个索引需求
策略:配置一个多索引方案,每个表单独建立索引
前端根据不同类型选择不同的查询索引;全部,即选择所有索引
===========================================================================

五、性能及应用场景总结
1、基础数据、假如我们是一家商城;有用户user,商品goods,以及增量索引计数表search_counter。

2、编写配置文件 sphinx.conf

3、索引,启动服务

4、索引方案
索引策略
1、搜索时,同时从主索引和增量索引取数据
2、每5分钟,运行一次增量索引;满足新数据搜索需求
3、不同表的索引,分别执行方可
4、每晚,运行一次主索引,同时会更新索引标示;再运行增量索引,实质为清空增量索引,避免与主索引重复索引
5、好处:避免开合并索引,合并索引效率较差
6、如数据量特别大,可考虑合并索引的方案

索引策略shell

5、测试程序

5.1 加入用户信息测试

5.2 类别商品 多个关键字对比

6、小结
通过分词 和 采用 SPH_MATCH_EXTENDED (Sphinx内部查询语言的表达式) 模式;
能获取较好的搜索结果,排序和权值都是比较理想的。

7、优化扩展
7.1
如访问量较大,可将分词结果添加一层memecache,避免每次调用分词接口。

7.2
本文的的准实时索引,只对新增数据有效,如修改了老数据的内容则不能及时索引。
补充方案:(基于性能,不推荐)
7.2.1 全文重新索引
7.2.1在启一个索引为 updategoods,当数据发生改变时候,将来变化数据ID存如数据库,动态读取更新;
定时将更新的数据merge到主索引

7.3 词语高亮
利用API,SphinxClient::buildExcerpts可实现对关键词加入标签高亮

$opts 可实现对索引ID,搜索出的详情数组;进行匹配处理,得出理想的搜索结果。具体参数,见PHP手册。

8、全文搜索
由于sphinx索引ID唯一的问题,跨表的全文搜索不能直接实现;即,不能简单通过查询多个索引而获得结果;
不过通过如下方式,亦可实现全文搜索。

方案A
可在索引时对每个表的ID进行处理;
如:SELECT (id+1000000) AS id,name,price FROM goods;
在提供外部使用时,根据规则(如:ID > 1000000 为商品类)还原相应ID即可。

方案B
将数据来源存储为一个属性,将类比在属性中返回;获得的结果集中,可通过source_id进行类别区分了;如下:

转自:http://www.wubiao.info/314

redis-rdb-tools来解析分析reids dump文件及内存使用量

一. 前言

解析redis的dump.rdb文件,分析内存,以JSON格式导出数据。|
提供的功能有:
1. 生成内存报告
2. 转储文件到JSON
3. 使用标准的diff工具比较两个dump文件

Rdbtools是以python语言开发的。

二. 安装

2.1 前提条件
1. python2.4以上版本 和 pip
2. redis-py可选,只运行在测试用例下

2.2 从PyPI安装(推荐)

2.3 从源码包安装

三. 转换dump文件到JSON

3.1 解析dump文件并以JSON格式标准输出

3.2 只解析符合正则的keys

3.3 只解析以“a”为开头的hash且位于数据库ID为2的

四. 生成内存报告

生成CSV格式的内存报告。包含的列有:数据库ID,数据类型,key,内存使用量(byte),编码。内存使用量包含key、value和其他值。
注意:内存使用量是近似的。在一般情况下,略低于实际值。
可以根据key或数据库ID或数据类型对报告的内容进行过滤。

内存报告有助于检测是否是应用程序逻辑导致的内存泄露,也有助于优化reids内存使用情况。

五. 单个key所使用的内存量

有时候,需要查询某个key所使用的内存。如果全部导出来在查找将是很愚蠢且耗时的。对于这种情景,可以使用redis-memory-for-key命令。
如果出现下面信息,需要安装redis模块。redis-memory-for-key依赖redis-py包。

实例如下:

六. 比较RDB文件

使用–command diff选项,并通过管道来进行排序。

使用kdiff3工具来进行比较,kdiff3是图形化的工具,比较直观。kdiff3工具比较两个或三个输入文件或目录。
安装kdiff3

七. 使用解析器

八. 其他资源

1. FAQ:https://github.com/sripathikrishnan/redis-rdb-tools/wiki/FAQs
2. redis dump文件规范: https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format
3. redis RDB历史版本: https://github.com/sripathikrishnan/redis-rdb-tools/blob/master/docs/RDB_Version_History.textile
4. redis-rdb-tools:https://github.com/sripathikrishnan/redis-rdb-tools

九. 其他工具Redis-audit 

Redis-audit 是一个用ruby实现的脚本,通过它,我们可以知道每一类 key 对内存的使用量。它可以提供的数据有:某一类 key 值的访问频率如何,有多少值设置了过期时间,某一类 key 值使用内存的大小,这很方便让我们能排查哪些 key 不常用或者压根不用。
项目地址:https://github.com/snmaynard/redis-audit

如需转载请注明出处:http://www.ttlsa.com/html/2653.html

MongoDB.so: undefined symbol: HeUTF8解决方法

因为shell操作mongo比较麻烦,只好尝试使用perl操作mongo,perl需要操作mongodb必须先安装相应的驱动,大部分人使用cpan安装,个人觉得太麻烦,使用cpanm安装perl模块

cpanm报错了,使用–force参数

看起来一切完好。测试脚本
脚本内容

运行

google查询“MongoDB.so: undefined symbol: HeUTF8”,只发现一篇相关文章.一群人讨论这个问题。其中一个人的解决方法如下:

perl脚本运行ok.

实际上是因为不兼容的问题,对于系统RHEL5/CENTOS5发行版,mongodb的perl驱动最后的一个版本是v0.45
如下是国外网友的回复:

The latest version to compile, test and install properly on Rhel5/Centos5 is v0.45 by KRISTINA. (requires Any::Moose)
https://metacpan.org/release/KRISTINA/MongoDB-0.45

转载请注明出处: http://www.ttlsa.com/html/2344.html

参考地址:https://jira.mongodb.org/browse/PERL-247?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel

PHP操作MongoDB实例 — ttlsa教程系列之mongodb(十一)

PHPmongodb扩展安装

将mongo.so添加到php.ini

重启php-fpm生效

php的mongodb扩展,提供了4个核心类接口
1). 针对mongodb的连接操作类MongoClient
http://www.php.net/manual/zh/class.mongoclient.php
2). 针对mongodb的数据库操作类MongoDB
http://www.php.net/manual/zh/class.mongodb.php
3). 针对mongodb的集合操作类MongoCollection
http://www.php.net/manual/zh/class.mongocollection.php
4). 针对mongodb的查询结果集(游标)操作类MongoCursor
http://www.php.net/manual/zh/class.mongocursor.php

连接MongoDB
mongodb驱动连接格式为:mongodb://[username:password@]host1[:port1][,host2[:port2],…[,hostN[:portN]]][/[database][?options]],如:
mongodb://localhost
mongodb://user:password@localhost
mongodb://user:password@localhost/database
mongodb://example1.com:27017,example2.com:27017
mongodb://localhost,localhost:27018,localhost:27019
mongodb://host1,host2,host3/?slaveOk=true
mongodb://localhost/?safe=true
mongodb://host1,host2,host3/?safe=true;w=2;wtimeoutMS=2000
mongodb://rs1.example.com:27017,rs2.example.com:27017/?replicaSet=myReplSetName
mongodb://localhost/?journal=true&w=majority&wTimeoutMS=20000
具体含义参见《ttlsa教程系列之mongodb—(一)mongodb介绍》 http://www.ttlsa.com/html/1594.html

PHP连接实例:

在连接到复制集时,用它来判断哪台是primary。返回主机名称、端口号、健康程度、状态(1-primary,2-secondary,0-other)、ping耗时、前一次ping的时间戳。

列出所有数据库,返回数据库名称、大小、是否为空以及总大小、ok状态。

选择数据库,返回数据库对象

选择表(集合),返回文档集合对象

列出所有集合,返回集合对象

获取当前选择的数据库名,返回数据库名

删除当前数据库

设置slaveok状态(可读状态设置)

获取slaveok当前状态

插入数据MongoCollection::insert(array $a,array $options)
array $a 要插入的数组
array $options 选项:safe 是否返回操作结果信息;fsync 是否直接插入到物理硬盘;w 写入份数;timeout 超时时间

删除集合中的记录MongoCollection::remove(array $criteria,array $options)
array $criteria 条件
array $options 选项: safe 是否返回操作结果; fsync 是否是直接影响到物理硬盘; justOne 是否只影响一条记录

更新集合中的记录MongoCollection::update(array $criceria,array $newobj,array $options)
array $criteria 条件
array $newobj 要更新的内容
array $options 选项: safe 是否返回操作结果; fsync 是否是直接影响到物理硬盘; upsert 是否没有匹配数据就添加一条新的; multiple 是否影响所有符合条件的记录,默认只影响一条

查询集合获取单条记录MongoCollection::findOne(array $query,array $fields)
array $query 条件
array $fields 要获得的字段

获取多条记录MongoCollection::find(array $query,array $fields)
array $query 条件
array $fields 要获得的字段

获取查询结果数量

选定列MongoCursor::fields

分页

排序MongoCursor::sort

取查询结果

快照MongoCursor::snapshot
保证一致性。在做find()操作时,获得$cursor之后,这个游标是动态的,在循环取结果过程中,如果有其他连接来更改符合条件的记录时,这个$cursor也会跟着变化的。$cursor->snapshot();之后,再插入或删除符合条件的记录时,获取的结果集将不再变化。如果是小于1M的结果集会自动被当作snapshot来处理。
如果要获取$cursor之后不变的结果需要这么做:

snapshot对findOne无效。

如需转载请注明出处:PHP操作MongoDB实例  http://www.ttlsa.com/html/2288.html

mongodb架构mongodb分片集群与简易搭建方案—ttlsa教程系列之mongodb(六)

mongodb的扩展方式—分片,如果业务数据和系统负载不断增加,可以通过分片来解决。

分片就是指将数据拆分,分散到不同的服务器上,从而处理更大的负载,存储大数据。

当数据增大到一定程度时,查询数据会变的很慢,难以忍受的地步,严重影响用户体验。往往就会根据业务对大表大数据库进行分表分库操作,MySQL分表操作参见http://www.ttlsa.com/html/1757.html,人为的按照某种协定好的策略将若干不同的数据存储到不同的数据库服务器上,应用程序管理不同服务器上的不同数据,每台服务器上的连接都是完全独立的。在我曾经工作过的地方,mysql分表分库大量应用,比如将论坛附件表根据uid拆分成10个表00-09,取模10,也就是取uid最后两位;将post_000到post_014存在db1服务器上,将post_015到post_029存在db2服务器上,如此类推。这种分表分库可以很好的工作,弊端就是非常难以维护,调整数据分布和服务器负载,添加或减除节点非常困难,变一处而动全身。

mongodb支持自动分片,集群自动的切分数据,做负载均衡。避免上面的分片管理难度。
mongodb分片是将集合切合成小块,分散到若干片里面,每个片负责所有数据的一部分。这些块对应用程序来说是透明的,不需要知道哪些数据分布到哪些片上,甚至不在乎是否有做过分片,应用程序连接mongos进程,mongos知道数据和片的对应关系,将客户端请求转发到正确的片上,如果请求有了响应,mongos将结果收集起来返回给客户端程序。

分片适用场景:
1. 服务器磁盘不够用
2. 单个mongod不能满足日益频繁写请求
3. 将大量数据存放于内存中提高性能

建立分片需要三种角色:
1. shard server
保存实际数据容器。每个shard可以是单个的mongod实例,也可以是复制集,即使片内又多台服务器,只能有一个主服务器,其他的保存相同数据的副本。为了实现每个shard内部的auto-failover,强烈建议为每个shard配置一组Replica Set。
2. config server
为了将一个特定的collection 存储在多个shard 中,需要为该collection 指定一个shardkey,shardkey 可以决定该条记录属于哪个chunk。Config Servers 就是用来存储:所有shard 节点的配置信息、每个chunk 的shardkey 范围、chunk 在各shard 的分布情况、该集群中所有DB 和collection 的sharding 配置信息。
3. route server
集群前端路由,路由所有请求,然后将结果聚合。客户端由此接入,询问config server需要到哪些shard上查询或保存数据,再连接到相应的shard进行操作,最后将结果返回给客户端。客户端只需要将原先发送给mongod的请求原封不动的发给mongos即可,不必数据分布在哪个shard上。

shard key:
设置分片时,需要从集合中选一个键,作为数据拆分的依据,这个键就是shard key。
shard key的选择决定了插入操作在片之间的分布。
shard key保证足够的不一致性,数据才能更好的分布到多台服务器上。同时保持块在一个合理的规模是非常重要的,这样数据平衡和移动块不会消耗大量的资源。

mongodb shard集群配置参加 http://www.ttlsa.com/html/1096.html

判断是否shard

生产环境下,常用分片方案:
Shard server: 使用Replica Sets,确保每个数据节点都具有备份、自动容错转移、自动恢复能力。
Config server: 使用三个配置服务器,确保元数据完整性(two-phase commit)。
Route server: 配合LVS,实现负载平衡,提高接入性能(high performance)。也可以通过mongodb驱动连接,mongodb://。

mongodb sharding cluster简易搭建方案:

如需转载请注明出处mongodb架构-mongodb分片集群与简易搭建方案 http://www.ttlsa.com/html/1787.html

ttlsa教程系列之mongodb——(五)mongodb架构-复制原理&复制集

mongodb集群:复制,复制集和分片。 强烈建议在生产环境中使用mongodb的复制功能。复制具有故障切换,读扩展,热备份和离线批处理操作。
默认情况下,主节点负责客户端所有的读写请求,从节点不可读不可写。

一. 工作原理
1. mongodb的复制至少需要两个实例。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
2. 主节点的操作记录称为oplog(operation log),存储在local数据库中(local数据库不会被复制,用来存放复制状态信息的)。oplog中的每个文档代表着主节点上执行的操作。oplog只作为从节点与主节点保持数据同步的机制。
3. oplog.rs是一个固定长度的capped collection。默认情况下,64位的实例将使用oplog 5%的可用空间,这个空间将在local数据库中分配,并在服务器启动时预先分配。
4. 如果从节点落后主节点很远了,oplog日志从节点还没执行完,oplog可能已经轮滚一圈了,那么从节点将会追赶不上主节点了,复制将会停止。从节点需要重新做完整的同步,可以用{resync:1}命令来手动执行重新同步或在启动从节点时指定–autoresync选项让其自动重新同步。重新同步的代价昂贵,应尽量避免,避免的方法就是配置足够大的oplog。
查看oplog信息:

查看oplog.rs内容:

字段说明:
ts:操作的时间戳,用于跟踪操作执行的时间。
op:操作类型,i代表插入,u代表更新,d代表delete
ns:执行操作的集合名
o: 文档内容

二. 复制
mongodb支持传统的master-slave架构。没有自动故障转移功能,需要指定master和slave端。强烈推荐使用复制集架构,复制集架构比复制架构更好维护,功能更强。
master-slave架构一般使用于下面两种情况:
1. slave超过11个
2. 需要复制单一的数据库

master-salve架构配置:
// master server启动master,只需指定master参数

// slave server启动slave,需要指定slave参数和master的IP和端口

主从复制的选项有:
1. –only 在slave节点上指定只复制的数据库
2. –slavedelay 指定slave节点延时多少秒同步master
3. –fastsync 以master节点的数据快照为基础启动slave节点
4. –autoresync 如果slave节点不同步了,则主动重新同步
5. –oplogSize master节点oplog大小

三. 复制集
复制集最少需要三台服务器或两台服务器+仲裁一台。
复制集的配置参见:http://www.ttlsa.com/html/1093.html

查看master 的oplog元数据信息:

字段说明:
configured oplog size: oplog文件大小
log length start to end: oplog日志的启用时间段
oplog first event time: 第一个事务日志的产生时间
oplog last event time: 最后一个事务日志的产生时间
now: 现在的时间

查看slave的同步状态:

字段说明:
source:从库的IP以及端口
syncedTo:当前的同步情况

增加节点:

减少节点:

允许从库读操作:

手动转移primary:

复制集状态:
1. STARTUP:刚加入到复制集中,配置还未加载
2. STARTUP2:配置已加载完,初始化状态
3. RECOVERING:正在恢复,不适用读
4. ARBITER: 仲裁者
5. DOWN:节点不可到达
6. UNKNOWN:未获取其他节点状态而不知是什么状态,一般发生在只有两个成员的架构,脑裂
7. REMOVED:移除复制集
8. ROLLBACK:数据回滚,在回滚结束时,转移到RECOVERING或SECONDARY状态
9. FATAL:出错。查看日志grep “replSet FATAL”找出错原因,重新做同步
10. PRIMARY:主节点
11. SECONDARY:备份节点

四. 复制认证
如果启用了认证,需要在主节点和从节点上的local数据库下,建个相同的用户名和密码的用户,可读写。 从节点连接主节点时,会用存储在local.system.users中的用户进行认证,最先尝试用repl用户,若没有,则用local.system.users中的第一个可用用户。

五. 分片
分片下一节说。

转载请注明出处: http://www.ttlsa.com/html/1679.html

一分钟搭建mongodb架构Replica Set&Sharding—ttlsa教程系列之mongodb(七)

在测试试验阶段,我们需要有一个模拟的测试环境来测试应用程序和系统架构各个方面的功能,是否符合需求。在我公司,我常常使用下面的方法来为开发人员搭建mongodb的复制集和分片架构进行测试。我也常用这个方法来模拟线上架构,测试相关内容。
开启一个MongoDB shell,不连接任何mongod

创建复制集,一个primary两个secondary

启动三个mongod实例

复制集初始化

启动了三个实例,分别监听在31000,31001,31002端口上

当前MongoDB shell窗口会有大量的日志信息输出,影响操作,另开启一个MongoDB shell

插入1000条文档

创建第二个连接,连接到secondary

允许secondary可读

尝试想secondary写数据

可看到secondary不接收客户端写操作

测试复制集的automatic failover功能:
shutdown 31000实例

查看哪个实例变成primary

可见31002实例变成新的master

关闭replica set

sharding简易搭建方法参见: http://www.ttlsa.com/html/1787.html

转载请注明出处:一分钟搭建mongodb架构Replica Set&Sharding http://www.ttlsa.com/html/1830.html

mongodb备份与恢复(下)—ttlsa教程系列之mongodb(九)

一. 适用于mongodb任何架构(standalon、replic set、sharding)备份脚本
需要安装perl的MongoDB模块,安装方法参见:使用cpanm安装perl相关模块 http://www.ttlsa.com/html/2030.html 。代码这东西,仁者见仁智者见智,一分价钱一分货,所以对于优秀的程序员不要抠门。对语言的熟练度高,编程经验丰富的程序员,写出来的代码,两个字:漂亮!

下面的脚本只需更改变量$mongodb相关参数即可,如有更好的更便捷的方法请赐教。