TIME_WAIT和CLOSE_WAIT解疑(上)

运维 being 发表了文章 0 个评论 4462 次浏览 2016-02-20 18:11 来自相关话题

一、你遇到过TIME_WAIT的问题吗? 我相信很多人都遇到过这个问题。一旦有用户在喊:网络变慢了。第一件事情就是:netstat -a | grep TIME_WAIT | wc -l 查看一下TIME——WAIT数量 ...查看全部


一、你遇到过TIME_WAIT的问题吗?


我相信很多人都遇到过这个问题。一旦有用户在喊:网络变慢了。第一件事情就是:
netstat -a | grep TIME_WAIT | wc -l 

查看一下TIME——WAIT数量,哎哟好几千个TIME_WAIT.
 
然后,做的第一件事情就是:打开Google、Baidu或者Bing,输入关键词:too many time wait。一定能找到解决方案,而排在最前面或者被很多人到处转载的解决方案一定是:
 
打开 sysctl.conf 文件,修改以下几个参数:
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1
你也会被告知,开启tw_recylce和tw_reuse一定需要timestamps的支持,而且这些配置一般不建议开启,但是对解决TIME_WAIT多的问题,有很大的用处。
 
接下来,你就直接修改了这几个参数,reload一下,发现,咦,没几分钟,TIME_WAIT的数量真的降低了,也没发现哪个用户说有问题,然后就没有然后了。
 
做到这一步,相信50%或者更高比例的运维或者开发就已经止步了。问题好像解决了,但是,要彻底理解并解决这个问题,可能就没这么简单,或者说,还有很长的路要走!


二、什么是TIME-WAIT和CLOSE-WAIT?


所谓,要解决问题,就要先理解问题。随便改两行代码,发现bug“没有了”,也不是bug真的没有了,只是隐藏在更深的地方,你没有发现,或者以你的知识水平,你无法发现而已。
 
大家知道,由于socket是全双工的工作模式,一个socket的关闭,是需要四次握手来完成的。
    []主动关闭连接的一方,调用close();协议层发送FIN包[/][]被动关闭的一方收到FIN包后,协议层回复ACK;然后被动关闭的一方,进入CLOSE_WAIT状态,主动关闭的一方等待对方关闭,则进入FIN_WAIT_2状态;此时,主动关闭的一方 等待 被动关闭一方的应用程序,调用close操作[/][]被动关闭的一方在完成所有数据发送后,调用close()操作;此时,协议层发送FIN包给主动关闭的一方,等待对方的ACK,被动关闭的一方进入LAST_ACK状态;[/][]主动关闭的一方收到FIN包,协议层回复ACK;此时,主动关闭连接的一方,进入TIME_WAIT状态;而被动关闭的一方,进入CLOSED状态[/][]等待2MSL时间,主动关闭的一方,结束TIME-WAIT,进入CLOSED状态[/]
 通过上面的一次socket关闭操作,你可以得出以下几点:[list=1][]主动关闭连接的一方 - 也就是主动调用socket的close操作的一方,最终会进入TIME_WAIT状态[/][]被动关闭连接的一方,有一个中间状态,即CLOSE_WAIT,因为协议层在等待上层的应用程序,主动调用close操作后才主动关闭这条连接[/][]TIME_WAIT会默认等待2MSL时间后,才最终进入CLOSED状态;[/][]在一个连接没有进入CLOSED状态之前,这个连接是不能被重用的![/] 所以,这里凭你的直觉,TIME_WAIT并不可怕(not really,后面讲),CLOSE_WAIT才可怕,因为CLOSE_WAIT很多,表示说要么是你的应用程序写的有问题,没有合适的关闭socket;要么是说,你的服务器CPU处理不过来(CPU太忙)或者你的应用程序一直睡眠到其它地方(锁,或者文件I/O等等),你的应用程序获得不到合适的调度时间,造成你的程序没法真正的执行close操作。 到这里又出现两个问题:[list=1][]上文提到的连接重用,那连接到底是个什么概念?[/][]协议层为什么要设计一个TIME_WAIT状态?这个状态为什么默认等待2MSL时间才会进入CLOSED[/]先解释清楚这两个问题,我们再来看,开头提到的几个网络配置究竟有什么用,以及TIME_WAIT的后遗症问题。

三、Socket连接到底是个什么概念?

大家经常提socket,那么,到底什么是一个socket?其实,socket就是一个 五元组,包括:[list=1][]源IP[/][]源端口[/][]目的IP[/][]目的端口[/][]类型:TCP or UDP[/]这个五元组,即标识了一条可用的连接。注意,有很多人把一个socket定义成四元组,也就是 源IP:源端口 + 目的IP:目的端口,这个定义是不正确的。 例如,如果你的本地出口IP是180.172.35.150,那么你的浏览器在连接某一个Web服务器,例如百度的时候,这条socket连接的四元组可能就是:
[180.172.35.150:45678, tcp, 180.97.33.108:80]
源IP为你的出口IP地址 180.172.35.150,源端口为随机端口 45678,目的IP为百度的某一个负载均衡服务器IP 180.97.33.108,端口为HTTP标准的80端口。 如果这个时候,你再开一个浏览器,访问百度,将会产生一条新的连接:
[180.172.35.150:43678, tcp, 180.97.33.108:80]
这条新的连接的源端口为一个新的随机端口 43678。 如此来看,如果你的本机需要压测百度,那么,你最多可以创建多少个连接呢? 第二个问题,TIME_WAIT有什么用?如果我们来做个类比的话,TIME_WAIT的出现,对应的是你的程序里的异常处理,它的出现,就是为了解决网络的丢包和网络不稳定所带来的其他问题: 第一,防止前一个连接【五元组,我们继续以 180.172.35.150:45678, tcp, 180.97.33.108:80 为例】上延迟的数据包或者丢失重传的数据包,被后面复用的连接【前一个连接关闭后,此时你再次访问百度,新的连接可能还是由180.172.35.150:45678, tcp, 180.97.33.108:80 这个五元组来表示,也就是源端口凑巧还是45678】错误的接收(异常:数据丢了,或者传输太慢了),参见下图: 
ACK.png
SEQ=3的数据包丢失,重传第一次,没有得到ACK确认
    []如果没有TIME_WAIT,或者TIME_WAIT时间非常端,那么关闭的连接【180.172.35.150:45678, tcp, 180.97.33.108:80 的状态变为了CLOSED,源端口可被再次利用】,马上被重用【对180.97.33.108:80新建的连接,复用了之前的随机端口45678】,并连续发送SEQ=1,2 的数据包[/][]此时,前面的连接上的SEQ=3的数据包再次重传,同时,seq的序号刚好也是3(这个很重要,不然,SEQ的序号对不上,就会RST掉),此时,前面一个连接上的数据被后面的一个连接错误的接收[/]
 第二,确保连接方能在时间范围内,关闭自己的连接。其实,也是因为丢包造成的,参见下图:
