Container引发的一场变革

Yii 1.x、thinkPHP、CodeIgniter在PHP 5.3之前,MVC的实现算是比较的足规中矩,大体解决办法是从REQUEST_URI中提取uri,根据uri规则分解出contraller、action、params或者还有app(Yaf)。逻辑...
继续阅读 »
Yii 1.x、thinkPHP、CodeIgniter在PHP 5.3之前,MVC的实现算是比较的足规中矩,大体解决办法是从REQUEST_URI中提取uri,根据uri规则分解出contraller、action、params或者还有app(Yaf)。逻辑也比较清晰,用notepad++就可以了解MVC的结构和主体思想。
 
现在的MVC框架随着PHP版本的升级,支持的特性越来越多,尤其匿名函数这概念的引入,使得服务容器Container在众多一流MVC新版本中极为受宠。laravel的Illuminate/Container使得laravel 5可以让开发者非常灵活组合地使用composer组件。其他如Symfony 2的Component/DependencyInjection/ContainerBuilder和Yii 2的di/Container各家都做了自己的实现。
 
服务容器也叫IoC 容器,或者另外一些说法叫控制反转、依赖注入。暂时叫依赖注入,这名字更贴切的表达服务容器的使命:为解决依赖而生。
 
先来简释Yii2的Container,事实上Yii2的容器实现非常复杂。以Controller::behaviors()这方法说起,先看下:
public function behaviors() {
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'actions' => ['logout', 'index'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
这就得一路追起来
    []yii\web\Application[/][]yii\base\Application::run()[/][]yii\base\Component::trigger()[/][]yii\base\Component::ensureBehaviors()[/][]yii\base\Component::attachBehaviorInternal()(到现在终于才看到controller::behavior()的影子)[/][]yii\BaseYii::createObject()(终于是服务容器登场了)[/][]yii\di\Container::get()[/]

再细看Container::get($class, $params = , $config = )如何实现服务容器的。三个参数里config其实对于BaseYii::createObject()是暂时没用的,先关注前面两个参数。
# 1、对于单例(对象)来说,无须检查依赖和参数传递
if (isset($this->_singletons[$class])) {
return $this->_singletons[$class];

# 2、好吧,首次创建这个对象
} elseif (!isset($this->_definitions[$class])) {
return $this->build($class, $params, $config);
}
Container::build()这个对象得需要知道这个对象的依赖关系:Container::getDependencies($class)
$dependencies = ;
# 先建立对象反射
$reflection = new ReflectionClass($class);

# 获取这个对象的初始化__construct(Foo $foo, $level = 0)依赖条件
$constructor = $reflection->getConstructor();
if ($constructor !== null) {
foreach ($constructor->getParameters() as $param) {
# 有默认值的好说,如level = 0
if ($param->isDefaultValueAvailable()) {
$dependencies = $param->getDefaultValue();

# 否则,我们得知道这个依赖的类是什么,如:类Far,并且创建这个对象Instance::of('Foo')
} else {
$c = $param->getClass();
$dependencies = Instance::of($c === null ? null : $c->getName());
}
}
}

# 记录$_reflections、$_dependencies并返回
$this->_reflections[$class] = $reflection;
$this->_dependencies[$class] = $dependencies;
此时已经得到一个AccessControl的反射类和相关依赖,好吧,回头一看Controller::behaviors()应该可以由服务容器提供一个AccessControl了吧。细心的同学在上面获取依赖类的过程,有一个细节:创建类Far是用了Instance::of('Far'),只是一个$id = 'Far'的Instance。并不是真正的Far类,而且能想到这个Far实例会不会也像AccessControl一样也有依赖呢?啊,这样下去还有完没完了!
 
好吧,那所有的都走一次Container::get($class, $params),满足了吧。所以也就有了Container::build($class, $params)方法里先解决一层AccessControl依赖,接着再来一次解决依赖Container::resolveDependencies()
list ($reflection, $dependencies) = $this->getDependencies($class);

...

$dependencies = $this->resolveDependencies($dependencies, $reflection);
具体看Container::resolveDependencies()的实现
/**
* Resolves dependencies by replacing them with the actual object instances.
* 以最终实例化的对象来填充类的依赖
* @param array $dependencies the dependencies
* @param ReflectionClass $reflection the class reflection associated with the dependencies
* @return array the resolved dependencies
* @throws InvalidConfigException if a dependency cannot be resolved or if a dependency cannot be fulfilled.
*/
protected function resolveDependencies($dependencies, $reflection = null) {
foreach ($dependencies as $index => $dependency) {
if ($dependency instanceof Instance) {
if ($dependency->id !== null) {
# 取回$id = 'Far'值,重新Container::get('Far')得到真正的实例,新的一轮Container::get()又开始了,直到所有依赖的依赖的依赖...都被解决
$dependencies[$index] = $this->get($dependency->id);
} elseif ($reflection !== null) {
$name = $reflection->getConstructor()->getParameters()[$index]->getName();
$class = $reflection->getName();
throw new InvalidConfigException("Missing required parameter \"$name\" when instantiating \"$class\".");
}
}
}
return $dependencies;
}
Container::build($class, $params)已经被打断两次了,好不容易把依赖都解决完了,终于可以创建最开始的实例AccessControl了。
# 打断:解决依赖
list ($reflection, $dependencies) = $this->getDependencies($class);

...

# 打断:解决依赖的依赖...
$dependencies = $this->resolveDependencies($dependencies, $reflection);

# 利用反射类实例对象,顺手把$config数据元素赋到对象的属性
if (!empty($config) && !empty($dependencies) && is_a($class, 'yii\base\Object', true)) {
// set $config as the last parameter (existing one will be overwritten)
$dependencies[count($dependencies) - 1] = $config;
return $reflection->newInstanceArgs($dependencies);
} else {
$object = $reflection->newInstanceArgs($dependencies);
foreach ($config as $name => $value) {
$object->$name = $value;
}
return $object;
}
纵观上面服务容器可以支持实例singleton、类名string,但还不能支持闭包clourse,那Yii 2怎么好意思呢?刚才追到了Container::build($class, $params, $config),现在稍微回溯一级到Container::get($class, $params, $config)

在我们看代码之前,试想下,如果自己要实现一个服务容器,分别支持这三种类型该如何设计?实例不须做工作,先记录保存;字符串类名需要特别细心,通过上述层层依赖的反射最终可以解决;剩下的闭包可以通过call_user_func处理匿名函数就可以得到最终的实例。现在验证下Yii 2是不是也这样的策略。

在我们马上要彻底分析Container::get之前,还有一些工作需要我们理清楚的。get相当于依赖解析和实例化对象,而之前还有一个工作就是注入。到现在我们也还没有对注入进行分析,而在PHP中设计一个服务容器支持上面提到的三种类型,注入是重要的入口,只有注入优雅了,依赖解析才会优雅。

Yii 2的注入是在Container::set中实现,Container::set($class, $params)都支持哪些类注册方式?以达到我们可以随意的Container::get呢?我简单分类说明,代码可以忽略,以下注释就是对Container::set中唯一一个方法normalizeDefinition($class, $definition)对定义进行规范化处理的实例版本。
#A:初级版本的注册,直接一个命名空间的类名,毫无挑战性,甚至都没有注册的必要
$container->set('yii\db\Connection');

// register an interface
// When a class depends on the interface, the corresponding class
// will be instantiated as the dependent object
#B:对于用接口作为类型约束,那实例化时可不能对接口进行实例化,需要根据实际的继承类来实例化。
# 如:__construct(yii\mail\MailInterface $mailer),而最终实例化的是yii\swiftmailer\Mailer
$container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');

// register an alias name. You can use $container->get('db')
// to create an instance of Connection
#C:如果你觉得yii\db\Connection这货名字太长,可以别名为db,这样在model层就可以随意的$container->get('db')
$container->set('db', 'yii\db\Connection');

// register a class with configuration. The configuration
// will be applied when the class is instantiated by get()
#D:如果对于A版本,没法满足你了,需要在注入时就初始化该的一些属性,使用$params数组即可
$container->set('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);

// register an alias name with class configuration
// In this case, a "class" element is required to specify the class
#E:如果你想要C+D这种结合体,当然也可以,请在$params的key为class标明你原始类名
$container->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);

// register a PHP callable
// The callable will be executed when $container->get('db') is called
#F:总会有一些任性的同学,我想要自定义类,那总得支持吧,请使用闭包函数吧
# 虽然它不会像js那些做到真正的回调,但变量的作用域的思想是一致的
$container->set('db', function ($container, $params, $config) {
return new \yii\db\Connection($config);
});
既然注入是这么简单的规则,学习成本小,接下来的最后依赖解析Container::get($class, $params, $config)的完整代码。
/**
* Returns an instance of the requested class.
* 所谓好的IoC就是能static::get('啥都有')都能return正确的对象
*/
public function get($class, $params = , $config = ) {
# 1、对于单例(对象)来说,无须检查依赖和参数传递
if (isset($this->_singletons[$class])) {
return $this->_singletons[$class];

# 2、好吧,首次创建这个对象
} elseif (!isset($this->_definitions[$class])) {
return $this->build($class, $params, $config);
}

# 3、为什么已定义的对象不直接给返回?
# 此定义非已经创建过对象这种定义,而是Container::set($class, $definition, $params)注册了一个$class而已,跟laravel的bind相像。
$definition = $this->_definitions[$class];

# 4、$definition为闭包函数:
if (is_callable($definition, true)) {
$params = $this->resolveDependencies($this->mergeParams($class, $params));
$object = call_user_func($definition, $this, $params, $config);

# 5、$definition为数组:
} elseif (is_array($definition)) {
# 数组中必须要给出一个key为class的类名
$concrete = $definition['class'];
unset($definition['class']);

$config = array_merge($definition, $config);
$params = $this->mergeParams($class, $params);

# 对于没有别名的,可以直接创建该对象
if ($concrete === $class) {
$object = $this->build($class, $params, $config);

# 别名为什么要递归?而不是$this->build(concrete, $params, $config)
#
} else {
$object = $this->get($concrete, $params, $config);
}

# 6、$definition为对象:
} elseif (is_object($definition)) {
return $this->_singletons[$class] = $definition;
} else {
throw new InvalidConfigException("Unexpected object definition type: " . gettype($definition));
}

# 更新单例记录的对象,取最后更新值。假设Foo::__construct($level = 0) {}
# 当同一进程中有$this->_singletons['Foo'] = new Foo(1);
# 现在Container::get('Foo')
# 此时$this->_singletons[$class] = new Foo(0);
if (array_key_exists($class, $this->_singletons)) {
// singleton
$this->_singletons[$class] = $object;
}

return $object;
}


原文作者:花满树
分享原文链接:http://blog.huamanshu.com/?date=2015-06-26


收起阅读 »

hbase两点错误总结

一、hbase的HRegionServer节点启动失败 2015-10-23 17:24:33,147 WARN [regionserver60020] zookeeper.RecoverableZooKeeper: Node /hbase/rs/Sla...
继续阅读 »


一、hbase的HRegionServer节点启动失败


2015-10-23 17:24:33,147 WARN  [regionserver60020] zookeeper.RecoverableZooKeeper: Node /hbase/rs/SlaveServer,60020,1413095376898 already deleted, retry=false
2015-10-23 17:24:33,147 WARN [regionserver60020] regionserver.HRegionServer: Failed deleting my ephemeral node
org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /hbase/rs/SlaveServer,60020,1413095376898
at org.apache.zookeeper.KeeperException.create(KeeperException.java:111)
at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
at org.apache.zookeeper.ZooKeeper.delete(ZooKeeper.java:873)
at org.apache.hadoop.hbase.zookeeper.RecoverableZooKeeper.delete(RecoverableZooKeeper.java:156)
at org.apache.hadoop.hbase.zookeeper.ZKUtil.deleteNode(ZKUtil.java:1273)
at org.apache.hadoop.hbase.zookeeper.ZKUtil.deleteNode(ZKUtil.java:1262)
at org.apache.hadoop.hbase.regionserver.HRegionServer.deleteMyEphemeralNode(HRegionServer.java:1298)
at org.apache.hadoop.hbase.regionserver.HRegionServer.run(HRegionServer.java:1012)
at java.lang.Thread.run(Thread.java:662)
2015-10-23 17:24:33,158 INFO [regionserver60020] zookeeper.ZooKeeper: Session: 0x249020a2cfd0014 closed
2015-10-23 17:24:33,158 INFO [regionserver60020-EventThread] zookeeper.ClientCnxn: EventThread shut down
2015-10-23 17:24:33,158 INFO [regionserver60020] regionserver.HRegionServer: stopping server null; zookeeper connection closed.
2015-10-23 17:24:33,158 INFO [regionserver60020] regionserver.HRegionServer: regionserver60020 exiting
2015-10-23 17:24:33,158 ERROR [main] regionserver.HRegionServerCommandLine: Region server exiting
java.lang.RuntimeException: HRegionServer Aborted
at org.apache.hadoop.hbase.regionserver.HRegionServerCommandLine.start(HRegionServerCommandLine.java:66)
at org.apache.hadoop.hbase.regionserver.HRegionServerCommandLine.run(HRegionServerCommandLine.java:85)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
at org.apache.hadoop.hbase.util.ServerCommandLine.doMain(ServerCommandLine.java:126)
at org.apache.hadoop.hbase.regionserver.HRegionServer.main(HRegionServer.java:2422)
2015-10-23 17:24:33,160 INFO [Thread-9] regionserver.ShutdownHook: Shutdown hook starting; hbase.shutdown.hook=true; fsShutdownHook=org.apache.hadoop.fs.FileSystem$Cache$ClientFinalizer@8d5aad
2015-10-23 17:24:33,160 INFO [Thread-9] regionserver.ShutdownHook: Starting fs shutdown hook thread.
2015-10-23 17:24:33,160 INFO [Thread-9] regionserver.ShutdownHook: Shutdown hook finished.
一般这种情况,是因为集群中节点时间相差太多,时间没有同步导致的,解决方案:
# yum -y install ntpdate  && chkconfig ntpdate off
# crontab -e #add sync time cron scripts
[i]/2 [/i] [i] [/i] * ntpdate asia.pool.ntp.org
如果遇到是其他原因的同学,下面回答分享一下!


二、主机名配置问题


failed on connection exception: java.net.ConnectException: Connection refused; For more details see:  http://wiki.apache.org/hadoop/ConnectionRefused
根据查看提示链接http://wiki.apache.org/hadoop/ConnectionRefused排查错误,将/etc/hosts中的127.0.0.1 hbase1删除(从节点对应也删除)后程序运行正常。接着尝试运行HBase,没有出现问题!创建表也正常了!
一开始知道得删除hosts文件中127.0.1.1,但是没想到127.0.0.1 主机名也得删除。
 
还有一种情况也会导致集群启动问题,那就是主机名不规范,作为hadoop集群中的主机名,是不支持_和-的,比如hbase_host1这是不支持的! 收起阅读 »

kvm错误整理

Kvm
一、启动虚拟机​Connection reset by peer # virsh start vmhost1 error: Failed to start domain vmhost1 error: Unable to read from monitor:...
继续阅读 »


一、启动虚拟机​Connection reset by peer


# virsh start vmhost1
error: Failed to start domain vmhost1
error: Unable to read from monitor: Connection reset by peer
在虚拟机运行过程中关闭宿主服务器就有可能导致这种情况出现,由于宿主服务器中的kvm虚拟机控制器与安装在kvm中的虚拟机会话被异常重置,所以我们可以如下解决:
# virsh managedsave-remove vmhost1
# virsh start vmhost1
如果启动查看/var/log/libvirt/qemu/vmhost1.log下log还报如下错误:
Cannot set up guest memory 'pc.ram': Cannot allocate memory
这个问题可能是分配给vmhost1分配的内存过大(甚至超过的物理主机的内存大小),或者可能是宿主机没有足够的内存分配给此虚拟机,导致无法启动!


二、重Define虚拟机时无/usr/bin/kvm


error: Failed to define domain from hostname.xml
error: Cannot find QEMU binary /usr/bin/kvm: No such file or directory
解决方法:
# ln -s /usr/libexec/qemu-kvm /usr/bin/kvm


三、error: internal error process exited while connecting to monitor


# virsh start vmhost1  
error: Failed to start domain vmhost1
error: internal error process exited while connecting to monitor: kvm: -drive file=/dev/sp1368155439693/v1368544020461,if=none,id=drive-virtio-disk0,format=qcow2: could not open disk image /dev/sp1368155439693/v1368544020461: Invalid argument
分析:镜像格式错误,用qemu-img info 检查镜像和xml配置文件中指定的type是否一致!


四、Unable to load library 'virt': libvirt.so


Unable to load library 'virt': libvirt.so: cannot open shared object file: No such file or directory

Linux下解决:
ln -s /usr/lib/libvirt.so.0 /usr/lib/libvirt.so

windows下解决:
将libvirt-0.dll改名为virt.dll


五、error: Refusing to undefine while domain managed save image exists


# virsh undefine vmhost1
error: Refusing to undefine while domain managed save image exists
http://www.redhat.com/archives/libvir-list/2011-July/msg01219.html
解决方法:virsh undefine $domain  --managed-save


六、启动libvirtd进程出错


# /usr/local/sbin/libvirtd -d -l --config /usr/local/etc/libvirt/libvirtd.conf (编译安装的启动方式)
error:/usr/local/sbin/libvirtd: initialization failed
try to install libpcap-devel RPM and rebuild libvirt http://comments.gmane.org/gmane.comp.emulators.libvirt/58218

apt-get install libpcap-dev
上面的方法好像都没有效果,但是尝试了http://wiki.libvirt.org/page/The_daemon_cannot_be_started说的,把配置文件里的
listen_tls = 0注释取消(更奇怪的问题,在我的客户端链接不对)


七、启动虚拟机报错


# virsh start vmhost1
error: Failed to start domain vmhost1
error: internal error process exited while connecting to monitor: Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
No accelerator found!
上面的提示信息就是因为QEMU在初始化阶段因为无法找到kvm内核模块。
# modprobe kvm   #载入指定的模块
重启电脑,进入bios界面,设置advance选项里面的virtualization标签为Enabled
通过命令 lsmod | grep kvm    #显示已载入的模块


八、虚拟机迁移


# virsh migrate --live 1 qemu+tcp://192.168.0.121 --p2p --tunnelled --unsafe 
error: operation failed: Failed to connect to remote libvirt URI qemu+tcp://192.168.0.121(在URI后面加上/system,‘system’相当于root用户的访问权限)

#virsh migrate --live 2 qemu+tcp://192.168.0.121/system --p2p --tunnelled
error: Unsafe migration: Migration may lead to data corruption if disks use cache != none(加上--unsafe参数)

#virsh migrate --live 2 qemu+tcp://192.168.0.121/system --p2p --tunnelled --unsafe
error: Timed out during operation: cannot acquire state change lock (启动虚拟机有时也会遇此错误),需要重启libvirtd进程


九、virsh


error: Failed to connect socket to '/var/run/libvirt/libvirt-sock': Connection refused(libvirtd 进程没有启动,libvirtd是一个监听客户端请求的进程)

# virsh -c qemu:///system list
error: Failed to connect socket to '/var/run/libvirt/libvirt-sock': Permission denied
error: failed to connect to the hypervisor
(当前用户没有权限,修改/etc/libvirt/libvirtd.conf,unix_sock_rw_perms = 0777,使所有用户都有权限读写)
收起阅读 »

zookeepr运维经验分享

ZooKeeper 是分布式环境下非常重要的一个中间件,可以完成动态配置推送、分布式 Leader 选举、分布式锁等功能。在运维 ZooKeeper 服务的以来,积累如下经验: 集群数量 3台起,如果是虚拟机,必须分散在不同的宿主机上,以实现容灾的目的。如果...
继续阅读 »
ZooKeeper 是分布式环境下非常重要的一个中间件,可以完成动态配置推送、分布式 Leader 选举、分布式锁等功能。在运维 ZooKeeper 服务的以来,积累如下经验:


  1. 集群数量


3台起,如果是虚拟机,必须分散在不同的宿主机上,以实现容灾的目的。如果长远来看(如2-3年)需求会持续增长,可以直接部署5台。ZooKeeper集群扩容是比较麻烦的事情,因此宁可前期稍微浪费一点。


  1. 客户端配置域名而不是 IP


如果有一天你的 ZooKeeper 集群需要做机房迁移,或者其中几个节点机器挂了,需要更换。让你的用户更新 ZooKeeper 服务器配置不是件轻松的事情,因此一开始就配置好域名,到时候更新 DNS 即可。


  1. 开启 autopurge.snapRetainCount


ZooKeeper 默认不会自动清理 tx log,所以总会有一天你会收到磁盘报警(如果你有磁盘监控的话)。开启自动清理机制后,就不用担心了,我的配置如下:
autopurge.snapRetainCount=500
autopurge.purgeInterval=24


  1. 扩容


如果你可以接受停止服务半个小时,那基本随意玩了,但在比较严肃的环境下,还是不能停服务的。我的做法是这样的:
0. 有节点 A, B, C 处于服务状态
server.3=192.168.12.1:2888:3888
server.4=192.168.12.2:2888:3888
server.5=192.168.12.3:2888:3888
1. 加入节点 D,配置如下:
server.3=192.168.12.1:2888:3888
server.4=192.168.12.2:2888:3888
server.5=192.168.12.3:2888:3888
server.6=192.168.12.4:2888:3888
server.7=192.168.12.5:2888:3888
用 4 字命令检查,保证该节点同步完毕集群数据,处于 Follower 状态:
# echo srvr | nc 192.168.12.4 2181
Zookeeper version: 3.4.5-1392090, built on 09/30/2012 17:52 GMT
Latency min/avg/max: 0/0/13432
Received: ***
Sent: ***
Connections: ***
Outstanding: 0
Zxid: 0x***
Mode: follower
Node count: ***
需要注意的是,这一步加入的节点的 id,必须大于集群中原有的节点的 id,例如 6 > 3,4,5,我也不知道为什么需要这样。
  1. 同上一步一样,加入节点 E
  2. 更新 A B C 的配置如 D 和 E,并依此重启


  1. 机房迁移


例如要把服务从 X 机房的 A B C 迁移到 Y 机房的 A’ B’ C’。
做法是首先把集群扩容成包含6个节点的集群;然后修改域名指向让用户的连接都转到 A’ B’ C’;最后更新集群配置,把 A B C 从集群摘除。


  1. 跨机房容灾


由于 ZooKeeper 天生不喜欢偶数(怕脑裂),因此有条件的就三机房部署,但机房之间的网络条件得是类似局域网的条件,否则性能就堪忧了。

双机房做自动容灾基本不可能,加入手动步骤是可以的,和 DB 一样,短时间不可用,立刻启用另外一个机房,平时保证数据同步。

三机房部署,如果一个机房离的比较远,网络延迟较高怎么办?可以 3 + 3 + 1 部署,1 就放在那个网络延迟较高的地方,确保 leader 在 3 + 3 这两个机房中间,那么平时的性能就能保证了。怎么保证 leader 不到 1 呢?目前能想到的办法就是如果发现就重启它
收起阅读 »

kvm虚拟机克隆过程详解

Kvm
在使用ucloud云主机的时候,发现他们制作镜像只能克隆系统盘数据制作,这是为什么,为什么不能连数据盘一起克隆呢,然后就问了一下他们的技术人员,他们底层用的是kvm技术,因为kvm镜像制作会按照你主机空间大小块来克隆,意思就是说,比如我/ 分区大小为20G,数...
继续阅读 »
在使用ucloud云主机的时候,发现他们制作镜像只能克隆系统盘数据制作,这是为什么,为什么不能连数据盘一起克隆呢,然后就问了一下他们的技术人员,他们底层用的是kvm技术,因为kvm镜像制作会按照你主机空间大小块来克隆,意思就是说,比如我/ 分区大小为20G,数据盘/data分区大小为200G,然后你连着数据盘一起制作镜像的话,存在两个问题:
    []克隆镜像使用时间较长[/][]克隆出来的镜像大小较大,如上面所说的主机,那克隆出来的镜像大小为220G[/]

所以基于这种情况,ucloud的上面的云主机默认创建的主机系统磁盘大小为20G,创建镜像的时候只会克隆系统盘!所以你要做基准镜像,就需要先创建一个基准系统,安装好服务,然后做镜像,最后挂载数据盘!
 
同样我们公司内网也使用了一些kvm虚拟机作为内网的测试环境和一些服务。下面简单的记录自己的笔记,总结还是看自己的笔记比较有思路,回头看思路比较清晰!
 
查阅资料和书籍,kvm虚拟机克隆有如下两种方式:
    []KVM本机虚拟机直接克隆[/][]通过复制xml文件与磁盘文件复制克隆 (适用于异机的静态迁移和状态保存便于以后使用)。[/]
下面逐一介绍:

一、本机直接克隆

1、查看虚拟机配置文件获取磁盘文件路径
[root@kvmsuzhu2 ~]# cat /etc/libvirt/qemu/hysen_6101_101.xml |grep 'source file'|grep img      [root@kvmsuzhu2 ~]# cat /etc/libvirt/qemu/hysen_6101_101.xml |grep '^.*/name>$'  hysen_6101_101[root@kvmsuzhu2 ~]# 
克隆前确认主机已经关闭:
[root@kvmsuzhu ~]# virsh list --all Id    名称                         状态---------------------------------------------------- 3     dev_5974_74                    running 14    dev_5954_54                    running -     hysen_6101_101                 关闭 -     openstack_5978_78              关闭
不关闭则克隆会报ERROR    Domain with devices to clone must be paused or shutoff.
2、开始克隆
[root@kvmsuzhu2 ~]# virt-clone -o hysen_6101_101 -n hysen_6103_103 -f /data1/vmdisk/hysen_6103_103.img 正在克隆 hysen_6101_101.img                                                                        |  30 GB     13:55     Clone 'hysen_6103_103' created successfully.克隆已经完成30G的大小!
3、修改vnc端口号,启动主机
[root@kvmsuzhu2 ~]# cat /etc/libvirt/qemu/hysen_6103_103.xml |grep 'vnc'    [root@kvmsuzhu2 ~]# virsh edit hysen_6103_103    //这里你必须用virsh edit命令编辑配置文件,用vim编辑是不会生效的!编辑了域 hysen_6103_103 XML 配置。[root@kvmsuzhu2 ~]# cat /etc/libvirt/qemu/hysen_6103_103.xml |grep 'vnc'    [root@kvmsuzhu2 ~]# virsh start hysen_6103_103.xml域 hysen_6103_103 已开始[root@kvmsuzhu2 ~]# netstat -anltp |grep 6103tcp        0      0 0.0.0.0:6103                0.0.0.0:*                   LISTEN      13740/qemu-kvm [root@kvmsuzhu2 ~]#  
4、修改主机名、ip地址
修改主机名[root@hysen_6101_101 ~]# vi /etc/sysconfig/networkNETWORKING=yes    NETWORKING_IPV6=no     HOSTNAME=hysen_6103_103 GATEWAY=10.0.1.1[root@hysen_6101_101 ~]# hostname hysen_6103_103修改IP地址[root@hysen_6103_103 ~]# vi /etc/sysconfig/network-script/ifcfg-eth0# Virtio Network Device    DEVICE=eth0     BOOTPROTO=static     ONBOOT=yes     HWADDR=52:54:00:ae:1d:7b     IPADDR=10.0.1.117     NETMASK=255.255.255.0注意修改mac地址,有uuid的配置修改uuid配置[root@hysen_6103_103 ~]# service network start重启报错:device eth0 does not seem to be present, delaying initialization如下操作解决:[root@hysen_6103_103 ~]# rm -rf /etc/udev/rules.d/70-persistent-net.rules 有说修改文件把eth0和eth1互换的也可以![root@hysen_6103_103 ~]# reboot重启网卡服务[root@hysen_6103_103 ~]# service network start    Bringing up loopback interface:  [  OK  ]     Bringing up interface eth0:  [  OK  ]     [root@hysen_6103_103 ~]# 

二、通过复制xml文件与磁盘文件复制克隆

我们这里还是拿hysen_6101_101虚拟机作为模板机器克隆。同样这种方法也需要模板机器已经关机!1、复制xml配置文件
[root@kvmsuzhu2 ~]# virsh dumpxml hysen_6101_101 > /etc/libvirt/qemu/hysen_6105_105.xml[root@kvmsuzhu2 ~]# ls -l /etc/libvirt/qemu/hysen_6105_105.xml-rw-r--r-- 1 root root 2748 10月 17 17:50 /etc/libvirt/qemu/hysen_6105_105.xml[root@kvmsuzhu2 ~]#
2、复制hysen_6101_101虚拟机磁盘文件
[root@kvmsuzhu2 ~]# cp  /data1/vmdisk/hysen_6101_101.img  /data1/vmdisk/hysen_6105_105.img[root@kvmsuzhu2 ~]# ls /data1/vmdisk/hysen_6105_105.img/data1/vmdisk/hysen_6105_105.img[root@kvmsuzhu2 ~]# 
3、修改拷贝的配置文件
    []修改虚拟机的名称:hysen_6105_105[/][]修改uuid编号:13178d42-1055-8b94-1411-3c2bdd0e6e7a<[/][]修改mac地址:[/][]修改disk位置:[/][]修改vnc端口:[/]

此时还是将该配置文件注册进来,无法通过virsh edit进行编辑。
[root@kvmsuzhu2 ~]# vim /etc/libvirt/qemu/hysen_6105_105.xml
hysen_6101_101
13178d42-1055-8b94-1411-3c2bdd0e6e7a

4、定义新虚拟机配置文件
[root@kvmsuzhu2 ~]# virsh define /etc/libvirt/qemu/hysen_6105_105.xml 
定义域 hysen_6105_105(从 /etc/libvirt/qemu/hysen_6105_105.xml)

[root@kvmsuzhu2 ~]#
5、启动虚拟机并设置开机自启
[root@kvmsuzhu2 ~]# virsh start hysen_6105_105
域 hysen_6105_105 已开始

[root@kvmsuzhu2 ~]# virsh autostart hysen_6105_105
域 hysen_6105_105标记为自动开始

[root@kvmsuzhu2 ~]# virsh list --all |grep hysen_6105_105
237 hysen_6105_105 running
[root@kvmsuzhu2 ~]#
6、vnc连接修改主机名、ip地址
4、修改主机名、ip地址
修改主机名
[root@hysen_6101_101 ~]# vi /etc/sysconfig/network
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=hysen_6105_105
GATEWAY=10.0.1.1
[root@hysen_6101_101 ~]# hostname hysen_6105_105

修改IP地址
[root@hysen_6105_105 ~]# vi /etc/sysconfig/network-script/ifcfg-eth0
# Virtio Network Device
DEVICE=eth0
BOOTPROTO=static
ONBOOT=yes
HWADDR=54:52:01:11:12:1f
IPADDR=10.0.1.118
NETMASK=255.255.255.0

重启网卡服务
[root@hysen_6105_105 ~]# service network start
重启报错:device eth0 does not seem to be present, delaying initialization

如下操作解决:
[root@hysen_6105_105 ~]# rm -rf /etc/udev/rules.d/70-persistent-net.rules 有说修改文件把eth0和eth1互换的也可以!
[root@hysen_6105_105 ~]# reboot

重启之后再次登陆重启动网卡:
[root@hysen_6105_105 ~]# service network start
Bringing up loopback interface: [ OK ]
Bringing up interface eth0: [ OK ]
两种不同的方式有各有特点,你可以针对特点选择性使用! 收起阅读 »

HBase file layout needs to be upgraded案例分析

今天在一个内网的测试环境平台,kafka的river插件状态非正常,然后同事只好重建kafka river,river的状态始终无法正常,没有办法,同事对服务还不是很熟悉,我只好帮忙看看了!   因为kafka 的river插件作为kafka消息数据的...
继续阅读 »
hbase_image.png
今天在一个内网的测试环境平台,kafka的river插件状态非正常,然后同事只好重建kafka river,river的状态始终无法正常,没有办法,同事对服务还不是很熟悉,我只好帮忙看看了!
 
因为kafka 的river插件作为kafka消息数据的consumers角色,把消费掉的数据,通过Hbase转存储到hdfs中!
如下所示是river对hbase的配置:


hbase.rootdir
hdfs://10.2.2.39:9000/hbase


hbase.cluster.distributed
true


hbase.master
10.2.2.39:60000


hbase.zookeeper.quorum
10.2.2.56,10.2.2.94,10.2.2.225

从这可以看出river插件是需要hbase的,然后我执行创建river的命令,tail观看到hbase master的hbase-root-master-hbase1.log如下:
2015-10-14 17:34:13,980 INFO  [master:hbase1:60000] util.FSUtils: Waiting for dfs to exit safe mode...
从log中可以看出hbase在等待hdfs退出安全模式,为什么要等Hdfs退出安全模式呢?那下面就具体看看Hdfs的log中有什么线索,查看Hdfs的Namenode的hadoop-root-namenode-had1.log记录如下:
2015-10-14 17:33:52,283 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:root (auth:SIMPLE) cause:org.apache.hadoop.hdfs.server.namenode.SafeModeException: Log not rolled. Name node is in safe mode.
运行如下命令等待退出安全模式
bin/hadoop dfsadmin -safemode wait
发现半分钟后没有反映,然后运行如下命令检查hdfs的健康状态
bin/hadoop fsck / 
发现有很多corrupt blocks,不过还好备份数大于1.此时,hdfs需要自动的把备份数增加到2,所以需要对数据进行写操作,必须退出安全模式,于是:
bin/hadoop  dfsadmin -safemode leave
关闭之后等待集群把数据备份好,达到2,耐心等待一段时间吧,看数据量的大小,达到2之后,运行:
bin/hadoop  fsck -move
也可以尝试:执行健康检查,删除损坏掉的block。 bin/hdfs fsck  /  -delete 注意: 这种方式会出现数据丢失,损坏的block会被删掉.

把那些破坏的块移到/lost+found这个目录下面,启动Hbase,发现Hmaster启动之后进程又消失了,查看日志:
2015-10-14 17:48:29,476 FATAL [master:hbase1:60000] master.HMaster: Unhandled exception. Starting shutdown.
org.apache.hadoop.hbase.util.FileSystemVersionException: HBase file layout needs to be upgraded. You have version null and I want version 8. Consult http://hbase.apache.org/book.html for further information about upgrading HBase. Is your hbase.rootdir valid? If so, you may need to run 'hbase hbck -fixVersionFile'.
at org.apache.hadoop.hbase.util.FSUtils.checkVersion(FSUtils.java:600)
at org.apache.hadoop.hbase.master.MasterFileSystem.checkRootDir(MasterFileSystem.java:462)
at org.apache.hadoop.hbase.master.MasterFileSystem.createInitialFileSystemLayout(MasterFileSystem.java:153)
at org.apache.hadoop.hbase.master.MasterFileSystem.(MasterFileSystem.java:129)
at org.apache.hadoop.hbase.master.HMaster.finishInitialization(HMaster.java:800)
at org.apache.hadoop.hbase.master.HMaster.run(HMaster.java:605)
at java.lang.Thread.run(Thread.java:744)
从什么log中可以发现可能是hbase.version文件消失了!我看很多网友的做法是先把/hbase清理调,然后重启就好了,但是以前的数据就丢失了,这有点不科学。于是我:
bin/hadoop fs -ls /hbase
发现/hbase/hbase.version确实已经消失了,这才恍然大悟,原来是之前的这个文件可能被损坏了,去/lost+found目录找确实能找到,但是这个文件似乎出了问题,-ls它也看不到。于是想到一个办法,我做了以下操作:
bin/hadoop fs -mv /hbase /hbase.bk
重启HBase,这时就生成了/hbase/hbase.version文件,然后:
bin/hadoop fs -cp /hbase/hbase.version /hbase.bk/

bin/hadoop fs -rmr /hbase

bin/hadoop fs -mv /hbase.bk /hbase
这样再次重启HBase,发现Hbase开始splitting hlogs,数据得以恢复。然后再重建river,状态可以正常了! 收起阅读 »

docker与虚拟机性能比较

概要 docker是近年来新兴的虚拟化工具,它可以和虚拟机一样实现资源和系统环境的隔离。本文将主要根据IBM发表的研究报告,论述docker与传统虚拟化方式的不同之处,并比较物理机、docker容器、虚拟机三者的性能差异及差异产生的原理。 docker...
继续阅读 »


概要


docker是近年来新兴的虚拟化工具,它可以和虚拟机一样实现资源和系统环境的隔离。本文将主要根据IBM发表的研究报告,论述docker与传统虚拟化方式的不同之处,并比较物理机、docker容器、虚拟机三者的性能差异及差异产生的原理。 


docker与虚拟机实现原理比较


如下图分别是虚拟机与docker的实现框架。
dvk1.png
比较两图的差异,左图虚拟机的Guest OS层和Hypervisor层在docker中被Docker Engine层所替代。虚拟机的Guest OS即为虚拟机安装的操作系统,它是一个完整操作系统内核;虚拟机的Hypervisor层可以简单理解为一个硬件虚拟化平台,它在Host OS是以内核态的驱动存在的。
 
虚拟机实现资源隔离的方法是利用独立的OS,并利用Hypervisor虚拟化CPU、内存、IO设备等实现的。例如,为了虚拟CPU,Hypervisor会为每个虚拟的CPU创建一个数据结构,模拟CPU的全部寄存器的值,在适当的时候跟踪并修改这些值。需要指出的是在大多数情况下,虚拟机软件代码是直接跑在硬件上的,而不需要Hypervisor介入。只有在一些权限高的请求下,Guest OS需要运行内核态修改CPU的寄存器数据,Hypervisor会介入,修改并维护虚拟的CPU状态。 

Hypervisor虚拟化内存的方法是创建一个shadow page table。正常的情况下,一个page table可以用来实现从虚拟内存到物理内存的翻译。在虚拟化的情况下,由于所谓的物理内存仍然是虚拟的,因此shadow page table就要做到:虚拟内存->虚拟的物理内存->真正的物理内存。

对于IO设备虚拟化,当Hypervisor接到page fault,并发现实际上虚拟的物理内存地址对应的是一个I/O设备,Hypervisor就用软件模拟这个设备的工作情况,并返回。比如当CPU想要写磁盘时,Hypervisor就把相应的数据写到一个host OS的文件上,这个文件实际上就模拟了虚拟的磁盘。
对比虚拟机实现资源和环境隔离的方案,docker就显得简练很多。docker Engine可以简单看成对Linux的NameSpace、Cgroup、镜像管理文件系统操作的封装。docker并没有和虚拟机一样利用一个完全独立的Guest OS实现环境隔离,它利用的是目前Linux内核本身支持的容器方式实现资源和环境隔离。简单的说,docker利用namespace实现系统环境的隔离;利用Cgroup实现资源限制;利用镜像实现根目录环境的隔离。
通过docker和虚拟机实现原理的比较,我们大致可以得出一些结论:
(1)docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有优势,具体的效率对比在下几个小节里给出。在IO设备虚拟化上,docker的镜像管理有多种方案,比如利用Aufs文件系统或者Device Mapper实现docker的文件管理,各种实现方案的效率略有不同。
(2)docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。我们知道,引导、加载操作系统内核是一个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个过程,因此新建一个docker容器只需要几秒钟。另外,现代操作系统是复杂的系统,在一台物理机上新增加一个操作系统的资源开销是比较大的,因此,docker对比虚拟机在资源消耗上也占有比较大的优势。事实上,在一台物理机上我们可以很容易建立成百上千的容器,而只能建立几个虚拟机。


docker与虚拟机计算效率比较


在上一节我们从原理的角度推测docker应当在CPU和内存的利用效率上比虚拟机高。在这一节我们将根据IBM发表的论文给出的数据进行分析。以下的数据均是在IBM x3650 M4服务器测得,其主要的硬件参数是: 
(1)2颗英特尔xeon E5-2655 处理器,主频2.4-3.0 GHz。每颗处理器有8个核,因此总共有16个核。
(2)256 GB RAM.
在测试中是通过运算Linpack程序来获得计算能力数据的。结果如下图所示: 
dvk2.png
图中从左往右分别是物理机、docker和虚拟机的计算能力数据。可见docker相对于物理机其计算能力几乎没有损耗,而虚拟机对比物理机则有着非常明显的损耗。虚拟机的计算能力损耗在50%左右。 
为什么会有这么大的性能损耗呢?一方面是因为虚拟机增加了一层虚拟硬件层,运行在虚拟机上的应用程序在进行数值计算时是运行在Hypervisor虚拟的CPU上的;另外一方面是由于计算程序本身的特性导致的差异。虚拟机虚拟的cpu架构不同于实际cpu架构,数值计算程序一般针对特定的cpu架构有一定的优化措施,虚拟化使这些措施作废,甚至起到反效果。
比如对于本次实验的平台,实际的CPU架构是2块物理CPU,每块CPU拥有16个核,共32个核,采用的是NUMA架构;而虚拟机则将CPU虚拟化成一块拥有32个核的CPU。这就导致了计算程序在进行计算时无法根据实际的CPU架构进行优化,大大减低了计算效率。


docker与虚拟机内存访问效率比较


内存访问效率的比较相对比较复杂一点,主要是内存访问有多种场景: 
(1)大批量的,连续地址块的内存数据读写。这种测试环境下得到的性能数据是内存带宽,性能瓶颈主要在内存芯片的性能上; 
(2)随机内存访问性能。这种测试环境下的性能数据主要与内存带宽、cache的命中率和虚拟地址与物理地址转换的效率等因素有关。
以下将主要针对这两种内存访问场景进行分析。在分析之前我们先概要说明一下docker和虚拟机的内存访问模型差异。下图是docker与虚拟机内存访问模型: 
dvk3.png
可见在应用程序内存访问上,虚拟机的应用程序要进行2次的虚拟内存到物理内存的映射,读写内存的代价比docker的应用程序高。
下图是场景(1)的测试数据,即内存带宽数据。左图是程序运行在一块CPU(即8核)上的数据,右图是程序运行在2块CPU(即16核)上的数据。单位均为GB/s。 
dvk4.png

dvk5.png
从图中数据可以看出,在内存带宽性能上docker与虚拟机的性能差异并不大。这是因为在内存带宽测试中,读写的内存地址是连续的,大批量的,内核对这种操作会进行优化(数据预存取)。因此虚拟内存到物理内存的映射次数比较少,性能瓶颈主要在物理内存的读写速度上,因此这种情况docker和虚拟机的测试性能差别不大; 
内存带宽测试中docker与虚拟机内存访问性能差异不大的原因是由于内存带宽测试中需要进行虚拟地址到物理地址的映射次数比较少。根据这个假设,我们推测,当进行随机内存访问测试时这两者的性能差距将会变大,因为随机内存访问测试中需要进行虚拟内存地址到物理内存地址的映射次数将会变多。
结果如下图所示:
dvk6.png

dvk7.png
1图是程序运行在一个CPU上的数据,右图是程序运行在2块CPU上的数据。从左图可以看出,确实如我们所预测的,在随机内存访问性能上容器与虚拟机的性能差距变得比较明显,容器的内存访问性能明显比虚拟机优秀;但出乎我们意料的是在2块CPU上运行测试程序时容器与虚拟机的随机内存访问性能的差距却又变的不明显。
针对这个现象,IBM的论文给出了一个合理解释。这是因为当有2块CPU同时对内存进行访问时,内存读写的控制将会变得比较复杂,因为两块CPU可能同时读写同一个地址的数据,需要对内存数据进行一些同步操作,从而导致内存读写性能的损耗。这种损耗即使对于物理机也是存在的,可以看出右图的内存访问性能数据是低于左图的。2块CPU对内存读写性能的损耗影响是非常大的,这个损耗占据的比例远大于虚拟机和docker由于内存访问模型的不同产生的差异,因此在右图中docker与虚拟机的随机内存访问性能上我们看不出明显差异。


docker与虚拟机启动时间及资源耗费比较


上面两个小节主要从运行在docker里的程序和运行在虚拟机里的程序进行性能比较。
事实上,docker之所以如此受到开发者关注的另外一个重要原因是启动docker的系统代价比启动一台虚拟机的代价要低得多:无论从启动时间还是从启动资源耗费角度来说。docker直接利用宿主机的系统内核,避免了虚拟机启动时所需的系统引导时间和操作系统运行的资源消耗。利用docker能在几秒钟之内启动大量的容器,这是虚拟机无法办到的。快速启动、低系统资源消耗的优点使docker在弹性云平台和自动运维系统方面有着很好的应用前景。


docker的劣势


前面的内容主要论述docker相对于虚拟机的优势,但docker也不是完美的系统。相对于虚拟机,docker还存在着以下几个缺点:
1.资源隔离方面不如虚拟机,docker是利用cgroup实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源。
2.安全性问题。docker目前并不能分辨具体执行指令的用户,只要一个用户拥有执行docker的权限,那么他就可以对docker的容器进行所有操作,不管该容器是否是由该用户创建。比如A和B都拥有执行docker的权限,由于docker的server端并不会具体判断docker cline是由哪个用户发起的,A可以删除B创建的容器,存在一定的安全风险。 
3.docker目前还在版本的快速更新中,细节功能调整比较大。一些核心模块依赖于高版本内核,存在版本兼容问题


原文作者:chenbiaolong
 
 
分享原文地址:http://blog.csdn.net/cbl709/article/details/43955687


收起阅读 »

elasticsearch中文分词插件IK使用

ES支持中文的前提是安装正确的分词组件,比如elasticsearch-analysis-ik。 版本支持如下: 安装 # git clone https://github.com/medcl/elasticsearch-analysi...
继续阅读 »
eslogo.png

ES支持中文的前提是安装正确的分词组件,比如elasticsearch-analysis-ik
版本支持如下:
ik1.png


安装


# git clone https://github.com/medcl/elasticsearch-analysis-ik.git --depth 1
# cd elasticsearch-analysis-ik/
# mvn package
# unzip ./target/releases/elasticsearch-analysis-ik-1.2.9.zip

OR
# git clone https://github.com/medcl/elasticsearch-analysis-ik
# cd elasticsearch-analysis-ik
# mvn compile
# mvn package
# plugin --install analysis-ik --url file:///#{project_path}/elasticsearch-analysis-ik/target/releases/elasticsearch-analysis-ik-1.3.0.zip
zip解压得到5个jar包:
    []- elasticsearch-analysis-ik-1.2.9.jar[/][]- httpclient-4.3.5.jar[/][]- httpcore-4.3.2.jar[/][]- commons-logging-1.1.3.jar[/][]- commons-codec-1.6.jar[/]

 
返回ES目录,新建路径./plugins/analysis-ik并把上述jar包全部移进去。
第二步,把elasticsearch-analysis-ik/config/ik文件夹(IK自带的词典)复制到ES目录的./config路径下。
第三步,在./config/elasticsearch.yml文件的最后加上:
index:
analysis:
analyzer:
ik:
alias: [news_analyzer_ik,ik_analyzer]
type: org.elasticsearch.index.analysis.IkAnalyzerProvider

index.analysis.analyzer.default.type : "ik"

OR
[b]index.analysis.analyzer.ik.type : "ik"[/b]
注意配置分词组件必须在创建索引之前,否则是无效的。


Example


1.create a index
# curl -XPUT http://localhost:9200/index
2.create a mapping
# curl -XPUT http://localhost:9200/index
create a mapping
curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'
{
"fulltext": {
"_all": {
"indexAnalyzer": "ik",
"searchAnalyzer": "ik",
"term_vector": "no",
"store": "false"
},
"properties": {
"content": {
"type": "string",
"store": "no",
"term_vector": "with_positions_offsets",
"indexAnalyzer": "ik",
"searchAnalyzer": "ik",
"include_in_all": "true",
"boost": 8
}
}
}
}'
3.index some docs
# curl -XPOST http://localhost:9200/index/fulltext/1 -d'
{"content":"美国留给伊拉克的是个烂摊子吗"}
'
# curl -XPOST http://localhost:9200/index/fulltext/2 -d'
{"content":"公安部:各地校车将享最高路权"}
'
# curl -XPOST http://localhost:9200/index/fulltext/3 -d'
{"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}
# curl -XPOST http://localhost:9200/index/fulltext/4 -d'
{"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"}
'
4.query with highlighting
# curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
{
"query" : { "term" : { "content" : "中国" }},
"highlight" : {
"pre_tags" : ["", ""],
"post_tags" : ["
", ""],
"fields" : {
"content" : {}
}
}
}
'
Result
{
"took": 14,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 2,
"hits": [
{
"_index": "index",
"_type": "fulltext",
"_id": "4",
"_score": 2,
"_source": {
"content": "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
},
"highlight": {
"content": [
"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首 "
]
}
},
{
"_index": "index",
"_type": "fulltext",
"_id": "3",
"_score": 2,
"_source": {
"content": "中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"
},
"highlight": {
"content": [
"均每天扣1艘中国渔船 "
]
}
}
]
}
}
收起阅读 »

Elasticsearch索引存储类型

文件系统存储类型     基于文件系统的存储是默认索引存储方式。有不同的实现或存储类型。最好的一个操作系统的自动选择是:mmapfs使用在Windows的64bit系统上,simplefs使用在windows的32bit系统上,除此之外默认是用(h...
继续阅读 »
eslogo.png


文件系统存储类型
    基于文件系统的存储是默认索引存储方式。有不同的实现或存储类型。最好的一个操作系统的自动选择是:mmapfs使用在Windows的64bit系统上,simplefs使用在windows的32bit系统上,除此之外默认是用(hybrid niofs 和 mmapfs)。
 
    你可以通过修改配置文件elasticsearch.yml来指定存储类型:
index.store.type: niofs
    当然你也可以在创建索引的时候指定:
curl -XPUT localhost:9200/my_index -d '{
"settings": {
"index.store.type": "niofs"
}
}';
    下面是所有支持的不同存储类型:


Simple FS(简单文件系统)


Simplefs类型是一个简单的实现随机访问文件的文件存储系统(映射到Lucene SimpleFsDirectory的)。该实现的并发性能较差(多线程是个瓶颈)。当你需要将索引持久化,最好使用niofs。


NIO FS(NIO文件系统)


niofs类型是通过NIO将分片索引文件写到文件系统上(映射到Lucene NIOFSDirectory)。它允许多线程同时读取文件。不建议在Windows系统上使用,由于SUN JAVA实现上的一个错误。


MMap FS(内存映射文件系统)


mmapfs类型存储分片索引到文件系统上(映射到Lucene MMapDirectory)通过映射文件到内存中(MMAP)。内存映射的过程中将划分出与被映射文件大小一样的虚拟内存空间。使用这个类之前,请确保您有足够的虚拟地址空间。
Linux下虚拟内存设置:
# sysctl -w vm.max_map_count=262144
永久生效:
update the vm.max_map_count setting in /etc/sysctl.conf.
# echo "vm.max_map_count=262144" >> /etc/sysctl.conf && sysctl -p


Hybrid MMap / NIO FS


默认类型存储碎片索引在文件系统中根据不同的文件类型的文件映射到内存(mmap)或使用Java NIO。目前只Lucene术语字典和doc值文件内存映射到减少对操作系统的影响。所有其他文件都使用Lucene NIOFSDirectory打开。

内存
    内存类型索引存储在主内存,使用Lucene的RamIndexStore。
    
    也有节点级别的设置来控制高速缓存(重要的,当使用直接缓冲区):
estore.png

参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-store.html#store-memory
           https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html#file-descriptors 收起阅读 »

elasticsearch特点介绍

    Elasticsearch是分布式,REST风格,搜索和分析系统。具有实时数据,实时分析,分布式,高可用性,多租户,全文搜索,面向文档,冲突管理,自由模式,rest风格API,每个操作的持久性,Apache 2的开源许可证,基于Apache ...
继续阅读 »
es1.jpeg

    Elasticsearch是分布式,REST风格,搜索和分析系统。具有实时数据,实时分析,分布式,高可用性,多租户,全文搜索,面向文档,冲突管理,自由模式,rest风格API,每个操作的持久性,Apache 2的开源许可证,基于Apache Lucene之上的特点。


实时数据


数据流进入的系统后,数据怎么能够快速的可视化。用elasticsearch,所有数据立即可用被搜索和分析。
elasticsearch1.png


实时分析


结合搜索的速度与分析的力量,改变你的关系与你的数据。交互搜索,发现和分析,以获得改善你的产品或简化您的业务。
elasticsearch2.png


分布式


Elasticsearch允许你开始小规模使用,但是随着你使用数据的增长,它可以建立在横向扩展的开箱即用。当你需要更多的容量,只需添加更多的节点,并让集群重组,只需要增加额外的硬件,让集群自动利用额外的硬件。
elasticsearch3.png


高可用


Elasticsearch集群弹性-他们将发现新的或失败的节点,重组和重新平衡数据,确保您的数据是安全的和可访问的。
elasticsearch4.png


多租户


集群可以托管多个索引,可独立或作为一个组进行查询。索引别名允许你过滤视图时添加索引,可以透明地更新您的应用程序。
elasticsearch5.png


全文搜索


Elasticsearch在后台使用Lucene来提供最强大的全文检索,提供任何开源产品的能力。搜索自带的多语言支持,强大的查询语言,地理位置支持,上下文感知的建议,自动完成和搜索片段。
elasticsearch6.png


面向文档


存储复杂的真实世界的实体在Elasticsearch结构化JSON文件。所有的字段都被默认索引,所有的索引可以使用一个单一的查询,以方便快速的返回复杂的结果。
elasticsearch7.png


模式自由


Elasticsearch允许你快速上手。简单的指定一个JSON文档将自动检测数据的结构和类型,创建一个索引,并使你的数据检索。您还拥有完全控制,以自定义您的数据是如何被索引的。
elasticsearch8.png


友好的RESTful API


Elasticsearch是API驱动。几乎任何动作都可以用一个简单的RESTful API使用JSON基于HTTP请求。客户库可使用多种编程语言。
elasticsearch9.png


操作持久化


Elasticsearch把你的数据安全第一。文档改变被记录在群集上的多个节点上的事务日志(transaction logs)中记录,以减少任何数据丢失的机会。
elasticsearch10.png


Apache 2开源许可证


Elasticsearch可以下载,使用和免费修改。它是基于Apache 2的开源许可证,最灵活的开源许可证。
elasticsearch11.png


基于Apache Lucene之上


Apache Lucene是一个用Java编写的高性能,功能齐全信息检索库。elasticsearch内部利用lucene来构建的分布式和分析功能。
elasticsearch12.png


冲突管理


乐观的版本控制,可以使用在需要的地方,多个进程的冲突变化,开放式版本控制可以确保数据不会丢失。
elasticsearch13.png

英文地址:原文地址 收起阅读 »