标签归档:MongoDB

Spring Data for Mongo 介绍

本文将快速介绍Spring Data for Mongo的使用。
Spring Data for MongoDB是Spring Data的一个子模块。 目标是为MongoDB提供一个相近的一致的基于Spring的编程模型。
Spring Data for MongoDB核心功能是映射POJO到Mongo的DBCollection中的文档,并且提供Repository 风格数据访问层。相似的ORM/持久化框架还有morphia: MongoDB官方支持的ORM框架,可以很好的和Spring, Guice等DI框架集成,使用起来很方便。
Hibernate OGM: Hibernate提供了Hibernate风格的NoSql ORM框架。
jongo: 提供Mongo shell一样灵活的查询,并且提供ORM by Jackson,和Mongo java driver一样快。

特性:

可以通过@Configuration注解或者XML风格配置
MongoTemplate 辅助类 (类似JdbcTemplate),方便常用的CRUD操作
异常转换
丰富的对象映射
通过注解指定对象映射
持久化和映射声明周期事件
通过MongoReader/MongoWriter 定义底层的映射
基于Java的Query, Criteria, Update DSL
自动实现Repository,可以提供定制的查找
QueryDSL 支持类型安全的查询
跨数据库平台的持久化 - 支持JPA with Mongo
GeoSpatial 支持
Map-Reduce 支持
JMX管理和监控
CDI 支持
GridFS 支持

本文介绍的Spring Data for MongoDB版本为1.7.0.M1。

Spring Data for MongoDB提供了两种编程风格来应用MongoDB,下面逐一介绍这两种方式。
Spring Data Repository 风格

Spring Data提供了repository 抽象方式,可以极大的减少数据访问层千篇一律的类似的重复的代码。 基本DAO都会实现,find,findAll, findById, save, delete,update等方法,而且代码逻辑基本一致。Spring Data提供了简化方法,通过接口定义 Spring Data通过Proxy自动提供具体的实现。
这里有一篇介绍文章。
核心概念

Spring Data最重要的接口是Repository。它使用域类型和它的ID类型作为类型参数。

public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {

<S extends T> S save(S entity);

T findOne(ID primaryKey);

Iterable<T> findAll();

Long count();

void delete(T entity);

boolean exists(ID primaryKey);

// … more functionality omitted.
}

同时也提供特定数据库的接口: JpaRepository和 MongoRepository。 这些接口继承CrudRepository。 CrudRepository之上还有一个接口PagingAndSortingRepository提供分页的功能。

public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {

Iterable<T> findAll(Sort sort);

Page<T> findAll(Pageable pageable);
}

可以增加一些特定的统计和删除方法。

public interface UserRepository extends CrudRepository<User, Long> {
Long countByLastname(String lastname);
}

public interface UserRepository extends CrudRepository<User, Long> {
Long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
查询方法

标准的CRUD功能的repositories一般会提供一些查询方法。在Spring Data中只需四步。
1) 声明一个子接口: interface PersonRepository extends Repository<User, Long> { … }
2) 声明查询方法

interface PersonRepository extends Repository<User, Long> {
List<Person> findByLastname(String lastname);
}

3) 设置Spring为这些接口产生Proxy实例:两种方式。

import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@EnableJpaRepositories
class Config {}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/data/jpa

http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<jpa:repositories base-package="com.acme.repositories"/>

</beans>

4) 注入此repository实例并使用它

public class SomeClient {

@Autowired
private PersonRepository repository;

public void doSomething() {
List<Person> persons = repository.findByLastname("Matthews");
}
}
定义repository 接口

第一步就是为特定的domain类定义相应的定义repository。
调整repository 定义

典型的,repository 接口应该继承Repository,CrudRepository,PagingAndSortingRepository。 如果你不想继承这些接口,使用@RepositoryDefinition注解标记此接口为repository。
@NoRepositoryBean增加一些非典型的方法,然后在domain class Repository继承它。

@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {

T findOne(ID id);

T save(T entity);
}

interface UserRepository extends MyBaseRepository<User, Long> {
User findByEmailAddress(EmailAddress emailAddress);
}
定义查询方法

repository proxy有两种方式根据方法导出数据库特定的语句。 一种是根据方法名直接导出。 另一种是是手工定义。
Query lookup策略

通过XML方式的query-lookup-strategy 属性或者${store}注解的queryLookupStrategy 指定。

CREATE: 根据方法名
USE_DECLARED_QUERY: 通过注解或者其它方式得到
CREATE_IF_NOT_FOUND: 复合前面两种

Query creation

方法名应该是find…By, read…By, query…By, count…By, and get…By这样的格式。可以设置Distinct 和And, Or:

public interface PersonRepository extends Repository<User, Long> {

List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
Property expressions

假定Person有Address, Address有ZipCode 属性。
List<Person> findByAddressZipCode(ZipCode zipCode); 会使用x.address.zipCode遍历。
更明确的用:

List<Person> findByAddress_ZipCode(ZipCode zipCode);
特殊参数

Page<User> findByLastname(String lastname, Pageable pageable);
Slice<User> findByLastname(String lastname, Pageable pageable);
List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);
限制查询结果