ACK1.png
    []主动关闭方关闭了连接,发送了FIN;[/][]被动关闭方回复ACK同时也执行关闭动作,发送FIN包;此时,被动关闭的一方进入LAST_ACK状态[/][]主动关闭的一方回去了ACK,主动关闭一方进入TIME_WAIT状态;[/][]但是最后的ACK丢失,被动关闭的一方还继续停留在LAST_ACK状态[/][]此时,如果没有TIME_WAIT的存在,或者说,停留在TIME_WAIT上的时间很短,则主动关闭的一方很快就进入了CLOSED状态,也即是说,如果此时新建一个连接,源随机端口如果被复用,在connect发送SYN包后,由于被动方仍认为这条连接【五元组】还在等待ACK,但是却收到了SYN,则被动方会回复RST[/][]造成主动创建连接的一方,由于收到了RST,则连接无法成功 [/]

所以,你看到了,TIME_WAIT的存在是很重要的,如果强制忽略TIME_WAIT,还是有很高的机率,造成数据粗乱,或者短暂性的连接失败。
 
那么,为什么说,TIME_WAIT状态会是持续2MSL(2倍的max segment lifetime)呢?这个时间可以通过修改内核参数调整吗?第一,这个2MSL,是RFC 793里定义的,参见RFC的截图标红的部分:
RFC.png
#define TCP_TIMEWAIT_LEN (60[i]HZ) /[/i] how long to wait to destroy TIME-WAIT
[i] state, about 60 seconds [/i]/
所以,再次回想一下前面的问题,如果一条连接,即使在四次握手关闭了,由于TIME_WAIT的存在,这个连接,在1分钟之内,也无法再次被复用,那么,如果你用一台机器做压测的客户端,你一分钟能发送多少并发连接请求?如果这台是一个负载均衡服务器,一台负载均衡服务器,一分钟可以有多少个连接同时访问后端的服务器呢?
 
写到这里,也许你稍微理解了TIME_WAIT和CLOSE_WAIT的区别!


分享原文:大房说


Hbase的Python API模块Starbase介绍

编程 chris 发表了文章 0 个评论 6051 次浏览 2016-02-20 16:14 来自相关话题

The following guest post is provided by Artur Barseghyan, a web developer currently employed by Goldmund, Wyldebeast & Wunderliebe ...查看全部
The following guest post is provided by Artur Barseghyan, a web developer currently employed by Goldmund, Wyldebeast & Wunderliebe in The Netherlands.

Python is my personal (and primary) programming language of choice and also happens to be the primary programming language at my company. So, when starting to work with a new technology, I prefer to use a clean and easy (Pythonic!) API.

After studying tons of articles on the web, reading (and writing) white papers, and doing basic performance tests (sometimes hard if you’re on a tight schedule), my company recently selected Cloudera for our Big Data platform (including using Apache HBase as our data store for Apache Hadoop), with Cloudera Manager serving a role as “one console to rule them all.”

However, I was surprised shortly thereafter to learn about the absence of a working Python wrapper around the REST API for HBase (aka Stargate). I decided to write one in my free time, and the result, ladies and gentlemen, wasStarbase (GPL).

In this post, I will provide some code samples and briefly explain what work has been done on Starbase. I assume that reader of this blog post already has some basic understanding of HBase (that is, of tables, column families, qualifiers, and so on).


一、安装


Next, I’ll show you some frequently used commands and use cases. But first, install the current version of Starbase from CheeseShop (PyPi).
# pip install starbase
导入模块:
>>> from starbase import Connection
…and create a connection instance. Starbase defaults to 127.0.0.1:8000; if your settings are different, specify them here.
>>> c = Connection()


二、API 操作实例


2.1 显示所有的表
假设有两个现有的表名为table1和table2表,以下将会打印出来。
>>> c.tables()
['table1', 'table2']
2.2 表的设计操作
每当你需要操作的表,你需要先创建一个表的实例。
创建一个表实例(注意,在这一步骤中没有创建表):
>>> t = c.table('table3')
Create a new table:
Create a table with columns ‘column1′, ‘column2′, ‘column3′ (here the table is actually created):
>>> t.create('column1', 'column2', 'column3')
201
检查表是否存在:
>>> t.exists()
True
查看表的列:
>>> t.columns()
['column1', 'column2', 'column3']
将列添加到表,(‘column4’,‘column5’,‘column6’,‘column7’):
>>> t.add_columns('column4', 'column5', 'column6', 'column7')
200
删除列表,(‘column6’, ‘column7’):
>>> t.drop_columns('column6', 'column7')
201
删除整个表:
>>> t.drop()
200
2.3 表的数据操作
将数据插入一行:
>>> t.insert(
[quote]>> 'my-key-1',
>>> {
>>> 'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
>>> 'column2': {'key21': 'value 21', 'key22': 'value 22'},
>>> 'column3': {'key32': 'value 31', 'key32': 'value 32'}
>>> }
>>> )
200
请注意,您也可以使用“本地”的命名方式列和细胞(限定词)。以下的结果等于前面的例子的结果。
>>> t.insert(
>>> 'my-key-1a',
>>> {
>>> 'column1:key11': 'value 11', 'column1:key12': 'value 12', 'column1:key13': 'value 13',
>>> 'column2:key21': 'value 21', 'column2:key22': 'value 22',
>>> 'column3:key32': 'value 31', 'column3:key32': 'value 32'
>>> }
>>> )
200
更新一排数据:
>>> t.update(
>>> 'my-key-1',
>>> {'column4': {'key41': 'value 41', 'key42': 'value 42'}}
>>> )
200
Remove a row cell (qualifier):
>>> t.remove('my-key-1', 'column4', 'key41')
200
Remove a row column (column family):
>>> t.remove('my-key-1', 'column4')
200
Remove an entire row:
>>> t.remove('my-key-1')
200
Fetch a single row with all columns:
>>> t.fetch('my-key-1')
{
'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
'column2': {'key21': 'value 21', 'key22': 'value 22'},
'column3': {'key32': 'value 31', 'key32': 'value 32'}
}
Fetch a single row with selected columns (limit to ‘column1′ and ‘column2′ columns):
>>> t.fetch('my-key-1', ['column1', 'column2'])
{
'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
'column2': {'key21': 'value 21', 'key22': 'value 22'},
}
Narrow the result set even more (limit to cells ‘key1′ and ‘key2′ of column `column1` and cell ‘key32′ of column ‘column3′):
>>> t.fetch('my-key-1', {'column1': ['key11', 'key13'], 'column3': ['key32']})
{
'column1': {'key11': 'value 11', 'key13': 'value 13'},
'column3': {'key32': 'value 32'}
}
Note that you may also use the native means of naming the columns and cells (qualifiers). The example below does exactly the same thing as the example above.
>>>  t.fetch('my-key-1', ['column1:key11', 'column1:key13', 'column3:key32'])
{
'column1': {'key11': 'value 11', 'key13': 'value 13'},
'column3': {'key32': 'value 32'}
}
If you set the perfect_dict argument to False, you’ll get the native data structure:
>>>  t.fetch('my-key-1', ['column1:key11', 'column1:key13', 'column3:key32'], perfect_dict=False)
{
'column1:key11': 'value 11', 'column1:key13': 'value 13',
'column3:key32': 'value 32'
}
2.4 对表数据批处理操作
Batch operations (insert and update) work similarly to routine insert and update, but are done in a batch. You are advised to operate in batch as much as possible.[/quote]

