大数据面临问题:存储 、 分析
存储: 数据库 RMDBS 关系型数据库(MySQL、ORACLE)表 存储
RMDBS: 分库 –> 解决存储
缺点: 不稳定,维护成本高、极大的限制
查询 (只能通过 片键 去查)
性能:基于磁盘 修改|查询>动用磁盘IO 慢 coonection连接数 有限 无法应对 高并发
解决:cache(无法保证缓存和db数据高度一致性) | 读写分离
分析:并没有很好的算法支持分析
解决方案:
存储:NoSQL (not only SQL)并不是替换 RMDBS 而是一种补充
① 很好的集群支持(主从、副本集、分片、分片+副本集)
② 很好的性能 基于内存 支持高并发
摒弃RMDBS的要求:
1、schemaless 弱化表结构
2、弱化事务、弱化约束
NoSQL:Redis 、MongoDB、HBase
1、redis:key-value Map 键值对 内存
2、MongoDB:文档(json) 不支持事务 磁盘 利用率高
3、HBase :列存储 大数据随机访问 10亿行*百万列 量级
MongoDB:
特点
1.不支持事务
2.基于磁盘存储
3.单条记录不得超过16M
4.没有表结构没有约束
与RDBMS对比
RDBMS: 磁盘利用率低
Mongodb:磁盘利用率高 插入速度快
MongoDB安装与使用
1,解压
[root@zpark ~]# tar -zxf mongodb-linux-i686-3.0.6.gz -C /usr/
2.启动MongoDB
参考:[root@zpark mongodb]# ./bin/mongod -h查看启动参数
[root@zpark mongodb]# ./bin/mongod –port 27017 –dbpath ~/db/data/ –journal
3.连接mongo
参考:[root@zpark mongodb]# ./bin/mongo -h
[root@zpark mongodb]# ./bin/mongo –port 27017
1.数据库操作
查看库
db
查看所有库
show databases|dbs
创建库
use 数据库名
删除
db.dropDatabase();
建表>db.createCollection(‘t_user’)
查表>show tables|collections
db.getCollectionNames();
删除表>db.表名.drop();
1.保存
db.表名.save/insert({document});
2.修改 ($set / $inc /$unset multi/upsert)
db.表名.update({query},{update}[,{options}])
db.t_user.update({id:1},{$set:{salary:12000}})
db.t_user.update({id:1},{$inc:{salary:12000}})
db.t_user.update({id:1},{$unset:{salary:true}})
db.t_user.update({id:4},{$inc:{salary:500}},{multi:true,upsert:true})
3.删除
db.表名.remove({query})
4.查询
等值查
db.表名.findOne({query}[,{fieds}]) //返回一条记录 Document
db.表名.find({query}[,{fieds}])//返回多条 DBCursor 游标 只可以遍历一次
等值
db.t_user.find({id:1})
db.t_user.find({id:{$eq:1}})
不等值查 (> < >= <= != !) gt lt gte lte ne not
db.t_user.find({salary:{$gt:7000}})
AND 操作
db.t_user.find({salary:{$gt:10000,$lt:20000},sex:true})
OR | NOR
db.t_user.find({$or:[{id:1},{name:’lisi’}]})
db.t_user.find({$nor:[{id:1},{name:’lisi’}]})
IN | NIN
db.t_user.find({id:{$in:[1,2,3]}})
db.t_user.find({id:{$nin:[1,2,3]}})
判断field 是否存在 exists
db.t_user.find({name:{$exists:false}})
正则搜索 $regex 只适用于字符串
db.t_user.find({name:{$regex:’^[a-zA-Z]{4}$’}})
db.t_user.find({$or:[{name:{$regex:’^.小.$’}},{id:1}]})
投影查询
db.t_user.find({},{_id:false,id:true,sex:true})
分页
db.t_user.find({}).skip(1).limit(3)
排序
db.t_user.find({}).skip(1).limit(3).sort({id:-1}).pretty();
查询salary最小
db.t_user.find({}).skip(0).limit(1).sort({salary:1}).pretty();
查询总记录数
db.t_user.find({}).count() //返回查询到的文档数目
db.t_user.find({}).size() //返回游标的大小
5、索引:
获取所有索引:
db.t_user.getIndexes();
创建索引:
db.t_user.ensureIndex({name:1},{name:’name_index’})
删除索引:
db.t_user.dropIndex(“name_index”)
复合索引:
db.t_user.ensureIndex({name:1,age:1},{name:’name_age_index’})
唯一索引:
db.t_user.ensureIndex({name:1},{name:”name_index”,unique:true});
稀疏索引:
db.t_user.ensureIndex({name:1},{name:”name_index”,unique:true,sparse:true});
SpringData操作MongoDB(Spring-4.2.8版本)
spring.xml配置文件
<mongo:mongo id="mongo" host="192.168.11.128" 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>
<mongo:db-factory id="dbFactory" dbname="love" mongo-ref="mongo"/>
<!-- 配置momngoTemplate -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg index="0" ref="dbFactory"/>
</bean>
代码
测试类
public class TestMongoDB {
private Mongo mongo;
private MongoTemplate mongoTemplate;
private DB db;
private DBCollection collection;
@Before
public void before(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
mongo = (Mongo) ac.getBean("mongo");
mongoTemplate = (MongoTemplate) ac.getBean("mongoTemplate");
}
@Test
public void save(){
Hero hero=new Hero("张局座",42,new Date());
mongoTemplate.save(hero);
}
@Test
public void find(){
Query query=new Query();
Criteria criteria=new Criteria();
query.addCriteria(criteria);
List<Hero> find = mongoTemplate.find(query, Hero.class);
for(Hero hero:find){
System.out.println(hero);
}
}
@Test
public void findCriteria(){
Query query=new Query();
Criteria criteria=new Criteria("name");
criteria.is("spiderMan");
criteria.and("age").equals("22");
query.addCriteria(criteria);
List<Hero> find = mongoTemplate.find(query, Hero.class);
System.out.println(find);
}
@Test
public void findById(){
Hero findById = mongoTemplate.findById("5860bff364282b8143a92386", Hero.class);
System.out.println(findById);
}
@Test
public void count(){
Query query=new Query();
long count = mongoTemplate.count(query, Hero.class);
System.out.println(count);
}
@Test
public void update(){
Query query=new Query();
Criteria criteria=new Criteria("name");
criteria.is("张局座");
query.addCriteria(criteria);
Update update=new Update();
update.set("age", 41);
WriteResult updateFirst = mongoTemplate.updateFirst(query, update, Hero.class);
System.out.println(updateFirst);
}
@Test
public void delete(){
Query query=new Query();
Criteria criteria=new Criteria("name").is("superMan");
query.addCriteria(criteria);
WriteResult remove = mongoTemplate.remove(query, Hero.class);
System.out.println(remove);
}
@Test
public void queryAll(){
Query query=new Query();
query.skip(0);
query.limit(5);
Sort sort=new Sort(Direction.ASC,"age");
query.with(sort);
List<Hero> find = mongoTemplate.find(query, Hero.class);
for(Hero hero:find){
System.out.println(hero);
}
}
}
实体类
public class Hero implements Serializable{
@Id
private String id;
@Field
@Indexed(direction=IndexDirection.ASCENDING,name="name_index",unique=true,sparse=true)
private String name;
@Indexed(direction=IndexDirection.ASCENDING,name="age_index",unique=true,sparse=true)
private Integer age;
private Date bir;
public Hero(String name, Integer age, Date bir) {
super();
this.name = name;
this.age = age;
this.bir = bir;
}
public Hero() {
super();
// TODO Auto-generated constructor stub
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBir() {
return bir;
}
public void setBir(Date bir) {
this.bir = bir;
}
@Override
public String toString() {
return "Hero [id=" + id + ", name=" + name + ", age=" + age + ", bir="
+ bir + "]";
}
}
辅线
主从架构(old):
优点:数据冗余备份
缺点:机器的故障转移一般需要人工干预;存储 遵循 木桶原理
应用:读写分离
副本集(升级版主从):
优点:数据冗余备份,故障转移
缺点:存储 遵循 木桶原理
分片(起源 RDBMS 分库分表):
优点: 提升系统的并发能力,提升系统存储能力
缺点: 增加了系统故障率,一旦有一台宕机整个集群处于宕机状态.
副本集+分片: 解决存储/并发 故障率降低了
启动主机:
[root@zpark ~]# ./mongodb/bin/mongod –port 27017 –dbpath /db/master/ –journal –master
启动从机
[root@zpark ~]# ./mongodb/bin/mongod –port 27018 –dbpath /db/slave/ –journal –slave –source 192.168.12.129:27017
查看当前是否是主机:
rs.isMaster();
如果查看从机器:
rs.slaveOK();
副本集搭建
启动三台副本集合
[root@zpark ~]# ./mongodb/bin/mongod –port 27017 –dbpath ~/db/rep1/ –journal –replSet zpark
[root@zpark ~]# ./mongodb/bin/mongod –port 27018 –dbpath ~/db/rep2/ –journal –replSet zpark
[root@zpark ~]# ./mongodb/bin/mongod –port 27019 –dbpath ~/db/rep3/ –journal –replSet zpark
use admin
var config = {
_id:"zpark",
members:[
{_id:0,host:"192.168.12.129:27019"},
{_id:1,host:"192.168.12.129:27018"},
{_id:2,host:"192.168.12.129:27017"}
]
}
rs.initiate(config) | rs.isMaster();
rs.status();//查看集群状态
副本集运维(只能在主机上运维集群):
①添加一台机器到集群
[root@zpark ~]# ./bin/mongod –port 27020 –dbpath ~/db/rep4/ –journal –replSet zpark
rs.add(‘192.168.12.129:27020’)/rs.add({_id:3,host:”192.168.12.129:27020”})
②删除一个节点
rs.remove(‘192.168.12.129:27020’)
节点类型介绍
主节点 /从节点/仲裁节点/secondary Only节点/隐藏节点/延迟节点/non-voting节点
1、仲裁节点:
只参与 选举/投票 不参与存储 一般用于凑数
2、secondary Only节点:
永远只当从节点 永远都不可以成为主
var conf=rs.conf();
conf[].priority=0
rs.reconf(conf);
3、隐藏节点:
var conf=rs.conf();
conf[].priority=0
conf[].hidden=true
rs.reconf(conf);
4、延迟节点:
var conf=rs.conf();
conf[].priority=0
conf[].hidden=true
conf[].slaveDelay=3600
rs.reconf(conf);
5、non-voting节点
var conf=rs.conf();
conf[].votes=0
rs.reconf(conf);
注意事项:一般要求3台机器作为一个副本集合 MongoDB的副本级别最大上限是17个,其中最对7台具备投票权
分片搭建:
1.启动两个shard (启动两个副本集)
[root@zpark ~]# ./bin/mongod –port 27017 –dbpath ~/db/shard1/ –journal –shardsvr
[root@zpark ~]# ./bin/mongod –port 27018 –dbpath ~/db/shard2/ –journal –shardsvr
2.启动confserver(启动三台)
[root@zpark ~]# ./bin/mongod –port 27019 –dbpath ~/db/conf/ –journal –configsvr
3.启动路由服务
[root@zpark ~]# ./bin/mongos –port 27020 –configdb 192.168.12.129:27019,[….]
4.连接路由服务器写入集群配置
[root@zpark ~]# ./bin/mongo –port 27020
5、启动
use admin
sh.addShard("192.168.12.129:27017") //sh.addShard("副本集id/server:port,...")
sh.addShard("192.168.12.129:27018")
db.runCommand({addshard : "192.168.12.129:27018", "name" : "shard00000" })
sh.enableSharding('baizhi');//开启对baizhi库的分片
sh.shardCollection("baizhi.t_user",{_id:1}); // range based shard
sh.shardCollection('baizhi.t_email',{_id:'hashed'});//hash bashed shard
6、插入测试数据
use baizhi
for(var i=0; i<10000; i++){
db.t_user.insert({name:"user"+i, age:i, email:"zpark@163.com" })
}
db.printShardingStatus();
db.t_user.stats();
7、shard管理:
①添加shard
[root@zpark ~]# ./bin/mongod –port 27021 –dbpath ~/db/shard3/ –journal –shardsvr
②删除节点
use admin
db.runCommand({removeShard : “shard0001”});