User findFirstByOrderByLastname();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
产生repository实例
XML配置方式

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/data/jpa

http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<repositories base-package="com.acme.repositories" />
</beans:beans>

使用筛选器:

<repositories base-package="com.acme.repositories">
<context:exclude-filter type="regex" expression=".*SomeRepository" />
</repositories>
JavaConfig方式

使用@Enable${store}Repositories注解。如EnableMongoRepositories, EnableJpaRepositories

@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {

@Bean
public EntityManagerFactory entityManagerFactory() {
// …
}
}
编程方式

RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);
定制Repository实现

如果觉得默认的约定不够,可以定制实现。

interface UserRepositoryCustom {
public void someCustomMethod(User user);
}

class UserRepositoryImpl implements UserRepositoryCustom {

public void someCustomMethod(User user) {
// Your custom implementation
}
}

注意实现名是接口名加Impl。 不过可以定制后缀。

<repositories base-package="com.acme.repository" />
<repositories base-package="com.acme.repository" repository-impl-postfix="FooBar" />

你可以到这里下载例子。
相关文件:
文件    描述
config/MongoConfig    Spring配置文件,替代Spring XML配置文件
entity/Customer    domain object
entity/Address    domain object
repository/CustomerRepository    DAO层接口
APP    测试类
MongoTemplate方式

以上啰嗦了很多,感觉和Mongo关系不大。 这是Spring Data为各种数据库如JPA,Mongo提供的一种统一的方式。 理论上来说,无论你使用Mysql, Oracle,Mongo,都可以采用这种方式组织你的代码。

但是, Spring Data for MongoDB还提供了另外一种方式, 类似JdbcTemplate的方式。 这种方式你可以自己定义你的repository的编程方式。 这种方式让你感觉更灵活, 不被上面的各种约定束缚住。

你可以通过XML或者JavaConfig方式配置MongoTemplate.

1) JavaConfig方式

/*
* Use the standard Mongo driver API to create a com.mongodb.Mongo instance.
*/
public @Bean Mongo mongo() throws UnknownHostException {
return new Mongo("localhost");
}

或者

/*
* Factory bean that creates the com.mongodb.Mongo instance
*/
public @Bean MongoFactoryBean mongo() {
MongoFactoryBean mongo = new MongoFactoryBean();
mongo.setHost("localhost");
return mongo;
}

2) XML方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation=
"http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

*http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd*

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!-- Default bean name is 'mongo' -->
*<mongo:mongo host="localhost" port="27017"/>*

</beans>

可以设置更多的参数。

<beans>

<mongo:mongo host="localhost" port="27017">
<mongo:options connections-per-host="8"
threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="1000"
max-wait-time="1500}"
auto-connect-retry="true"
socket-keep-alive="true"
socket-timeout="1500"
slave-ok="true"
write-number="1"
write-timeout="0"
write-fsync="true"/>
</mongo:mongo/>

</beans>

如果你想将MongoTemplate配置成Spring Bean:

@Configuration
public class MongoConfiguration {

public @Bean MongoDbFactory mongoDbFactory() throws Exception {
UserCredentials userCredentials = new UserCredentials("joe", "secret");
return new SimpleMongoDbFactory(new Mongo(), "database", userCredentials);
}

public @Bean MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}

或者XML:

<mongo:db-factory id="anotherMongoDbFactory"
host="localhost"
port="27017"
dbname="database"
username="joe"
password="secret"/>
MongoTemplate

MongoTemplate提供了非常多的操作MongoDB的方法。 它是线程安全的,可以在多线程的情况下使用。
MongoTemplate实现了MongoOperations接口, 此接口定义了众多的操作方法如"find", "findAndModify", "findOne", "insert", "remove", "save", "update" and "updateMulti"等。
它转换domain object为DBObject,并提供了Query, Criteria, and Update等流式API。
缺省转换类为MongoMappingConverter。

它有几个构造函数:

MongoTemplate(Mongo mongo, String databaseName)
MongoTemplate(Mongo mongo, String databaseName, UserCredentials userCredentials)
MongoTemplate(MongoDbFactory mongoDbFactory)
MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter)

Repository

在这种方式下,你需要自己实现Repository的具体类。
一般情况下你需要为所有的Repository实现一个抽象的父类,在父类中实现大部分CRUD操作。 在子类中实现特定的操作方法。
你的Repository可以实现MongoRepository或者CrudRepository接口,但是不是必须的。
本例子中简单实现了一个简单的Repository,纯演示使用。

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import com.colobu.springmongo.entity.Customer;

@Repository
public class AnotherCustomerRepository {
@Autowired
private MongoTemplate mongoTemplate;

public Customer save(Customer c) {
mongoTemplate.save(c);
return c;
}

public void deleteAll() {
mongoTemplate.dropCollection(Customer.class);
}

public List<Customer> findAll() {
return mongoTemplate.findAll(Customer.class);
}

public List<Customer> findByLastname(String lastname, Sort sort){
Criteria criteria = new Criteria("lastname").is(lastname);
return mongoTemplate.find(new Query(criteria), Customer.class);
}

public GeoResults<Customer> findByAddressLocationNear(Point point, Distance distance){
return mongoTemplate.geoNear(NearQuery.near(point).maxDistance(distance), Customer.class);
}
}