In the example below, we will insert 5,000 records in a batch:  
>>> data = {
[quote]>> 'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
>>> 'column2': {'key21': 'value 21', 'key22': 'value 22'},
>>> }
>>> b = t.batch()
>>> for i in range(0, 5000):
>>> b.insert('my-key-%s' % i, data)
>>> b.commit(finalize=True)
{'method': 'PUT', 'response': [200], 'url': 'table3/bXkta2V5LTA='}
In the example below, we will update 5,000 records in a batch:
>>> data = {
>>> 'column3': {'key31': 'value 31', 'key32': 'value 32'},
>>> }
>>> b = t.batch()
>>> for i in range(0, 5000):
>>> b.update('my-key-%s' % i, data)
>>> b.commit(finalize=True)
{'method': 'POST', 'response': [200], 'url': 'table3/bXkta2V5LTA='}
Note: The table batch method accepts an optional size argument (int). If set, an auto-commit is fired each the time the stack is full.
2.5 表数据搜索(行扫描)
A table scanning feature is in development. At the moment it’s only possible to fetch all rows from a table. The result set returned is a generator.[/quote]

注意:表数据扫描功能正在开发中。目前仅支持取出表中所有数据(Full Table Scan),暂不支持范围扫描(RowKey Range Scan),其结果以一个迭代器形式返回。
>>> t.fetch_all_rows()
就介绍到这里了,没有时间翻译,聽简单的英文!

Python访问hbase数据操作脚本分享

编程 chris 发表了文章 0 个评论 3079 次浏览 2016-02-20 15:33 来自相关话题

#!/usr/bin/python import getopt,sys,time from thrift.transport.TSocket import TSocket from thrift.transp ...查看全部
#!/usr/bin/python

import getopt,sys,time
from thrift.transport.TSocket import TSocket
from thrift.transport.TTransport import TBufferedTransport
from thrift.protocol import TBinaryProtocol
from hbase import Hbase

def usage():
print '''Usage :
-h: Show help information;
-l: Show all table in hbase;
-t {table} Show table descriptors;
-t {table} -k {key} : show cell;
-t {table} -k {key} -c {coulmn} : Show the coulmn;
-t {table} -k {key} -c {coulmn} -v {versions} : Show more version;
(write by liuhuorong@koudai.com)
'''

class geilihbase:
def __init__(self):
self.transport = TBufferedTransport(TSocket("127.0.0.1", "9090"))
self.transport.open()
self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport)
self.client = Hbase.Client(self.protocol)
def __del__(self):
self.transport.close()
def glisttable(self):
for table in self.client.getTableNames():
print table
def ggetColumnDescriptors(self,table):
rarr=self.client.getColumnDescriptors(table)
if rarr:
for (k,v) in rarr.items():
print "%-20s\t%s" % (k,v)
def gget(self,table,key,coulmn):
rarr=self.client.get(table,key,coulmn)
if rarr:
print "%-15s %-20s\t%s" % (rarr[0].timestamp,time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(rarr[0].timestamp/1000)),rarr[0].value)
def ggetrow(self,table,key):
rarr=self.client.getRow(table, key)
if rarr:
for (k,v) in rarr[0].columns.items():
print "%-20s\t%-15s %-20s\t%s" % (k,v.timestamp,time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(v.timestamp/1000)),v.value)
def ggetver(self, table, key, coulmn, versions):
rarr=self.client.getVer(table,key,coulmn, versions);
if rarr:
for row in rarr:
print "%-15s %-20s\t%s" % (row.timestamp,time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(row.timestamp/1000)),row.value)

def main(argv):
tablename=""
key=""
coulmn=""
versions=""
try:
opts, args = getopt.getopt(argv, "lht:k:c:v:", ["help","list"])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit(0)
elif opt in ("-l", "--list"):
ghbase=geilihbase()
ghbase.glisttable()
sys.exit(0)
elif opt == '-t':
tablename = arg
elif opt == '-k':
key = arg
elif opt == '-c':
coulmn = arg
elif opt == '-v':
versions = int(arg)
if ( tablename and key and coulmn and versions ):
ghbase=geilihbase()
ghbase.ggetver(tablename, key, coulmn, versions)
sys.exit(0)
if (tablename and key and coulmn ):
ghbase=geilihbase()
ghbase.gget(tablename, key, coulmn)
sys.exit(0)
if (tablename and key ):
ghbase=geilihbase()
ghbase.ggetrow(tablename, key)
sys.exit(0)
if (tablename ):
ghbase=geilihbase()
ghbase.ggetColumnDescriptors(tablename)
sys.exit(0)
usage()
sys.exit(1)

if __name__ == "__main__":
main(sys.argv[1:])

听云你是要停止运营吗?

科技前沿 空心菜 发表了文章 1 个评论 2939 次浏览 2016-02-18 09:50 来自相关话题

今天早上,登陆听云本来想看一下的,这个魔力AMP象限,但是它的注册接口竟然挂了,无图无真相,图见下方: 看来你的魔力只是表面哦,魔力APM? ...查看全部
今天早上,登陆听云本来想看一下的,这个魔力AMP象限,但是它的注册接口竟然挂了,无图无真相,图见下方:
tingyun.png

看来你的魔力只是表面哦,魔力APM?
APM.png

GZ.png

别整这么多没用的,先把自己监控、分析起来吧。放这么多狗肉干嘛!哈哈,闲来无事,嘿嘿!

Redis高可用集群开源项目Codis介绍

开源项目 koyo 发表了文章 0 个评论 3643 次浏览 2016-02-17 23:56 来自相关话题

Redis在豌豆荚的使用历程---单实例==》多实例,业务代码中做sharding==》单个Twemproxy==》多个Twemproxy==》Codis,豌豆荚自己开发的分布式Redis服务。在大规模的Redis使用过程中,他们发现Redis受限于多个方面: ...查看全部
Redis在豌豆荚的使用历程---单实例==》多实例,业务代码中做sharding==》单个Twemproxy==》多个Twemproxy==》Codis,豌豆荚自己开发的分布式Redis服务。在大规模的Redis使用过程中,他们发现Redis受限于多个方面:单机内存有限、带宽压力、单点问题、不能动态扩容以及磁盘损坏时的数据抢救。
 
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.
 
Codis 由四部分组成:
    []Codis Proxy   (codis-proxy)[/][]Codis Manager (codis-config)[/][]Codis Redis   (codis-server)[/][]ZooKeeper (coordinator)[/]
每个部分都可动态扩容.
codis-proxy 是客户端连接的 Redis 代理服务, codis-proxy 本身实现了 Redis 协议, 表现得和一个原生的 Redis 没什么区别 (就像 Twemproxy), 对于一个业务来说, 可以部署多个 codis-proxy, codis-proxy 本身是无状态的.
 
codis-config是Codis的管理工具, 支持包括, 添加/删除 Redis 节点, 添加/删除 Proxy 节点, 发起数据迁移等操作. codis-config本身还自带了一个 http server, 会启动一个 dashboard, 用户可以直接在浏览器上观察Codis集群的运行状态.
codis-server是Codis项目维护的一个 Redis 分支, 基于 2.8.13 开发, 加入了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 只能和这个版本的 Redis 交互才能正常运行.
Codis 依赖 ZooKeeper 来存放数据路由表和 codis-proxy 节点的元信息, codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy.
Codis 支持按照 Namespace 区分不同的产品, 拥有不同的 product name 的产品, 各项配置都不会冲突.目前 Codis 已经是稳定阶段,目前豌豆荚已经在使用该系统。架构
codis_arch.png
特性:
    []自动平衡[/][]使用非常简单[/][]图形化的面板和管理工具[/][]支持绝大多数 Redis 命令,完全兼容 twemproxy[/][]支持 Redis 原生客户端[/][]安全而且透明的数据移植,可根据需要轻松添加和删除节点[/][]提供命令行接口[/][]RESTful APIs[/]

安装:
cd  /usr/local/go/src/github.com/wandoulabs/codis;./bootstrap.sh
make gotest
ln -s /usr/local/go/src/github.com/wandoulabs/codis/ /usr/local/codis
操作界面展示:
Dashboard
codis_group.png

Migrate
snapshot_migrate.png

Slots
slots.png


项目地址:https://github.com/CodisLabs/codis
项目作者:刘奇


JAVA日志那点事

编程 chris 发表了文章 0 个评论 4125 次浏览 2016-01-30 22:56 来自相关话题

前言 日志这东西在语言里算基础组件了吧,可惜Java界第三方框架向来比原生组件好用也是事实,缺点是框架太多混战江湖,今天我们就理一理这些日志框架。Java的日志框架分为门面(Facade),或者叫通用日志接口,还有日志实现。日志接口不 ...查看全部


前言


日志这东西在语言里算基础组件了吧,可惜Java界第三方框架向来比原生组件好用也是事实,缺点是框架太多混战江湖,今天我们就理一理这些日志框架。Java的日志框架分为门面(Facade),或者叫通用日志接口,还有日志实现。日志接口不用说,就是定下的日志方法规范,需要具体日志组件去实现的(为啥Sun当年没有定义这东西,看看JPA、JDBC、JMS这些规范定义的多好,或者定义了被抛弃了?)。日志实现就是具体的日志组件了,可以实现日志打印到控制台、文件、数据库等等。下面咱们就具体说说这些东西。


Java日志框架分类


日志门面(Facade)
    []Slf4j[/]
全称Simple Logging Facade for JAVA,真正的日志门面,只提供接口方法,当配合特定的日志实现时,需要引入相应的桥接包
    []Common-logging[/]
Apache提供的一个通用的日志接口,common-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库,自己也自带一个功能很弱的日志实现。
差别:[list=1][]Common-logging动态查找日志实现(程序运行时找出日志实现),Slf4j则是静态绑定(编译时找到实现),动态绑定因为依赖ClassLoader寻找和载入日志实现,因此类似于OSGI那种使用独立ClassLoader就会造成无法使用的情况。(呵呵,我一个插件用一个日志框架不行啊,土豪多任性,不过说实话,没用过OSGI,这个我还真没有概念)[/][]Slf4j支持参数化的log字符串,避免了之前为了减少字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),现在你可以直接写:logger.debug(“current user is: {}”, user)。[/]日志实现
    []Log4j[/]
Log4j可能是Java世界里最出名的日志框架了,支持各种目的地各种级别的日志输出,从我刚接触日志就知道这个框架(呵呵,我一直不知道还有JDK Logging这个东西)。最近(也不近了……)Log4j2发布正式版了,没看到谁用,听说也很不错。
    []LogBack[/]
Log4j作者的又一力作(听说是受不了收费文档搞了个开源的,不需要桥接包完美适配Slf4j),个人感觉迄今为止最棒的日志框架了,一直都在用,配置文件够简洁,性能足够好(估计是看自己的Log4j代码差劲了,更新不能解决问题,直接重构了)。
    []JDK Logging 从JDK1.4开始引入,不得不说,你去Google下这个JDK自带的日志组件,并不如Log4j和LogBack之类好用,木有配置文件,日志级别不好理解,想顺心的用估计还得自己封装下,总之大家已经被Log4j惯坏了,JDK的设计并不能被大家认同,唯一的优点我想就是不用引入新额jar包了。[/]


为什么会有门面


看了以上介绍,如果你不是混迹(深陷)Java多年的老手,估计会蒙圈儿了吧,那你肯定会问,要门面干嘛。有了手机就有手机壳、手机膜,框架也一样,门面的作用更多的还是三个字:解耦合。说白了,加入一个项目用了一个日志框架,想换咋整啊?那就一行一行的找日志改呗,想想都是噩梦。于是,门面出来了,门面说啦, 你用我的格式写日志,把日志想写哪儿写哪儿,例如Slf4j-api加上后,想换日志框架,直接把桥接包一换就行。方便极了。
说实话,现在Slf4j基本可以是Java日志的一个标准了,按照它写基本可以实现所有日志实现通吃,但是就有人不服,还写了门面的门面(没错,这个人就是我)。


门面的门面


如果你看过Netty的源码,推荐你看下io.netty.util.internal.logging这个包里内容,会发现Netty又对日志封装了一层,于是灵感来源于此,我也对各大日志框架和门面做了封装。


Hutool-log模块