在这种情况下,方法名比较自由,你毋须遵守某种约定。
参考文档

http://docs.spring.io/spring-data/data-mongo/docs/1.7.0.M1/reference/html/

PHP操作MongoDB

来源:互联网

<?php
error_reporting(7);

$conn = new Mongo();

$db = $conn->PHPDataBase;
$collection = $db->PHPCollection;

/*-----------------------------
* 删除
*-----------------------------
$collection->remove(array("name" => "xixi111"));
*/

/*------------------------------
* 插入
*------------------------------
for($i = 0;$i <= 50;$i++) {
$data = array("name" => "xixi".$i,"email" => "673048143_".$i."@qq.com","age" => $i*1+20);
$collection->insert($data);
}
*/

/*-------------------------------
* 查找
*-------------------------------
$res = $collection->find(array("age" => array('$gt' => 25,'$lt' => 40)),array("name" => true));

foreach($res as $v) {
print_r($v);
}
*/

/*-------------------------------
* 更新
*-------------------------------
$collection->update(array("age" =>22),array('$set' => array("name" => "demoxixi")));
*/
?>

复制代码

完成MongoDB的安装

完成PHP对MongoDB的扩展,重启apache

开启MongoDB服务,就像mysql一样。

然后就可以用PHP操作MongoDB了。

下面是我自己今天学习的一些笔记:

首先要能对概念有个清晰的理解。
新闻的增删改查。
首先是新闻添加,新闻标题,新闻作者,新闻内容。
然后是新闻的读取。MongoDB中的数据读取出来,通过PHP读取。
这里面的界面都是用HTML语言写的,这个是一样的。

传统的关系数据库一般由数据库、表、记录三个层次组成。
MongoDB是由数据库、集合、文档三个层次组成。
MongoDB采用的是面向文档的数据模型使其可以自由在多台服务器之间分割数据。
它还可以平衡集群的数据和负载,自动重排文档。

支持:
索引
可以存储Javascript
文件存储

不支持:
join和复杂的多行事务

文档是MongoDB中数据的基本单元(类似于关系型数据库中的行)
类似的,集合可以被看做是没有模式的表。

多个键及其关联的值有序地放置在一起便是文档。
{"greeting":"Hello,world!"}
这个文档只有一个键"greeting",其对应的值为"Hello,world!"
{"greeting":"Hello,world!","foo":3}

MongoDB不但区分类型,而且区分大小写:
{"foo":3}
{"foo":"3"}

{"foo":3}
{"Foo":3}
都是不同的

还有一个非常重要的事项,MongoDB文档不能有重复的键。下面的文档时非法的:
{"greeting":"Hello,world!","greeting":"Hello,MongoDB"}

集合
集合就是一组文档。如果说MongoDB中的文档类似于关系型数据库中的行,那么集合就如同表。

集合是无模式的,这意味着一个集合里面的文档可以是各式各样的。
例如下面的文档可以存在于同一个集合里:
{"greeting":"Hello,world!"}
{"foo":5}

把同种类型的文档放在一个集合里,这样数据会更加集中。

MongoDB中多个文档组成集合,同样多个集合可以组成数据库。

数据库名最终会变成文件系统里的文件。

CRUD
插入:
insert函数添加一个文档到集合里面。例子:db.blog.insert(post)。
读取:
find读取集合里的文档。例子:db.blog.find()。
若是想查看一个文档,可以用findOne。
更新:
update。update接受两个参数,第一个是要更新文档的限定条件,第二个是新的文档。
例子:db.blog.update({title:"My Blog Post"},post)
删除:
remove。它可以接受一个文档以指定限制条件。
db.blog.remove({title:"My Blog Post"})

MongoDB字段类型
null:
null用于表示空值或者不存在的字段。{"x":null}
布尔:
布尔类型有两个值'true'和'false':
{"x":true}

32位整数:
64位整数:

64位浮点数:shell中的数字都是这种类型。
{"x":3.14}
这也是一个浮点数
{"x":3}

字符串:
{"x":"foobar"}
符号:
对象id:
日期:
正则表达式:
{"x":/foobar/i}
代码:
{"x":function(){/*...*/}}
二进制数据:
最大值:
最小值:
未定义:
{"x":undefined}
数组:
{"x":["a","b","c"]}
内嵌文档:
{"x":{"foo":"bar"}}

相关文章:

MongoDB基本操作指南
NoSQL数据库
MongoDB集群
MongoDB数据库
MongoDB备份与恢复
8种NoSQL数据库对比
配置mongodb分片群集(sharding cluster)
记一次MongoDB性能问题,附原理解析
mongodb之insert和save函数的区别
mongodb shell无法删除问题 与 secureCRT使用退格键出现^H解决办法
Mongodb源码分析之Mongos分析
PHP操作MongoDB

 

8种NoSQL数据库对比

来源:互联网

相关文章:

MongoDB基本操作指南
NoSQL数据库
MongoDB集群
MongoDB数据库
MongoDB备份与恢复
8种NoSQL数据库对比
配置mongodb分片群集(sharding cluster)
记一次MongoDB性能问题,附原理解析
mongodb之insert和save函数的区别
mongodb shell无法删除问题 与 secureCRT使用退格键出现^H解决办法
Mongodb源码分析之Mongos分析
PHP操作MongoDB

 

虽然SQL数据库是非常有用的工具,但经历了15年的一支独秀之后垄断即将被打破。这只是时间问题:被迫使用关系数据库,但最终发现不能适应需求的情况不胜枚举。NoSQL: 是一项全新的数据库革命性运动,NoSQL的拥护者们提倡运用非关系型的数据存储。现今的计算机体系结构在数据存储方面要求具备庞大的水平扩展性,而 NoSQL致力于改变这一现状。目前Google的BigTable和Amazon的Dynamo使用的就是NoSQL型数据库。参见NoSQL词条。

image

但是NoSQL数据库之间的不同,远超过两SQL数据库之间的差别。这意味着软件架构师更应该在项目开始时就选择好一个适合的NoSQL数据库。针对这种情况,这里对Cassandra、Mongodb、CouchDB、Redis、Riak、Membase、Neo4j和HBase进行了比较:

1.CouchDB

  • 所用语言:Erlang
  • 特点:DB一致性,易于使用
  • 使用许可:Apache
  • 协议:HTTP/REST
  • 双向数据复制,
  • 持续进行或临时处理,
  • 处理时带冲突检查,
  • 因此,采用的是master-master复制(master-master复制:是一种数据库同步方法,允许数据在一组计算机之间共享数据,并且可以通过小组中任意成员在组内进行数据更新。)
  • MVCC-写操作不阻塞读操作
  • 可保存文件之前的版本
  • Crash-only(可靠的)设计
  • 需要不时地进行数据压缩
  • 视图:嵌入式映射/减少
  • 格式化视图:列表显示
  • 支持进行服务器端文档验证
  • 支持认证
  • 根据变化实时更新
  • 支持附件处理
  • 因此,CouchApps(独立的js应用程序)
  • 需要jQuery程序库

最佳应用场景:适用于数据变化较少,执行预定义查询,进行数据统计的应用程序。适用于需要提供数据版本支持的应用程序。

例如:CRM、CMS系统。master-master复制对于多站点部署是非常有用的。

2.Redis

  • 所用语言:C/C++
  • 特点:运行异常快
  • 使用许可:BSD
  • 协议:类Telnet
  • 有硬盘存储支持的内存数据库,
  • 但自2.0版本以后可以将数据交换到硬盘(注意,2.4以后版本不支持该特性!)
  • Master-slave复制(Master-slave复制:如果同一时刻只有一台服务器处理所有的复制请求,这被称为Master-slave复制,通常应用在需要提供高可用性的服务器集群。)
  • 虽然采用简单数据或以键值索引的哈希表,但也支持复杂操作,例如ZREVRANGEBYSCORE。
  • INCR&co(适合计算极限值或统计数据)
  • 支持sets(同时也支持union/diff/inter)
  • 支持列表(同时也支持队列;阻塞式pop操作)
  • 支持哈希表(带有多个域的对象)
  • 支持排序sets(高得分表,适用于范围查询)
  • Redis支持事务
  • 支持将数据设置成过期数据(类似快速缓冲区设计)
  • Pub/Sub允许用户实现消息机制

最佳应用场景:适用于数据变化快且数据库大小可遇见(适合内存容量)的应用程序。

例如:股票价格、数据分析、实时数据搜集、实时通讯。

3.MongoDB

  • 所用语言:C++
  • 特点:保留了SQL一些友好的特性(查询,索引)。
  • 使用许可:AGPL(发起者:Apache)
  • 协议:Custom,binary(BSON)
  • Master/slave复制(支持自动错误恢复,使用sets复制)
  • 内建分片机制
  • 支持javascript表达式查询
  • 可在服务器端执行任意的javascript函数
  • update-in-place支持比CouchDB更好
  • 在数据存储时采用内存到文件映射
  • 对性能的关注超过对功能的要求
  • 建议最好打开日志功能(参数--journal)
  • 在32位操作系统上,数据库大小限制在约2.5Gb
  • 空数据库大约占192Mb
  • 采用GridFS存储大数据或元数据(不是真正的文件系统)

最佳应用场景:适用于需要动态查询支持;需要使用索引而不是map/reduce功能;需要对大数据库有性能要求;需要使用CouchDB但因为数据改变太频繁而占满内存的应用程序。

例如:你本打算采用MySQL或PostgreSQL,但因为它们本身自带的预定义栏让你望而却步。

http://www.iigrowing.cn/tags/mongodb