无论是Netty的日志模块还是我的Hutool-log模块,思想类似于Common Logging,做动态日志实现查找,然后找到相应的日志实现来写入日志,核心代码如下:
/**
* 决定日志实现
* @return 日志实现类
*/
public static Class detectLog(){
List> logClassList = Arrays.asList(
Slf4jLog.class,
Log4jLog.class,
Log4j2Log.class,
ApacheCommonsLog.class,
JdkLog.class
);
for (Class clazz : logClassList) {
try {
clazz.getConstructor(Class.class).newInstance(LogFactory.class).info("Use Log Framework: [{}]", clazz.getSimpleName());
return clazz;
} catch (Error | Exception e) {
continue;
}
}
return JdkLog.class;
}
详细代码可以看这里
说白了非常简单,按顺序实例化相应的日志实现,如果实例化失败(一般是ClassNotFoundException),说明jar不存在,那实例化下一个,通过不停的尝试,最终如果没有引入日志框架,那使用JDK Logging(这个肯定会有的),当然这种方式也和Common-logging存在类似问题,不过不用到跨ClassLoader还是很好用的。
对于JDK Logging,我也做了一些适配,使之可以与Slf4j的日志级别做对应,这样就将各个日志框架差异化降到最小。另一方面,如果你看过我的这篇日志,那你一定了解了我的类名自动识别功能,这样大家在复制类名的时候,就不用修改日志的那一行代码了,在所有类中,日志的初始化只有这一句:
Log log = LogFactory.get();
是不是简洁简洁又简洁?实现方式也很简单:
/**
* @return 获得调用者的日志
*/
public static Log get() {
return getLog(new Exception().getStackTrace()[1].getClassName());
}
通过堆栈引用获得当前类名。
 
作为一个强迫症患者,日志接口我也会定义的非常处女座:
/**
* 日志统一接口
*
* @author Looly
*
*/
public interface Log extends TraceLog, DebugLog, InfoLog, WarnLog, ErrorLog
这样就实现了单一使用,各个日志框架灵活引用的作用了。


分享阅读原文:http://www.xiaoleilu.com/some-thing-about-java-log/


KVM虚拟机CPU绑定性能调优

大数据 Geek小A 发表了文章 0 个评论 6657 次浏览 2016-01-29 21:32 来自相关话题

关于linux 进程的处理器亲和性的vCPU 隔离和绑定之前已经做过测试,查考 ubuntu中测试进程的处理器亲和性和vCPU的绑定。查看链接:Setting KVM processor affinities 那么KVM 虚拟化下如何直接为虚拟机 ...查看全部
关于linux 进程的处理器亲和性的vCPU 隔离和绑定之前已经做过测试,查考 ubuntu中测试进程的处理器亲和性和vCPU的绑定。查看链接:Setting KVM processor affinities
那么KVM 虚拟化下如何直接为虚拟机绑定CPU 呢,KVM 提供了很方便的方法
查看所有虚拟机:
root@network:~# virsh list --all  
Id Name State
----------------------------------------------------
2 instance-000000ef running
4 instance-000000f3 running
7 instance-00000120 running
10 instance-00000146 running
11 instance-00000147 running
12 instance-00000148 running
26 instance-00000157 running
35 instance-0000015c running
38 instance-00000158 running
39 instance-0000015b running
- instance-00000122 shut off
查看虚拟机信息
root@network:~# virsh dumpxml instance-00000146  

instance-00000146
45d77d2b-723f-40c8-a953-13f886a317f8
4194304
4194304
4

/machine



OpenStack Foundation
OpenStack Nova
2014.1.3
202b2f9b-3fb8-dc11-8e76-e03f490e5d2c
45d77d2b-723f-40c8-a953-13f886a317f8


查看cvpu
root@network:~# ps -ef|grep instance-00000146  
root 21561 13180 0 14:31 pts/12 00:00:00 grep --color=auto instance-00000146
libvirt+ 31858 1 5 Jan08 ? 17:09:02 /usr/bin/qemu-system-x86_64 -name instance-00000146 -S -machine pc-i440fx-trusty,accel=kvm,usb=off -cpu Opteron_G5,+bmi1,+perfctr_nb,+perfctr_core,+topoext,+nodeid_msr,+tce,+lwp,+wdt,+skinit,+ibs,+osvw,+cr8legacy,+extapic,+cmp_legacy,+fxsr_opt,+mmxext,+osxsave,+monitor,+ht,+vme -m 4096 -realtime mlock=off -smp 4,sockets=4,cores=1,threads=1 -uuid 45d77d2b-723f-40c8-a953-13f886a317f8 -smbios type=1,manufacturer=OpenStack Foundation,product=OpenStack Nova,version=2014.1.3,serial=202b2f9b-3fb8-dc11-8e76-e03f490e5d2c,uuid=45d77d2b-723f-40c8-a953-13f886a317f8 -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/instance-00000146.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=discard -no-hpet -no-shutdown -boot strict=on -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/var/lib/nova/instances/45d77d2b-723f-40c8-a953-13f886a317f8/disk,if=none,id=drive-virtio-disk0,format=qcow2,cache=none -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -drive file=/var/lib/nova/instances/45d77d2b-723f-40c8-a953-13f886a317f8/disk.swap,if=none,id=drive-virtio-disk1,format=qcow2,cache=none -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x5,drive=drive-virtio-disk1,id=virtio-disk1 -netdev tap,fd=25,id=hostnet0,vhost=on,vhostfd=34 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=fa:16:3e:83:8e:cf,bus=pci.0,addr=0x3 -chardev file,id=charserial0,path=/var/lib/nova/instances/45d77d2b-723f-40c8-a953-13f886a317f8/console.log -device isa-serial,chardev=charserial0,id=serial0 -chardev pty,id=charserial1 -device isa-serial,chardev=charserial1,id=serial1 -device usb-tablet,id=input0 -vnc 0.0.0.0:8 -k en-us -device cirrus-vga,id=video0,bus=pci.0,addr=0x2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x6
root@network:~# ps -eLo ruser,pid,ppid,lwp,psr|grep 31858
libvirt+ 31858 1 31858 0
libvirt+ 31858 1 31867 6
libvirt+ 31858 1 31869 4
libvirt+ 31858 1 31871 7
libvirt+ 31858 1 31873 0
libvirt+ 31858 1 31882 7
libvirt+ 31858 1 19834 6
libvirt+ 31858 1 20272 6
libvirt+ 31858 1 20679 6
libvirt+ 31858 1 20925 6
libvirt+ 31858 1 20926 6
libvirt+ 31858 1 20927 6
libvirt+ 31858 1 20928 7
libvirt+ 31858 1 20930 6
最后一列是cpu 的编号,重复执行 ps -eLo ruser,pid,ppid,lwp,psr|grep 31858  可以看到 线程是不停在不通cpu 上漂移的,绑定这么多线程是很麻烦的
利用 virsh vcpuinfo instance-00000146  查看每个vCPU 对应物理核心(也是浮动的)
root@network:~# virsh vcpuinfo instance-00000146  
VCPU: 0
CPU: 4
State: running
CPU time: 16025.9s
CPU Affinity: yyyyyyyy 这里看到是宿主机所有物理CPU 核心,Y代表有可以使用,基于CPU时间片来回切换


VCPU: 1
CPU: 6
State: running
CPU time: 20221.3s
CPU Affinity: yyyyyyyy

VCPU: 2
CPU: 6
State: running
CPU time: 12179.5s
CPU Affinity: yyyyyyyy

VCPU: 3
CPU: 5
State: running
CPU time: 12411.4s
CPU Affinity: yyyyyyyy
绑定instance-00000146 的vcpu0 到物理cpu3
root@network:~# virsh vcpupin instance-00000146 0 3  

root@network:~# virsh vcpuinfo instance-00000146
VCPU: 0
CPU: 3
State: running
CPU time: 16033.7s
CPU Affinity: ---y---- 这里看到只有第三个cpu 为Y

VCPU: 1
CPU: 1
State: running
CPU time: 20234.7s
CPU Affinity: yyyyyyyy

VCPU: 2
CPU: 0
State: running
CPU time: 12188.5s
CPU Affinity: yyyyyyyy

VCPU: 3
CPU: 0
State: running
CPU time: 12420.2s
CPU Affinity: yyyyyyyy
依次绑定
root@network:~# virsh vcpupin instance-00000146 1 4  

root@network:~# virsh vcpupin instance-00000146 2 5

root@network:~# virsh vcpupin instance-00000146 3 6

root@network:~# virsh vcpuinfo instance-00000146
VCPU: 0
CPU: 3
State: running
CPU time: 16050.3s
CPU Affinity: ---y----

VCPU: 1
CPU: 4
State: running
CPU time: 20255.6s
CPU Affinity: ----y---

VCPU: 2
CPU: 5
State: running
CPU time: 12203.2s
CPU Affinity: -----y--

VCPU: 3
CPU: 6
State: running
CPU time: 12438.0s
CPU Affinity: ------y-

KVM之初体验-手动及自动化安装

大数据 Geek小A 发表了文章 0 个评论 3910 次浏览 2016-01-29 21:25 来自相关话题

一,什么是KVM KVM包括很多部件:首先,它是一个Linux内核模块(现在包括在主线中)用于转换处理器到一种新的用户 (guset) 模式。用户模式有自己的ring状态集合,但是特权ring0的指令会陷入到管理器(hyperviso ...查看全部


一,什么是KVM


KVM包括很多部件:首先,它是一个Linux内核模块(现在包括在主线中)用于转换处理器到一种新的用户 (guset) 模式。用户模式有自己的ring状态集合,但是特权ring0的指令会陷入到管理器(hypervisor)的代码。由于这是一个新的处理器执行模型,代 码不需要任何的改动。   除了处理器状态转换,这个内核模块同样处理很小一部分低层次的模拟,比如MMU注册(用于管理VM)和一部分PCI模拟的硬件。 在可预见的未来,Qemu团队专注于硬件模拟和可移植性,同时KVM团队专注于内核模块(如果某些部分确实有性能提升的话,KVM会将一小部分模拟代码移 进来)和与剩下的用户空间代码的交互。 kvm-qemu可执行程序像普通Qemu一样:分配RAM,加载代码,不同于重新编译或者调用calling KQemu,它创建了一个线程(这个很重要);这个线程调用KVM内核模块去切换到用户模式,并且去执行VM代码。当遇到一个特权指令,它从新切换会 KVM内核模块,该内核模块在需要的时候,像Qemu线程发信号去处理大部分的硬件仿真。 这个体系结构一个比较巧妙的一个地方就是客户代码被模拟在一个posix线程,这允许你使用通常Linux工具管理。如果你需要一个有2或者4核的虚拟 机,kvm-qemu创建2或者4个线程,每个线程调用KVM内核模块并开始执行。并发性(若果你有足够多的真实核)或者调度(如果你不管)是被通用的 Linux调度器,这个使得KVM代码量十分的小 当一起工作的时候,KVM管理CPU和MEM的访问,QEMU仿真硬件资源(硬盘,声卡,USB,等等)当QEMU单独运行时,QEMU同时模拟CPU和 硬件。


二、KVM架构


kvm基本结构有2个部分构成:
    [] kvm 驱动,现在已经是linux kernel的一个模块了。其主要负责虚拟机的创建,虚拟内存的分配,VCPU寄存器的读写以及VCPU的运行。[/][]另个组成是Qemu,用于模拟虚拟机的用户空间组件,提供I/O设备模型,访问外设的途径。[/]

kvm.jpg


三、KVM 工作原理


kvm基本工作原理概述:
用户模式的qemu利用libkvm通过ioctl进入内核模式,kvm模块未虚拟机创建虚拟内存,虚拟CPU后执行VMLAUCH指令进入客户模 式。加载Guest OS并执行。如果Guest OS 发生外部中断或者影子页表缺页之类的情况,会暂停Guest OS的执行,退出客户模式出行异常处理,之后重新进入客户模式,执行客户代码。如果发生I/O事件或者信号队列中有信号到达,就会进入用户模式处理。
如下图所示:
kvmlc.png


四、手动安装配置KVM


1.安装前的准备
1.CPU支持虚拟化(Inter-VT、AMD-V)
[root@localhost ~]# grep --color 'svm|vmx|lm' /proc/cpuinfo

相关CPU功能标志包括:
svm=安全虚拟机(AMD-V)
vmx=虚拟机x86(Inter-VT)
lm=长模式(64位支持)

2. BIOS开启CPU虚拟化支持
1)重启
2)按delete键
3) 进入BIOS开启  
2.安装虚拟化(yum配置完毕)
# yum -y install kvm python-virtinst libvirt bridge-utils
virt-manager qemu-kvm-tools virt-viewer virt-v2v qemu-kvm tunctl
[root@localhost ~]#vim /etc/sysconfig/selinux //关闭selinux
SELINUX=disabled

3.启动libvirtd
[root@localhost ~]# /etc/init.d/libvirtd start //启动
[root@localhost ~]# ps -e|grep libvirtd //查看是否启动
[root@localhost ~]#chkconfig libvirtd on
注释:永久开启!不然系统重启后不会自动启动这个服务的哟~
# virsh iface-bridge eth0 br0
注释:创建网络桥!
验证:
ifconfig br0
注释:观察IP地址是否跑到了br0网卡上! 
4.配置网络桥接
root@localhost network-script]# vi ifcfg-eth0
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
BRIDGE=br0