4.Riak

  • 所用语言:Erlang和C,以及一些Javascript
  • 特点:具备容错能力
  • 使用许可:Apache
  • 协议:HTTP/REST或者custombinary
  • 可调节的分发及复制(N,R,W)
  • 用JavaScriptorErlang在操作前或操作后进行验证和安全支持。
  • 使用JavaScript或Erlang进行Map/reduce
  • 连接及连接遍历:可作为图形数据库使用
  • 索引:输入元数据进行搜索(1.0版本即将支持)
  • 大数据对象支持(Luwak)
  • 提供“开源”和“企业”两个版本
  • 全文本搜索,索引,通过Riak搜索服务器查询(beta版)
  • 支持Masterless多站点复制及商业许可的SNMP监控

最佳应用场景:适用于想使用类似Cassandra(类似Dynamo)数据库但无法处理bloat及复杂性的情况。适用于你打算做多站点复制,但又需要对单个站点的扩展性,可用性及出错处理有要求的情况。

例如:销售数据搜集,工厂控制系统;对宕机时间有严格要求;可以作为易于更新的web服务器使用。

5.Membase

  • 所用语言:Erlang和C
  • 特点:兼容Memcache,但同时兼具持久化和支持集群
  • 使用许可:Apache2.0
  • 协议:分布式缓存及扩展
  • 非常快速(200k+/秒),通过键值索引数据
  • 可持久化存储到硬盘
  • 所有节点都是唯一的(master-master复制)
  • 在内存中同样支持类似分布式缓存的缓存单元
  • 写数据时通过去除重复数据来减少IO
  • 提供非常好的集群管理web界面
  • 更新软件时软无需停止数据库服务
  • 支持连接池和多路复用的连接代理

最佳应用场景:适用于需要低延迟数据访问,高并发支持以及高可用性的应用程序

例如:低延迟数据访问比如以广告为目标的应用,高并发的web应用比如网络游戏(例如Zynga)

6.Neo4j

  • 所用语言:Java
  • 特点:基于关系的图形数据库
  • 使用许可:GPL,其中一些特性使用AGPL/商业许可
  • 协议:HTTP/REST(或嵌入在Java中)
  • 可独立使用或嵌入到Java应用程序
  • 图形的节点和边都可以带有元数据
  • 很好的自带web管理功能
  • 使用多种算法支持路径搜索
  • 使用键值和关系进行索引
  • 为读操作进行优化
  • 支持事务(用Javaapi)
  • 使用Gremlin图形遍历语言
  • 支持Groovy脚本
  • 支持在线备份,高级监控及高可靠性支持使用AGPL/商业许可

最佳应用场景:适用于图形一类数据。这是Neo4j与其他nosql数据库的最显著区别

例如:社会关系,公共交通网络,地图及网络拓谱

7.Cassandra

  • 所用语言:Java
  • 特点:对大型表格和Dynamo支持得最好
  • 使用许可:Apache
  • 协议:Custom,binary(节约型)
  • 可调节的分发及复制(N,R,W)
  • 支持以某个范围的键值通过列查询
  • 类似大表格的功能:列,某个特性的列集合
  • 写操作比读操作更快
  • 基于Apache分布式平台尽可能地Map/reduce
  • 我承认对Cassandra有偏见,一部分是因为它本身的臃肿和复杂性,也因为Java的问题(配置,出现异常,等等)

最佳应用场景:当使用写操作多过读操作(记录日志)如果每个系统组建都必须用Java编写(没有人因为选用Apache的软件被解雇)

例如:银行业,金融业(虽然对于金融交易不是必须的,但这些产业对数据库的要求会比它们更大)写比读更快,所以一个自然的特性就是实时数据分析

http://www.iigrowing.cn/tags/cassandra

8.HBase(配合ghshephard使用)

  • 所用语言:Java
  • 特点:支持数十亿行X上百万列
  • 使用许可:Apache
  • 协议:HTTP/REST(支持Thrift,Thrift是一种接口定义语言,为多种其他语言提供定义和创建服务,由Facebook开发并开源。)
  • 在BigTable之后建模
  • 采用分布式架构Map/reduce
  • 对实时查询进行优化
  • 高性能Thrift网关
  • 通过在server端扫描及过滤实现对查询操作预判
  • 支持XML,Protobuf,和binary的HTTP
  • Cascading,hive,andpigsourceandsinkmodules
  • 基于Jruby(JIRB)的shell
  • 对配置改变和较小的升级都会重新回滚
  • 不会出现单点故障
  • 堪比MySQL的随机访问性能

最佳应用场景:适用于偏好BigTable:)并且需要对大数据进行随机、实时访问的场合。

例如:Facebook消息数据库(更多通用的用例即将出现)

当然,所有的系统都不只具有上面列出的这些特性。这里我仅仅根据自己的观点列出一些我认为的重要特性。与此同时,技术进步是飞速的,所以上述的内容肯定需要不断更新。

相关文章:

MongoDB基本操作指南
NoSQL数据库
MongoDB集群
MongoDB数据库
MongoDB备份与恢复
8种NoSQL数据库对比
配置mongodb分片群集(sharding cluster)
记一次MongoDB性能问题,附原理解析
mongodb之insert和save函数的区别
mongodb shell无法删除问题 与 secureCRT使用退格键出现^H解决办法
Mongodb源码分析之Mongos分析
PHP操作MongoDB

 

Mongodb源码分析之Mongos分析