[root@localhost network-scripts]# vi ifcfg-br0
DEVICE=br0
TYPE=Bridge
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.100
GATEWAY=192.168.0.1
NETMASK=255.255.255.0
DNS1=192.168.0.1
DELAY=0

5.重启网络
[root@localhost]# service NetworkManager stop //这个关闭掉就行
停止 NetworkManager 守护进程: [确定]
注释:为什么关闭它呢~因为它和KVM桥接网卡冲突!
#chkconfig NetworkManager off
注释:永久关闭该服务!!!不然系统重启后还会自己再把这个服务开启的哟~
[root@localhost rules.d]# service network restart


6.用virt-install生成.img文件(参数含义在上一篇KVM初体验已有注释)
# virt-install --name=ubuntu1
--ram 1024 --vcpus=1
--disk path=/root/ubuntu1.img,size=10
--accelerate --cdrom /root/redhat6.4.iso
--graphics vnc,port=5920 --network bridge=br0
[root@localhost ~]# vi /etc/libvirt/qemu.conf
vnc_listen = "0.0.0.0"
user = "root" //去掉注释
group = "root" //去掉注释
dynamic_ownership = 0 //去掉注释,把1改为0

7.启动虚拟机
虚拟机使用方法:
virsh destroy 虚拟机名 #关闭虚拟机
virsh undefine 虚拟机名 #删除虚拟机
virsh start 虚拟机名 #开启虚拟机
virsh list --all 显示所有虚拟机
virsh console 虚拟机名 #连接虚拟机
手动安装完毕,现在就可以在命令行里秀操作了。


五、自动化脚本安装KVM


#!/bin/bash
echo "[1] 配置YUM"
echo "[2] 安装KVM工具"
echo "[3] 设置桥接"
echo "[4] 手动安装虚拟机"
echo "[5] 查看虚拟机"
echo "[6] 开启虚拟机"
echo "[7] 关闭虚拟机"
echo "[8] 连接虚拟机"
echo "[9] 自动安装虚拟机"
echo "[0] 退出"
read -p "type:" NUM
if [ $NUM = 0 ];then
exit;
elif [ $NUM = 1 ];then
#配置YUM
rm -rf /etc/yum.repos.d/*;
cat > /etc/yum.repos.d/yum.repo << EOF
[yum]
name=yum
enabled=1
gpgcheck=0
baseurl=ftp://192.168.0.200/rhel6.4
EOF
elif [ $NUM = 2 ];then
#安装KVM工具
LANG=en yum groupinstall "Virtualization*" -y;
elif [ $NUM = 3 ];then
#设置桥接
chkconfig NetworkManager off;
chkconfig network on;
service NetworkManager stop;
service network start;
yum install "bridge-utils" -y;
service libvirtd restart;
chkconfig libvirtd on;
virsh iface-bridge eth0 br0;
elif [ $NUM = 4 ];then
#安装虚拟机
read -p "输入虚拟机的名字:" NAME
read -p "输入虚拟及硬盘大小(G): " SIZE
read -p "输入虚拟机内存大小(M): " MEM
ping -c 1 192.168.0.200 > /dev/null
if [ $? -ne 0 ];then
echo "无法接连192.168.0.200,请检查网络!";
exit;
fi
virt-install --nographics -n $NAME --os-type=linux --os-variant=rhel6 -r $MEM --arch=x86_64 --vcpus=1 --disk path=/var/lib/libvirt/images/$NAME,size=$SIZE,format=qcow2 -w bridge=br0 -l ftp://172.16.8.100/rhel6.4 -x " console=ttyS0";
elif [ $NUM = 5 ];then
#查看虚拟机
virsh list --all
elif [ $NUM = 6 ];then
#开机
read -p "虚拟机名称: " XNAME
virsh start $XNAME;
elif [ $NUM = 7 ];then
#关闭
read -p "虚拟机名称: " XNAME &> /dev/null
virsh destroy $XNAME;
elif [ $NUM = 8 ];then
#连接虚拟机
read -p "虚拟机名称: " XNAME
virsh console $XNAME;
elif [ $NUM = 9 ];then
#自动安装虚拟机
read -p "输入虚拟机的名字:" NAME
read -p "输入虚拟及硬盘大小(G): " SIZE
read -p "输入虚拟机内存大小(M): " MEM
ping -c 1 192.168.0.200 > /dev/null
if [ $? -ne 0 ];then
echo "无法接连192.168.0.200,请检查网络!";
exit;
fi
virt-install --nographics -n $NAME --os-type=linux --os-variant=rhel6 -r $MEM --arch=x86_64 --vcpus=1 --disk path=/var/lib/libvirt/images/$NAME,size=$SIZE,format=qcow2 -w bridge=br0 -l ftp://192.168.0.200/rhel6.4 -x "ks=ftp://192.168.0.200/rhel6.4.ks console=ttyS0";


else
echo "请输入:0~4数字!";
fi
注:此脚本已基本实现KVM自动化安装的基本功能。


总结


其实KVM的安装和使用都很方便简单的,大家要理解KVM各个参数的含义。最关键的就是KVM的网络桥接的设置,但是现在KVM在某些方面还是有一定的缺陷(比如创建光驱要关机等),希望会在后续版本中有所改进,在这里大家要多看官方软件自身的文档,会有很大的帮助。


分享原文地址:http://5323197.blog.51cto.com/5313197/1738805


Cpu/Memory/IO虚拟化详解

大数据 chris 发表了文章 0 个评论 4131 次浏览 2016-01-29 13:52 来自相关话题

一、定义 虚拟化是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。虚拟化技术 ...查看全部


一、定义


虚拟化是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。
虚拟化技术可以扩大硬件的容量,简化软件的重新配置过程。CPU的虚拟化技术可以单CPU模拟多CPU并行,允许一个平台同时运行多个操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。


二、虚拟化的类别


虚拟化的类别有很多,定义也很宽泛;无法做到全面详述。这里将简单说明:
1、模拟:emulation(底层和模拟架构不需要一致);通过软件模拟是需要模拟环Ring0/1/2/3层;但是性能差;所以使用相对较少。
硬件 ---> Host ---> VMM(emulation) ---> Virtulization host
vt1.png
2、完全虚拟化(full-virtualization):只虚拟出环ring0(以CPU虚拟化来说明)

    []BT:二进制翻译技术(Binary Translate);将模拟的CPU直接翻译成特权指令;限定虚拟结构平台和底层物理架构必须保持一致。基于软件的完全虚拟化。[/][]优点:不用修改GuestOS内核可以直接使用;应用广泛。[/][]缺点:在VMM捕获特权指令和翻译过程会导致性能的下降。[/]
vt2.png
    []硬件辅助虚拟化:5个指令环;在环0的底层加了环-1;环0的特权指令给了环-1;HVM(hardware virtulization machine);属于硬件的完全虚拟化。[/]
vt3.png
3、半虚拟化(para-virtulization):Guest明确知道自己运行在虚拟机上;;在执行特权指令时直接向hyper call调用;省去了特权指令的翻译过程。
    []优点:相对完全虚拟化;性能高;省去了特权指令的翻译过程。[/][]缺点:需要对GuestOS内核的修改;应用有限制。[/]
vt4.png
4、OS级别的虚拟化:硬件-->OS kernel-->多个用户空间
vt5.png
5、库虚拟化:wine
6、应用程序虚拟化:jvm
虚拟化的实现方式两种类型:
    []Type-I:Hypervisor;在虚拟机的管理上更加的彻底和可靠。[/][]Type-II:宿主机运行在硬件上;可以依赖宿主机的各种管理软件进行虚拟机管理。[/]
 
vt6.png

三、内存(Memory)虚拟化

内存虚拟化是虚拟机实现中的重要部分。在虚拟机中,虚拟出来的Guest OS和Host OS用的是相同的物理内存,却不能让它们相互影响到。如果OS在物理机上运行,只要OS提供页表,MMU会在访存时自动做虚拟地址(Virtual address, VA)到物理地址(Physical address, PA)的转化。而如果虚拟机上运行时,Guest OS经过地址转化到的“物理地址”并不是真实物理内存上的地址(GVA-->GPA),因此还需要使用软件将其转化为真实物理内存地址(HPA)。也就是说Guest OS要访问VA需要经过GVA-->GPA-->HPA的转化。
    []MMU Virtualization[/]
Guest完成GVA-->GPA第一层转化,硬件同时完成GPA到HPA这第二层转化。第二层转化对于Guest OS来说是透明的。Guest OS访问内存时和在物理机运行时是相同的,所以可以实现全虚拟化。这种特性Intel和AMD都有支持。Intel称之为Extended Page Tables (EPT),AMD称之为Nested Page Tables (NPT)。其优点是hypervisor节省了工作,缺点是需要硬件支持。
    []TLB Virtualization:tagged TLB[/]
TLB:转换后援存储器;原生只存储VA-->PA的对应关系。所以在虚拟内存中的两次转换会导致TLB的命中率失效。致使性能降低。所以使用tagged TLB,它缓存了Guest对象和GVA-->HPA的对应关系。需要CPU的支持。

四、I/O虚拟化的方式

    []模拟(完全虚拟):完全使用软件来模拟真实硬件;模拟通常硬件;例如键盘鼠标;通过焦点捕获;焦点被哪个主机捕获就被哪个主机使用。性能很差。[/][]半虚拟化:对硬件驱动由前端(IO frontend)直接转到后端(IO backend)调用;通常仅适用于硬盘和网卡。性能高。[/][]IO-through:IO透传;直接分配给虚拟机物理设备;例如直接分配一个硬盘或网卡给虚拟机;需要硬件具备IO透传技术;在Xen下由Dom0分配;但是访问使用直接使用;不经过Dom0。需要硬件支持。[/]
I/O具体工作模式:
v7.png
VMM:对IO的驱动有三种模式:
    []自主VMM:由VMM自行提供驱动和控制台;[/][]混合VMM:借助于OS提供驱动;[/]
                              依赖于外部OS实现特权域                              自我提供特权域
    []寄宿式VMM:[/]


五、虚拟化网络


bridge:把原宿主机上的网卡当交换机;然后虚拟出一个桥来接收发往宿主机的数据包。
vm8.png

isolation mode:仅guest之间通信;不与外部网络和宿主机通信。
v9.png

routed mode:与外部主机通信;依赖于静态路由指定到各Guest需经过pnet0。
host-only:不与外部主机通信。
vt10.png

nat:地址转换;在虚拟网卡和物理网卡之间建立一个nat转发服务器;对数据包进行源地址转换。
vt11.png

到此基本虚拟化基础以详解完成。


分享阅读原文:http://www.toxingwang.com/cloud/2885.html


服务器磁盘只读修复过程记录

运维 Ansible 发表了文章 0 个评论 3652 次浏览 2016-01-29 11:04 来自相关话题

服务器的磁盘也没有做监控,其实我也不知道如何对磁盘的状态做监控,突然查看不到新数据,上去看了一下磁盘的情况,发现磁盘出现只读的情况,无法写入数据,后续研究一下怎么可以监控磁盘只读的方法。 处理过程 1、磁盘坏 ...查看全部
服务器的磁盘也没有做监控,其实我也不知道如何对磁盘的状态做监控,突然查看不到新数据,上去看了一下磁盘的情况,发现磁盘出现只读的情况,无法写入数据,后续研究一下怎么可以监控磁盘只读的方法。


处理过程


1、磁盘坏道检查
出现问题之后,首先把业务停掉了,然后把磁盘卸载掉来进行修复,出现这种问题有可能是磁盘的磁道有坏区,我首先检查了一下磁盘坏道的情况。
badblocks -sv /dev/sdb
差不多检查了一些时间,发现并没有坏道。
 
2、修复磁盘文件系统
在修复文件系统的时候发现无法修复,提示Superblock invalid。
[root@ad4 ~]# fsck -t ext4 /dev/sdb
fsck from util-linux-ng 2.17.2
e2fsck 1.41.12 (17-May-2010)
fsck.ext4: Superblock invalid, trying backup blocks...
fsck.ext4: Bad magic number in super-block while trying to open /dev/sdb
The superblock could not be read or does not describe a correct ext2
filesystem. If the device is valid and it really contains an ext2
filesystem (and not swap or ufs or something else), then the superblock
is corrupt, and you might try running e2fsck with an alternate superblock:
e2fsck -b 8193
3、查看文件系统备份Superblock
[root@ad4 ~]# mke2fs -n /dev/sdb         
mke2fs 1.41.12 (17-May-2010)
/dev/sdb is entire device, not just one partition!
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=1 blocks, Stripe width=0 blocks
122093568 inodes, 488364854 blocks
24418242 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
14904 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000, 214990848
4、修复文件系统
e2fsck -b 214990848 -y /dev/sdb
出现了很多修复的东西,修复了一会
disk1.png

 修复好之后,挂载进去目录查看如下
disk2.png

好歹只是丢失了文件夹的名称,剩下的回复交由DBA来进行操作。


分享阅读原文:http://wangzan18.blog.51cto.com/8021085/1739473