MongoDB提供了auto-sharding 功能。因为其是auto-sharding,即mongodb通过mongos(一个自动分片模块,用于构建一个大规模的可扩展的数据库集群,这个集群可 以并入动态增加的机器)自动建立一个水平扩展的数据库集群系统,将数据库分表存储在sharding的各个节点上。

MongoDB提供了auto-sharding 功能。因为其是auto-sharding,即mongodb通过mongos(一个自动分片模块,用于构建一个大规模的可扩展的数据库集群,这个集群可 以并入动态增加的机器)自动建立一个水平扩展的数据库集群系统,将数据库分表存储在sharding的各个节点上。

一个mongodb集群包括一些shards(包括一些mongod进程),mongos路由进程,一个或多个config服务器

下面是一些相关词汇说明:

Shards :每一个shard包括一个或多个服务和存储数据的mongod进程(mongod是MongoDB数据的核心进程)典型的每个shard开启多个服务来提高服务的可用性。这些服务/mongod进程在shard中组成一个复制集

Chunks:Chunk是一个来自特殊集合中的一个数据范围, (collection,minKey,maxKey)描叙一个chunk,它介于minKey和maxKey范围之间。例如chunks 的maxsize大小是100M,如果一个文件达到或超过这个范围时,会被切分到2个新的chunks中。当一个shard的数据过量时,chunks将 会被迁移到其他的shards上。同样,chunks也可以迁移到其他的shards上

Config Servers : Config服务器存储着集群的metadata信息,包括每个服务器,每个shard的基本信息和chunk信息Config服务器主要存储的是chunk信息。每一个config服务器都复制了完整的chunk信息。

今天要介绍的源码主要是Mongos的主入口函数的执行流程,首先我们打开Mongos的项目(可通过打开源码db\db_10.sln加载所有项目),如下图:

wps_clip_image-17594[3][1]

注:如果要调试mongos,需要设置一个mongod进程和一个Config Server,形如:

d:\mongodb>bin>mongod --dbpath d:\mongodb\db\ --port 27012

d:\mongodb>bin>mongod --configsvr --dbpath d:\mongodb\db\ --port 27022

然后在vs2010中配置相应的boost路径信息及启动参数信息,如下图:

wps_clip_image-27122[4][1]

wps_clip_image-5075[4][1]

wps_clip_image-18371[4][1]

下面开始正文。首先打开mongos项目中的server.cpp文件,找到下面方法:

int main(int argc, char* argv[]) {

try {

return _main(argc, argv);

}

catch(DBException& e) {

cout << "uncaught exception in mongos main:" << endl;

cout << e.toString() << endl;

}

catch(std::exception& e) {

cout << "uncaught exception in mongos main:" << endl;

cout << e.what() << endl;

}

catch(...) {

cout << "uncaught exception in mongos main" << endl;

}

return 20;

}

方法是mongos的主函数,代码很简,它主要是try方式执行_main方法,下面是_main的执行流程:

int _main(int argc, char* argv[]) {

static StaticObserver staticObserver;

mongosCommand = argv[0];

//声明options信息描述对象

po::options_description options("General options");

po::options_description sharding_options("Sharding options");

po::options_description hidden("Hidden options");

po::positional_options_description positional;

CmdLine::addGlobalOptions( options , hidden );

//添加sharding选项描述信息

sharding_options.add_options()

( "configdb" , po::value() , "1 or 3 comma separated config servers" )

( "test" , "just run unit tests" )

( "upgrade" , "upgrade meta data version" )

( "chunkSize" , po::value(), "maximum amount of data per chunk" )

( "ipv6", "enable IPv6 support (disabled by default)" )

( "jsonp","allow JSONP access via http (has security implications)" )

;

options.add(sharding_options);

.....

在完成option描述信息的初始化操作之后,下面就开始对启动命令行参数进行分析和执行了,如下:

.....

// parse options

po::variables_map params;

//对argc,argv进行分析并转换成params,以便下面使用

if ( ! CmdLine::store( argc , argv , options , hidden , positional , params ) )

return 0;

// The default value may vary depending on compile options, but for mongos

// we want durability to be disabled.

cmdLine.dur = false;

//如果是help

if ( params.count( "help" ) ) {

cout << options << endl;

return 0;

51     }

//如果是版本信息

if ( params.count( "version" ) ) {

printShardingVersionInfo();

return 0;

}

//如要设置chunkSize

if ( params.count( "chunkSize" ) ) {

Chunk::MaxChunkSize = params["chunkSize"].as() * 1024 * 1024;

}

......

//必选项,设置configdb信息

if ( ! params.count( "configdb" ) ) {

out() << "error: no args for --configdb" << endl;

return 4;

}

vector configdbs;

//对参数configdb进行分割 (以','分割 )

splitStringDelim( params["configdb"].as() , &configdbs , ',' );

//mongodb强制为1或3,具体原因不明

if ( configdbs.size() != 1 && configdbs.size() != 3 ) {

out() << "need either 1 or 3 configdbs" << endl;

return 5;

}

// we either have a seeting were all process are in localhost or none is

for ( vector::const_iterator it = configdbs.begin() ; it != configdbs.end() ; ++it ) {

try {

// 根据地址参数实例化HostAndPort对象,如地址不合法则抛出异常

HostAndPort configAddr( *it );

if ( it == configdbs.begin() ) {

grid.setAllowLocalHost( configAddr.isLocalHost() );

}

//不允许在configdbs出现本地地址,注:如果configdb中全部为本地地址

//(实际用处不大)时不会执行下面if逻辑

if ( configAddr.isLocalHost() != grid.allowLocalHost() ) {

out() << "cannot mix localhost and ip addresses in configdbs" << endl;

return 10;

}

}

catch ( DBException& e) {

out() << "configdb: " << e.what() << endl;

return 9;

}

}

上面完成了对命令行参数分析之后,接下来mongos要加载绑定几个hook:

// set some global state

//添加对链接池hook的绑定(shardingConnectionHook对象引用),以最终调用其onHandedOut方法

pool.addHook( &shardingConnectionHook );

//设置链接池名称

pool.setName( "mongos connectionpool" );

//不设置“延迟kill游标”

DBClientConnection::setLazyKillCursor( false );

//设置当replicaSet配置修改时的hook对象(replicaSetChangey方法会更新链接对象信息

ReplicaSetMonitor::setConfigChangeHook( boost::bind( &ConfigServer::replicaSetChange , &configServer , _1 ) );

上面的hook主要是在mongos主程序启动完成后,在运行期间执行一些数据操作时执行某些额外操作。从代码可以看出,mongos使用了链接池 功能以提升获取链接的效率,具体实现机制我会在后绪章节中加以阐述。代码中的ReplicaSetMonitor类为一个维护和获取有效复制集的监视类, 它提供了获取有效master,slave 的方法。完成这一步绑定后,接着mongos就会对config server信息进行初始化和升级操作了,如下:

//显示sharding版本信息

printShardingVersionInfo();

//实始化configServer

if ( ! configServer.init( configdbs ) ) {

cout << "couldn't resolve config db address" << endl;

return 7;

}

if ( ! configServer.ok( true ) ) {

cout << "configServer startup check failed" << endl;

return 8;

}

//检查Config版本信息(必要时进行升级操作)

int configError = configServer.checkConfigVersion( params.count( "upgrade" ) );

if ( configError ) {

if ( configError > 0 ) {

cout << "upgrade success!" << endl;

}

else {

cout << "config server error: " << configError << endl;

}

return configError;

}

//重新设置config db信息(包括shard中chunk的min,lastmod信息)

configServer.reloadSettings();

就是启动侦听服务,这里mongos启动了两个侦听服务器,一个是以线程方式启动,用于接收授权的用户操作信息,另一个则是普遍的循环侦听服务,用于侦听客户端message如下:

//初始化一些Signals信息,用于处理程序退出,中断等情况

init();

//以线程方式启动webserver,循环侦听授权访问的 message信息,详见dbwebserver.cpp文件中allowed方法

boost::thread web( boost::bind(&webServerThread, new NoAdminAccess() /* takes ownership */) );

MessageServer::Options opts;

opts.port = cmdLine.port;

opts.ipList = cmdLine.bind_ip;

start(opts);//启动message服务器,侦听客户端message

dbexit( EXIT_CLEAN );

return 0;

到这里,main代码就介绍完了,但上面代码段中的start才是启动balancer来均衡各个shard间chunk的操作,所以我们接着再看一下该方法的实现:

void start( const MessageServer::Options& opts ) {

setThreadName( "mongosMain" );//设置线程名称

installChunkShardVersioning();//绑定chunk shard版本控制信息

balancer.go();//均衡shard 中chunk(节点)信息,详情参见 balance.cpp的run()方法

cursorCache.startTimeoutThread();//对空闲(过期)游标进行清除操作

log() << "waiting for connections on port " << cmdLine.port << endl;

ShardedMessageHandler handler;

MessageServer * server = createServer( opts , &handler );//构造server对象

server->setAsTimeTracker();

server->run();//启动message服务

}

好了,今天的内容到这里就告一段落了,在接下来的文章中,将会介绍balancer的实现方式和操作流程。

原文链接:http://www.cnblogs.com/daizhj/archive/2011/05/16/2022041.html

 

相关文章:

MongoDB基本操作指南
NoSQL数据库
MongoDB集群
MongoDB数据库
MongoDB备份与恢复
8种NoSQL数据库对比
配置mongodb分片群集(sharding cluster)
记一次MongoDB性能问题,附原理解析
mongodb之insert和save函数的区别
mongodb shell无法删除问题 与 secureCRT使用退格键出现^H解决办法
Mongodb源码分析之Mongos分析
PHP操作MongoDB

来源:互联网

记一次MongoDB性能问题,附原理解析

来源:互联网

下面文章转载自火丁笔记,原作者描述了一次MongoDB数据迁移过程中遇到的性能问题及其解决方案,中间追查问题的方法和工具值得我们学习。

下面是其原文:

最近忙着把一个项目从MySQL迁移到MongoDB,在导入旧数据的过程中,遇到了些许波折,犯了不少错误,但同时也学到了不少知识,遂记录下来。

公司为这个项目专门配备了几台高性能务器,清一色的双路四核超线程CPU,外加32G内存,运维人员安装好MongoDB后,就轮到我了,我习惯于在使用新服务器前先看看相关日志,了解一下基本情况,当我浏览MongoDB日志时,发现一些警告信息:

WARNING: You are running on a NUMA machine.
We suggest launching mongod like this to avoid performance problems:
numactl --interleave=all mongod [other options]

当时我并不太清楚NUMA是什么东西,所以没有处理,只是把问题报告给了运维人员,事实证明运维人员也没有处理,所以问题的序幕就这样拉开了…

迁移工作首先要导入旧数据。开始一切倒还正常,不过几小时之后,我无意中发现不知道什么时候开始数据导入的速度下降了,同时我的PHP脚本开始不停的抛出异常:

cursor timed out (timeout: 30000, time left: 0:0, status: 0)

我一时判断不出问题所在,想想先在PHP脚本里加大Timeout的值应付一下:

MongoCursor::$timeout = -1;

可惜这样并没有解决问题,错误反倒变着花样的出现了:

max number of retries exhausted, couldn't send query
couldn't send query: Broken pipe

无奈之下用strace跟踪了一下PHP脚本:

shell> strace -p

发现进程卡在了recvfrom操作上:

recvfrom(,

通过如下命令查询recvfrom操作的含义是:receive a message from a socket

shell> apropos recvfrom

还可以按照下面的方式确认一下:

shell> lsof -p
shell> ls -l /proc//fd/

此时查询MongoDB当前操作,发现几乎每个操作会消耗大量的时间:

shell> echo "db.currentOp()" | /path/to/mongo

同时运行mongostat显示很高的locked值。

重复做了很多工作,但始终无法找到问题的症结在哪里,只好求助官方论坛,那里的技术支持都很热心,在我描述了问题后,没过多久就有了回复,建议我检查一下是不是索引不佳所致,为了验证这种可能,我激活了Profiler记录慢操作:

mongo> use
mongo> db.setProfilingLevel(1);

不过结果显示基本都是insert操作(因为我是导入数据为主),本身就不需要索引:

mongo> use
mongo> db.system.profile.find().sort({$natural:-1})

问 题到了这里,似乎已经走投无路了,为了死马当活马医,我又重复了几次迁移旧数据的过程,结果自然是次次都出问题,但幸运的是我发现每当出问题的时候,在 top命令的结果中,总有一个名叫irqbalance的进程居高不下,搜索了一下,结果很多介绍irqbalance的文章中都提及了NUMA,让我一 下子记起之前在日志中看到的警告信息,于是乎按照信息里介绍的,重新启动了一下MongoDB:

shell> numactl --interleave=all /path/to/mongod

一切都正常了。为了解决这个问题,浪费了很多精神,实在没有力气再解释NUMA到底是什么东西了,有想了解的网友可以参考老外的文章,里面的介绍很翔实。

对于罪魁祸首,作者留给大家去学习,在这里可以给大家做一个简单的描述,先解释几个概念

NUMA:NUMA是多核心CPU架构中的一种,其全称为Non-Uniform Memory Access,简单来说就是在多核心CPU中,机器的物理内存是分配给各个核的,架构简图如下所示:

mongodb0001

记一次MongoDB性能问题,附原理解析 - PHP网站开发 - 每日最新博客在置顶博客之后

每个核访问分配给自己的内存会比访问分配给其它核的内存要快,有下面几种访问控制策略:

1.缺省(default):总是在本地节点分配(分配在当前进程运行的节点上);
2.绑定(bind):强制分配到指定节点上;
3.交叉(interleave):在所有节点或者指定的节点上交织分配;
4.优先(preferred):在指定节点上分配,失败则在其他节点上分配。

上面文章中最后使用numactl –interleave命令就是指定其为交叉共享模式。

irqbalance:这是作者在上面提到的一个占用CPU的进程,这个进程的作用是在多核心CPU的操作系统中,分配系统中断信号的。参见:irqbalance.org

概念说完了,下面是上面问题的简单描述:

我们知道虚拟内存机制是通过一个中断信号来通过进行内存swap的,所以这个irqbalance进程忙,是一个危险信号,在这里是由于在进行频繁 的内存交换。这种频繁交换现象称为swap insanity,在MySQL中经常提到,也就是在NUMA框架中,采用不合适的策略,导致核心只能从指定内存块节点上分配内存,即使总内存还有富余, 也会由于当前节点内存不足时产生大量的swap操作。

http://blog.163.com/lgh_2002/blog/static/4401752620130152575313/

相关文章:

MongoDB基本操作指南
NoSQL数据库
MongoDB集群
MongoDB数据库
MongoDB备份与恢复
8种NoSQL数据库对比
配置mongodb分片群集(sharding cluster)
记一次MongoDB性能问题,附原理解析
mongodb之insert和save函数的区别
mongodb shell无法删除问题 与 secureCRT使用退格键出现^H解决办法
Mongodb源码分析之Mongos分析
PHP操作MongoDB