首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

openstack学习笔记九 cinder基础配置

cinder 就是 云硬盘 配置cinder步骤 1 安装软件包,然后到keystone注册 创建必要的用户名 密码 服务 endpoint 2 设置配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 yum install openstack-cinder-y keystoneuser-create--namecinder--passhequan keystoneuser-role-add--usercinder--roleadmin--tennatservices keystoneservice-create--namecinder-- type volume--descriptioncinderxxx 例子关于cul keystoneservice-list |d1271040fa9144318a836a0b476d1e66|cinder|volume|CinderService| keystoneendpoint-list| grep d1271040fa9144318a836a0b476d1e66 |8e18c46fc51c4a6287ea740a37537a59|RegionOne|http: //115 .29.107.17:8776 /v1/ %(tenant_id)s|http: //115 .29.107.17:8776 /v1/ %(tenant_id)s|http: //115 .29.107.17:8776 /v1/ %(tenant_id)s|d1271040fa9144318a836a0b476d1e66| keystoneendpoint-create--service- id d1271040fa9144318a836a0b476d1e66--publicul 'http://115.29.107.17:8776/v1/%(tenant_id)s' --internalurl 'http://115.29.107.17:8776/v1/%(tenant_id)s' --adminurl 'http://115.29.107.17:8776/v1/%(tenant_id)s' [root@hequan~(keystone_admin)] #cd/etc/cinder/ [root@hequancinder(keystone_admin)] #ls api- paste .inipolicy.jsonrootwrap.d cinder.confrootwrap.confvolumes [root@hequancinder(keystone_admin)] #cpcinder.confcinder.conf.bak##备份 [root@hequan~(keystone_admin)] #cp/usr/share/cinder/cinder-dist.conf/etc/cinder/cinder.conf##复制配置文件 [root@hequancinder(keystone_admin)] #chownroot.cindercinder.conf##记得修改权限 [root@hequancinder(keystone_admin)] #openstack-db--init-servicecinder--passwordhequan--rootpw123456##创建数据库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 [root@hequancinder(keystone_admin)] #vimcinder.conf [DEFAULT] logdir= /var/log/cinder state_path= /var/lib/cinder lock_path= /var/lib/cinder/tmp volumes_dir= /etc/cinder/volumes iscsi_helper=lioadm rootwrap_config= /etc/cinder/rootwrap .conf auth_strategy=keystone [database] connection=mysql: //cinder :hequan@115.29.107.17 /cinder [keystone_authtoken] admin_tenant_name=services admin_user=cinder admin_password=hequan auth_host=115.29.107.17 auth_port=35357 auth_protocol=http [root@hequancinder(keystone_admin)] #grep^rabbit/etc/keystone/keystone.conf rabbit_host=localhost rabbit_port=5672 rabbit_hosts=localhost:5672 rabbit_use_ssl=False rabbit_userid=guest rabbit_password=guest rabbit_virtual_host=/ rabbit_ha_queues=False ##把这些写到上面的配置文件里,通信用 [root@hequancinder(keystone_admin)] #systemctllist-unit-files|grepcinder openstack-cinder-api.serviceenabled ##用户接口 openstack-cinder-backup.serviceenabled ##备份 openstack-cinder-scheduler.serviceenabled ##调度 openstack-cinder-volume.serviceenabled ##后端存储卷 [root@hequancinder(keystone_admin)] #systemctlis-activeopenstack-cinder-api.service active [root@hequancinder(keystone_admin)] #systemctlstartopenstack-cinder-api.serviceopenstack-cinder-backup.serviceopenstack-cinder-scheduler.serviceopenstack-cinder-volume.service [root@hequancinder(keystone_admin)] #systemctlenableopenstack-cinder-api.serviceopenstack-cinder-backup.serviceopenstack-cinder-scheduler.serviceopenstack-cinder-volume.service 再创建一个cinderv2和上面一样 |8fe36f49892447679bc5433b21591906|cinderv2|volumev2|CinderServicev2| |75a8f5bbf35a42a0bfcd2e6a0d4cea9c|RegionOne|http: //115 .29.107.17:8776 /v2/ %(tenant_id)s|http: //115 .29.107.17:8776 /v2/ %(tenant_id)s|http: //115 .29.107.17:8776 /v2/ %(tenant_id)s|8fe36f49892447679bc5433b21591906| 2 修改配置 1 2 3 4 5 [root@hequancinder(keystone_admin)] #cinderlist +----+--------+------------------+------+------+-------------+----------+-------------+-------------+ |ID|Status|MigrationStatus|Name|Size|VolumeType|Bootable|Multiattach|Attachedto| +----+--------+------------------+------+------+-------------+----------+-------------+-------------+ +----+--------+------------------+------+------+-------------+----------+-------------+-------------+ 1 2 3 4 5 6 创建VG [root@hequancinder(keystone_admin)] #pvcreate/dev/xvdb [root@hequancinder(keystone_admin)] #vgcreatecinder-volumes/dev/xvdb [root@hequancinder(keystone_admin)] #vgs VG #PV#LV#SNAttrVSizeVFree cinder-volumes100wz--n-20.60g20.60g 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 [root@hequancinder(keystone_admin)] #cindercreate--display-namevoll1 +---------------------------------------+--------------------------------------+ |Property|Value| +---------------------------------------+--------------------------------------+ |attachments|[]| |availability_zone|nova| |bootable| false | |consistencygroup_id|None| |created_at|2016-07-27T15:14:07.000000| |description|None| |encrypted|False| | id |7f778803-41cd-492f-b3b7-baa349b9c3dc| |metadata|{}| |migration_status|None| |multiattach|False| |name|voll| |os-vol-host-attr:host|None| |os-vol-mig-status-attr:migstat|None| |os-vol-mig-status-attr:name_id|None| |os-vol-tenant-attr:tenant_id|ddac36f63e4547e0a8619574dbc41534| |os-volume-replication:driver_data|None| |os-volume-replication:extended_status|None| |replication_status|disabled| |size|1| |snapshot_id|None| |source_volid|None| |status|creating| |user_id|9382216e2ea540a2af70216577dbed00| |volume_type|None| +---------------------------------------+--------------------------------------+ [root@hequancinder(keystone_admin)] #cinderlist +--------------------------------------+-----------+------------------+------+------+-------------+----------+-------------+-------------+ |ID|Status|MigrationStatus|Name|Size|VolumeType|Bootable|Multiattach|Attachedto| +--------------------------------------+-----------+------------------+------+------+-------------+----------+-------------+-------------+ |7f778803-41cd-492f-b3b7-baa349b9c3dc|available|-|voll|1|-| false |False|| +--------------------------------------+-----------+------------------+------+------+-------------+----------+-------------+-------------+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ##添加到上面的配置cinder.conf中作为单独字段 [lvm] iscsi_helper=lioadm volume_group=cinder-volumes ##那个组决定默认存储 iscsi_ip_address=115.29.107.17 volume_driver=cinder.volume.drivers.lvm.LVMVolumeDriver ##云硬盘默认存储LVM volumes_dir= /var/lib/cinder/volumes iscsi_protocol=iscsi volume_backend_name=lvm [root@hequancinder(keystone_admin)] #lvs LVVGAttrLSizePoolOriginData%Meta%MoveLogCpy%SyncConvert volume-7f778803-41cd-492f-b3b7-baa349b9c3dccinder-volumes-wi-a-----1.00g [root@hequancinder(keystone_admin)] #lvscan ACTIVE '/dev/cinder-volumes/volume-7f778803-41cd-492f-b3b7-baa349b9c3dc' [1.00GiB]inherit 1 2 3 4 5 6 更换名字 volume_group=vg0 [root@hequancinder(keystone_admin)] #vgrenamecinder-volumesvg0##更改名字 [root@hequan~] #vgs VG #PV#LV#SNAttrVSizeVFree vg0120wz--n-20.60g9.60g 1 2 3 4 5 6 7 8 9 10 11 待测试ceph做后端存储具体ceph配置可看我前一篇glance volume_driver=cinder.volume.drivers.rbd.RBDDriver rbd_pool=cinder #ceph卷名字 rbd_ceph_conf= /etc/ceph/ceph .conf rbd_flatten_volume_from_snapshot= false rbd_max_clone_depth=5 rbd_stone_chunk_size=4 rados_connect_timeout=-1 glance_api_version=2 setfacl-mu:cinder:r-- /etc/ceph/ceph .client.admin.keyring ##cinder可读 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1830981,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android进阶学习】Http编程之HttpClient

在Android开发中,Android SDK附带了Apache的HttpClient,它是一个完善的客户端。它提供了对HTTP协议的全面支持,可以使用HttpClient的对象来执行HTTP GET和HTTP POST调用。 HTTP工作原理: 1.客户端(一般是指浏览器,这里是指自己写的程序)与服务器建立连接 2.建立连接后,客户端向服务器发送请求 3.服务器接收到请求后,向客户端发送响应信息 4.客户端与服务器断开连接 HttpClient的一般使用步骤: 1.使用DefaultHttpClient类实例化HttpClient对象 2.创建HttpGet或HttpPost对象,将要请求的URL通过构造方法传入HttpGet或HttpPost对象。 3.调用execute方法发送HTTP GET或HTTP POST请求,并返回HttpResponse对象。 4.通过HttpResponse接口的getEntity方法返回响应信息,并进行相应的处理。 最后记得要在AndroidManifest.xml文件添加网络权限 <uses-permission android:name="android.permission.INTERNET" /> 下面是具体的例子: 1.使用HttpClient来执行GET调用 在LogCat窗口就能看到输出的信息 packagecom.lingdududu.http; importjava.io.InputStream; importorg.apache.http.HttpResponse; importorg.apache.http.HttpStatus; importorg.apache.http.client.HttpClient; importorg.apache.http.client.methods.HttpGet; importorg.apache.http.impl.client.DefaultHttpClient; importandroid.app.Activity; importandroid.os.Bundle; importandroid.util.Log; publicclassHttpGetActivityextendsActivity{ Stringuri="http://developer.android.com/"; finalStringTAG_STRING="TAG"; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); try{ //得到HttpClient对象 HttpClientgetClient=newDefaultHttpClient(); //得到HttpGet对象 HttpGetrequest=newHttpGet(uri); //客户端使用GET方式执行请教,获得服务器端的回应response HttpResponseresponse=getClient.execute(request); //判断请求是否成功 if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){ Log.i(TAG_STRING,"请求服务器端成功"); //获得输入流 InputStreaminStrem=response.getEntity().getContent(); intresult=inStrem.read(); while(result!=-1){ System.out.print((char)result); result=inStrem.read(); } //关闭输入流 inStrem.close(); }else{ Log.i(TAG_STRING,"请求服务器端失败"); } }catch(Exceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } } 使用HTTP GET调用有一个缺点就是,请求的参数作为URL一部分来传递,以这种方式传递的时候,URL的长度应该在2048个字符之内。如果超出这个这范围,就要使用到HTTP POST调用。 2.使用HttpClient来执行POST调用 使用POST调用进行参数传递时,需要使用NameValuePair来保存要传递的参数。NameValuePair封装了一个键/值组合。另外,还需要设置所使用的字符集。 packagecom.androidbook.services.httppost; importjava.io.BufferedReader; importjava.io.IOException; importjava.io.InputStreamReader; importjava.util.ArrayList; importjava.util.List; importorg.apache.http.HttpResponse; importorg.apache.http.NameValuePair; importorg.apache.http.client.HttpClient; importorg.apache.http.client.entity.UrlEncodedFormEntity; importorg.apache.http.client.methods.HttpPost; importorg.apache.http.impl.client.DefaultHttpClient; importorg.apache.http.message.BasicNameValuePair; importandroid.app.Activity; importandroid.os.Bundle; publicclassHttpPostActivityextendsActivity{ Stringuri="http://developer.android.com/"; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); BufferedReaderin=null; try{ HttpClientclient=newDefaultHttpClient(); HttpPostrequest=newHttpPost("http://code.google.com/android/"); //使用NameValuePair来保存要传递的Post参数 List<NameValuePair>postParameters=newArrayList<NameValuePair>(); //添加要传递的参数 postParameters.add(newBasicNameValuePair("id","12345")); postParameters.add(newBasicNameValuePair("username","dave")); //实例化UrlEncodedFormEntity对象 UrlEncodedFormEntityformEntity=newUrlEncodedFormEntity( postParameters); //使用HttpPost对象来设置UrlEncodedFormEntity的Entity request.setEntity(formEntity); HttpResponseresponse=client.execute(request); in=newBufferedReader( newInputStreamReader( response.getEntity().getContent())); StringBufferstring=newStringBuffer(""); StringlineStr=""; while((lineStr=in.readLine())!=null){ string.append(lineStr+"\n"); } in.close(); StringresultStr=string.toString(); System.out.println(resultStr); }catch(Exceptione){ //Dosomethingaboutexceptions }finally{ if(in!=null){ try{ in.close(); }catch(IOExceptione){ e.printStackTrace(); } } } } } 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/803097

优秀的个人博客,低调大师

【Android进阶学习】屏蔽,捕获Home键

在Level5以上(包含)中,Activity类中的方法:public void onAttachedToWindow ()就能对Home键进行捕获。具体代码如下: MainActivity.java packagecom.lingdududu.test; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.KeyEvent; importandroid.view.WindowManager; importandroid.widget.Toast; publicclassMainActivityextendsActivity{ /**Calledwhentheactivityisfirstcreated.*/ privatebooleancatchHomeKey=false; publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override publicvoidonAttachedToWindow(){ //TODOAuto-generatedmethodstub if(!catchHomeKey){ this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD); } super.onAttachedToWindow(); } @Override publicbooleanonKeyDown(intkeyCode,KeyEventevent){ //TODOAuto-generatedmethodstub if(keyCode==KeyEvent.KEYCODE_HOME){ Toast.makeText(MainActivity.this,"你点击了HOME键",Toast.LENGTH_LONG).show(); } returnsuper.onKeyDown(keyCode,event); } } 当我们点击Home键的时候,程序并没有回到主界面,而是停留在当前的页面,并且能捕获到Home键,调用Toast显示信息。 效果图: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/732092

优秀的个人博客,低调大师

Android开发学习笔记:浅谈DDMS视图

DDMS 的全称是Dalvik Debug Monitor Service,即Dalvik调试监控服务,是一个可视化的调试监控工具。它主要是对系统运行后台日志的监控,还有系统线程,模拟器状态的监控。此外,它还可以模拟收发短信,拨打电话和发送GPS位置信息等。 在eclipse中启动DDMS 1.在eclipse界面的右上角,点击,出现下面的界面 2.选择other,这时界面如下图所示,双击DDMS就可以启动 DDMS各部分组成的功能简介 1.Devices 可以查看到所有与DDMS连 接的模拟器详细信息,以及每个模拟器正在运行的APP进程,每个进程最右边相对应的是与调试器链接的端口。 2.Emulator Control可以实现对模拟器的控制,比如:接听电话,根据选项模拟各种不同网络情况,模拟接受SMS消息和发送虚拟地址坐标用于测试GPS功能等。 Telephony Status:通过选项模拟语音质量以及信号连接模式。 Telephony Actions:模拟电话接听和发送SMS到测试终端。 Location Control:模拟地理坐标或者模拟动态的路线坐标变化并显示预设的地理标识,可以通过以下3种方式: (1)Manual:手动为终端发送二维经纬坐标。 (2)GPX:通过GPX文件导入序列动态变化地理坐标,从而模拟行进中GPS变化的数值。 (3)KML:通过KML文件导入独特的地理标识,并以动态形式根据变化的地理坐标显示在测试终端。 3.LogCat主要输出模拟器的一些信息 4.Filter功能类似过滤器,能过滤一些调试的信息 5. V:输出所有的信息 D:输出Debug信息 I:输出info信息 W:输出警告信息 E:输出错误的信息 :能删除当前LogCat输出的信息 6.Threads、Heap、File Exporler,最常用的就是File Exporler文件浏览器,通过File Exporler可以查看Android模拟器中的文件,可以很方便的导入/出文件。 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/631061

优秀的个人博客,低调大师

Android UI学习 - FrameLayou和布局优化

FrameLayout 先来看官方文档的定义:FrameLayout是最简单的一个布局对象。它被定制为你屏幕上的一个空白备用区域,之后你可以在其中填充一个单一对象 — 比如,一张你要发布的图片。所有的子元素将会固定在屏幕的左上角;你不能为FrameLayout中的一个子元素指定一个位置。后一个子元素将会直接在前一个子元素之上进行覆盖填充,把它们部份或全部挡住(除非后一个子元素是透明的)。 我的理解是,把FrameLayout当作画布canvas,固定从屏幕的左上角开始填充图片,文字等。看看示例,原来可以利用 android:layout_gravity来设置位置的: <?xmlversion="1.0"encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:id="@+id/image" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/candle" /> <TextView android:id="@+id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="#00ff00" android:text="@string/hello" /> <Button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:text="Start" /> </FrameLayout> 效果图 布局优化 使用tools里面的hierarchyviewer.bat来查看layout的层次。在启动模拟器启动所要分析的程序,再启动hierarchyviewer.bat,选择模拟器以及该程序,点击“Load View Hierarchy”,就会开始分析。可以save as png。 <merge>减少视图层级结构 从上图可以看到存在两个FrameLayout,红色框住的。如果能在layout文件中把FrameLayout声明去掉就可以进一步优化布局代码了。 但是由于布局代码需要外层容器容纳,如果 直接删除FrameLayout则该文件就不是合法的布局文件。这种情况下就可以使用<merge> 标签了。 修改为如下代码就可以消除多余的FrameLayout了: <?xmlversion="1.0"encoding="utf-8"?> <mergexmlns:android="http://schemas.android.com/apk/res/android"> <ImageView android:id="@+id/image" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/candle" /> <TextView android:id="@+id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="#00ff00" android:text="@string/hello" /> <Button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:text="Start" /> </merge> <merge>也有一些使用限制: 只能用于xml layout文件的根元素;在代码中使用LayoutInflater.Inflater()一个以merge为根元素的 布局文件时候,需要使用 View inflate (int resource, ViewGroup root, boolean attachToRoot)指定一个ViewGroup 作为其容器,并且要设置attachToRoot 为true。 <include>重用layout代码 如果在某个布局里面需要用到另一个相同的布局设计,可以通过<include> 标签来重用layout代码: <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <includeandroid:id="@+id/layout1"layout="@layout/relative"/> <includeandroid:id="@+id/layout2"layout="@layout/relative"/> <includeandroid:id="@+id/layout3"layout="@layout/relative"/> </LinearLayout> 效果图 这里要注意的是, "@layout/relative"不是引用Layout的id,而是引用res/layout/relative.xml,其内容是前面文章介绍RelativeLayout的布局代码。 另外,通过<include>,除了可以覆写id属性值,还可以修改其他属性值,例如android:layout_width,android:height等。 <viewstub> 延迟加载 (转自 http://rainhomepage.appspot.com/2010/01/use-viewstub-to-optimize-the-layout-of) ViewStub 是一个不可见的,大小为0的View,最佳用途就是实现View的延迟加载,在需要的时候再加载View,可Java中常见的性能优化方法延迟加载一样。 当调用ViewStub的setVisibility函数设置为可见或则调用 inflate初始化该View的时候,ViewStub引用的资源开始初始化,然后引用的资源替代ViewStub自己的位置填充在ViewStub的 位置。因此在没有调用setVisibility(int) 或则 inflate()函数之前 ViewStub一种存在组件树层级结构中,但是由于ViewStub非常轻量级,这对性能影响非常小。 可以通过ViewStub的inflatedId属性来重新定义引用的layout id。 例如: <ViewStubandroid:id="@+id/stub" android:inflatedId="@+id/subTree" android:layout="@layout/mySubTree" android:layout_width="120dip" android:layout_height="40dip"/> 上面定义的ViewStub ,可以通过id “stub”来找到,在初始化资源“mySubTree”后,stub从父组件中删除,然后"mySubTree"替代stub的位置。初始资源"mySubTree"得到的组件可以通过inflatedId 指定的id "subTree"引用。 然后初始化后的资源被填充到一个120dip宽、40dip高的地方。 推荐使用下面的方式来初始化ViewStub: ViewStubstub=(ViewStub)findViewById(R.id.stub); Viewinflated=stub.inflate(); 当调用inflate()函数的时候,ViewStub 被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数 findViewById()来查找了。 ViewStub目前有个缺陷就是还不支持 <merge /> 标签。 layoutopt (Layout Optimization工具) 这工具可以分析所提供的Layout,并提供优化意见。在tools文件夹里面可以找到layoutopt.bat。 用法: layoutopt <list of xml files or directories> 参数: 一个或多个的Layout xml文件,以空格间隔;或者多个Layout xml文件所在的文件夹路径 例子: layoutopt G:\StudyAndroid\UIDemo\res\layout\main.xml layoutopt G:\StudyAndroid\UIDemo\res\layout\main.xml G:\StudyAndroid\UIDemo\res\layout\relative.xml layoutopt G:\StudyAndroid\UIDemo\res\layout 本文转自 Icansoft 51CTO博客,原文链接: http://blog.51cto.com/android/308090

优秀的个人博客,低调大师

openstack学习笔记二 网络设置基础

租用这个服务的机构,我们称之"租户/tenant/项目/project" 租户 用户 vxlan划分租户 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@h1~] #ipaddr 1:lo:<LOOPBACK,UP,LOWER_UP>mtu65536qdiscnoqueuestateUNKNOWN link /loopback 00:00:00:00:00:00brd00:00:00:00:00:00 inet127.0.0.1 /8 scopehostlo valid_lftforeverpreferred_lftforever 2:eth0:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1500qdiscmqstateUPqlen1000 link /ether 00:50:56:a0:b6:6bbrdff:ff:ff:ff:ff:ff inet192.168.1.201 /24 brd192.168.1.255scopeglobaleth0 valid_lftforeverpreferred_lftforever 3:ovs-system:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link /ether 36:26:25:65:14:9cbrdff:ff:ff:ff:ff:ff 4:br-ex:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1500qdiscnoqueuestateUNKNOWN link /ether de:4c:6d:9c:15:4dbrdff:ff:ff:ff:ff:ff 5:br-int:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link /ether ce:0b:9b:b5:c1:4dbrdff:ff:ff:ff:ff:ff 6:br-tun:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link /ether ae:75:26:fb:f8:42brdff:ff:ff:ff:ff:ff 你想把哪个网络作为数据包的出口,那么你就应该把那个网卡桥接到 br-ex openvswitch 简称 ovs 配置网卡 重点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@h1network-scripts] #catifcfg-eth0 DEVICE=eth0 DEVICETYPE=ovs TYPE=OVSPort OVS_BRIDGE=br-ex ONBOOT= yes BOOTPROTO=none [root@h1network-scripts] #catifcfg-br-ex DEVICE=br-ex DEVICETYPE=ovs TYPE=OVSBridge ONBOOT= yes BOOTPROTO=none IPADDR=192.168.1.201 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 DNS1=202.106.0.20 1 2 3 4 5 6 7 8 9 10 查看网卡 2:eth0:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1500qdiscmqmasterovs-systemstateUPqlen1000 link /ether 00:50:56:a0:b6:6bbrdff:ff:ff:ff:ff:ff 3:ovs-system:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link /ether d2:18:7d:5e:5e:b9brdff:ff:ff:ff:ff:ff 5:br-ex:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1500qdiscnoqueuestateUNKNOWN link /ether 00:50:56:a0:b6:6bbrdff:ff:ff:ff:ff:ff inet192.168.1.201 /24 brd192.168.1.255scopeglobalbr-ex valid_lftforeverpreferred_lftforever 管理员登陆http://192.168.1.201/dashboard 选择系统--网络--创建网络 创建,点击网络名称put-ex 下一步 创建一个项目,创建一个新的用户,新用户关联项目。 用新的用户登录,创建网络 先创建网络,然后创建路由,连到网络上,最后添加端口 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1795705,如需转载请自行联系原作者

优秀的个人博客,低调大师

Qt学习之路(30): Graphics View Framework

现在基本上也已经到了2D绘图部分的尾声,所谓重头戏都是在最后压轴的,现在我们就要来看看在绘图部分功能最强大的Graphics View。我们经常说KDE桌面,新版本的KDE桌面就是建立在Graphics View的基础之上,可见其强大之处。 Qt的白皮书里面这样写道:“Qt Graphics View提供了用于管理和交互大量定制的 2D 图形对象的平面以及可视化显示对象的视图 widget,并支持缩放和旋转功能。Graphics View使用 BSP(二进制空间划分)树形可非常快速地找到对象,因此即使是包含百万个对象的大型场景,也能实时图形化显示。” Graphics View是一个基于item的M-V架构的框架。 基于item意思是,它的每一个组件都是一个item。这是与QPainter的状态机不同。回忆一下,使用QPainter绘图多是采用一种面向过程的描述方式,首先使用drawLine()画一条直线,然后使用drawPolygon()画一个多边形;而对于Graphics View来说,相同的过程可以是,首先创建一个场景scene,然后创建一个line对象和一个polygon对象,再使用scene的add()函数将line和polygon添加到scene,最后通过视口view就可以看到了。乍看起来,后者似乎更加复杂,但是,如果你的图像中包含了成千上万的直线、多边形之类,管理这些对象要比管理QPainter的draw语句容易得多。并且,这些图形对象也更加符合面向对象的设计要求:一个很复杂的图形可以很方便的复用。 M-V架构的意思是,Graphics View提供一个model和一个view。所谓model就是我们添加的种种对象,所谓view就是我们观察这些对象的视口。同一个model可以由很多view从不同的角度进行观察,这是很常见的需求。使用QPainter就很难实现这一点,这需要很复杂的计算,而Qt的Graphics View就可以很容易的实现。 Graphics View提供了一个QGraphicsScene作为场景,即是我们添加图形的空间,相当于整个世界;一个QGraphicsView作为视口,也就是我们观察的窗口,相当于照相机的取景框,这个取景框可以覆盖整个场景,也可以是场景的一部分;一些QGraphicsItem作为图形元件,以便scene添加,Qt内置了很多图形,比如line、polygon等,都是继承自QGraphicsItem。 下面我们来看一下代码: #include <QtGui> classDrawApp : publicQWidget { public: DrawApp(); protected: voidpaintEvent(QPaintEvent * event); }; DrawApp::DrawApp() { } voidDrawApp::paintEvent(QPaintEvent * event) { QPainter painter( this); painter.drawLine(10, 10, 150, 300); } intmain( intargc, char*argv[]) { QApplication a(argc, argv); QGraphicsScene *scene = newQGraphicsScene; scene->addLine(10, 10, 150, 300); QGraphicsView *view = newQGraphicsView(scene); view->resize(500, 500); view->setWindowTitle( "Graphics View"); view->show(); DrawApp *da = newDrawApp; da->resize(500, 500); da->setWindowTitle( "QWidget"); da->show(); returna.exec(); } 为了突出重点,我们就直接include了QtGui,不过在实际应用中不建议这么做。这里提供了直线的两种实现:一个是DrawApp使用我们前面介绍的技术,重写paintEvent()函数,这里就不在赘述,重点来看main()函数里面的实现。 首先,我们创建了一个QGraphicsScene作为场景,然后在scene中添加了一个直线,这样就把我们需要的图形元件放到了scene中。然后创建一个QGraphicsView对象进行观察。就这样,我们就是用Graphics View搭建了一个最简单的应用。运行这个程序来看结果: 第一张图是Graphics View的,第二个是DrawApp的。虽然这两个直线是同样的坐标,但是,DrawApp按照原始坐标绘制出了直线,而Graphics View则按照坐标绘制出直线之后,自动将直线居中显示在view视口。你可以通过拖动Graphics View来看直线是一直居中显示的。 这里仅仅是一个很简单的对比,不过你已经可以看到Graphics View功能的强大。仅这一个居中的操作,如果你是用QPainter,就需要很大的计算量了!当然,如果你不需要这种居中,Graphics View也是可以像QPainter绘制的一样进行显示的。 本文转自 FinderCheng 51CTO博客,原文链接:http://blog.51cto.com/devbean/241186

优秀的个人博客,低调大师

【Android进阶学习】Http编程之HttpConnection

HttpURLConnection是继承于URLConnection类,二者都是抽象类。其对象主要通过URL的openConnection方法获得的。 下面是具体的代码: packagecom.llingdududu.url; importjava.io.BufferedReader; importjava.io.InputStreamReader; importjava.net.HttpURLConnection; importjava.net.URL; importandroid.app.Activity; importandroid.os.Bundle; publicclassURLConnectionActivityextendsActivity{ StringurlStr="http://developer.android.com/"; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); try{ //实例化URL URLurl=newURL(urlStr); //使用HttpURLConnection打开连接 HttpURLConnectionhttpConnection=(HttpURLConnection)url.openConnection(); //得到输入流对象 InputStreamReaderin=newInputStreamReader(httpConnection.getInputStream()); BufferedReaderbufReader=newBufferedReader(in); StringlineStr=""; StringresultStr=""; while((lineStr=bufReader.readLine())!=null){ resultStr+=lineStr+"\n"; } System.out.println(resultStr); //关闭输入流 in.close(); //关闭连接 httpConnection.disconnect(); }catch(Exceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } } 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/803159

优秀的个人博客,低调大师

烂泥:haproxy学习之手机规则匹配

今天我们来介绍下有关haproxy匹配手机的一些规则配置。 一、业务需要 现在根据业务的实际需要,有以下几种不同的需求。如下: 1.1转发所有手机请求 所有通过手机端访问http.ilanni.com域名的话,全部转发到http://www.ilanni.com这个地址,而PC端不受此限制。 1.2根据url进行转发 如果手机端请求http.ilanni.com这个域名的url中,以docs或者manager这两个关键词开头的话,把该请求转发到后端的服务器,而PC端不受此限制。 也就是说手机端访问具体的url地址的话,可以正常访问。如果是直接访问http.ilanni.com域名的话,直接把该请求转发到http://www.ilanni.com这个地址。 二、haproxy配置 下面根据不同的业务需求进行配置haproxy,如下。 2.1转发所有手机请求配置 要把所有的手机端请求转到www.ilanni.com这个地址,需要我们首先把访问的终端匹配出来,haproxy可以通过hdr_sub(user-agent)这个参数把手机端匹配出来。 手机端匹配出来后,我们就可以定义相应的规则,把手机端的请求转发到www.ilanni.com这个地址了。 haproxy具体配置文件如下: global log 127.0.0.1 local0 log 127.0.0.1 local1 notice maxconn 4096 uid 188 gid 188 daemon tune.ssl.default-dh-param 2048 defaults log global mode http option httplog option dontlognull option http-server-close option forwardfor except 127.0.0.1 option redispatch retries 3 option redispatch maxconn 2000 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s maxconn 3000 listen admin_stats bind 0.0.0.0:1080 mode http option httplog maxconn 10 stats refresh 30s stats uri /stats stats auth admin:admin stats hide-version frontend weblb bind *:80 acl is_http hdr_beg(host) http.ilanni.com acl ua hdr_sub(user-agent) -i android iphone redirect prefix http://www.ilanni.com if ua use_backend httpserver if is_http backend httpserver balance source server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3 在以上配置文件中,有以下两行需要注意: acl ua hdr_sub(user-agent) -i android iphone redirect prefix http://www.ilanni.com if ua 这两行,第一行是第一个ua规则,该规则是判断是否是手机端。 注意:在此手机端,我们只匹配了安卓手机和iphone。 第二行是跳转规则,如果匹配是手机端的话,那么直接跳转到http://www.ilanni.com这个地址。 如果是PC端的话,默认跳转到httpserver这个后端服务器组。 以上配置是一台服务器对外只提供一个域名访问的请求,如果有两个域名的话,就要进行如下配置: global log 127.0.0.1 local0 log 127.0.0.1 local1 notice maxconn 4096 uid 188 gid 188 daemon tune.ssl.default-dh-param 2048 defaults log global mode http option httplog option dontlognull option http-server-close option forwardfor except 127.0.0.1 option redispatch retries 3 option redispatch maxconn 2000 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s maxconn 3000 listen admin_stats bind 0.0.0.0:1080 mode http option httplog maxconn 10 stats refresh 30s stats uri /stats stats auth admin:admin stats hide-version frontend weblb bind *:80 acl is_http hdr_beg(host) http.ilanni.com acl is_haproxy hdr_beg(host) haproxy.ilanni.com acl ua hdr_sub(user-agent) -i android iphone redirect prefix http://www.ilanni.com if ua !is_haproxy use_backend haproxyserver if ua is_haproxy use_backend haproxyserver if is_haproxy use_backend httpserver if is_http backend httpserver balance source server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3 backend haproxyserver balance source server web1 127.0.0.1:7070 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3 2.2测试转发所有手机请求 现在我们来测试该跳转功能,如下: 通过测试你会发现,在手机浏览器中输入http.ilanni.com会自动跳转到http://www.ilanni.com这个地址。 2.3根据url进行转发配置 根据手机端请求的url进行转发的话,首先也是需要匹配出手机端,然后定义url路径规则。最后结合手机端和url路径规则,进行跳转。 haproxy具体配置文件,如下: global log 127.0.0.1 local0 log 127.0.0.1 local1 notice maxconn 4096 uid 188 gid 188 daemon tune.ssl.default-dh-param 2048 defaults log global mode http option httplog option dontlognull option http-server-close option forwardfor except 127.0.0.1 option redispatch retries 3 option redispatch maxconn 2000 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s maxconn 3000 listen admin_stats bind 0.0.0.0:1080 mode http option httplog maxconn 10 stats refresh 30s stats uri /stats stats auth admin:admin stats hide-version frontend weblb bind *:80 acl is_http hdr_beg(host) http.ilanni.com acl is_docs url_beg /docs /manager acl ua hdr_sub(user-agent) -i android iphone redirect prefix http://www.ilanni.com if ua !is_docs use_backend httpserver if ua is_docs use_backend httpserver if is_http backend httpserver balance source server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3 在上述配置文件中,需要以下几行解释下。 acl is_docs url_beg /docs /manager 定义一个is_docs规则。如果url以/docs或者/manager开头的,则全部属于该规则。 acl ua hdr_sub(user-agent) -i android iphone redirect prefix http://www.ilanni.com if ua !is_docs 这两行首先是匹配出手机端,然后如果是手机端访问,并且访问的不是is_docs规则的话,则直接跳转到http://www.ilanni.com这个地址。 use_backend httpserver if ua is_docs 这条命令是,如果是手机端访问,并且访问的是is_docs规则的话,则直接跳转到httpserver这个后端服务器组。 如果是PC端的话,默认跳转到httpserver这个后端服务器组。 2.4测试根据url进行转发 根据url转发配置完毕后,我们现在来测试。如下: 通过上图,我们可以看到手机端访问http://http.ilanni.com/docs/这个连接的话,是可以直接访问的。 三、其他haproxy配置 在前面我们讲解了有关手机的相关配置,在实际的生产环境中,有时候我们会碰到一些奇奇怪怪的要求。 要求所有手机端访问的http.ilanni.com,转到指定的页面。 haproxy主要配置文件如下: frontend weblb bind *:80 acl is_http hdr_beg(host) http.ilanni.com acl ua hdr_sub(user-agent) -i android iphone redirect prefix http://www.ilanni.com/?p=10624 if ua use_backend httpserver if is_http backend httpserver balance source server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3 以上配置是所有手机端访问的,都跳转到http://www.ilanni.com/?p=10624这个页面。测试如下: 通过上图,我们可以看到手机端的访问确实跳转到了我们指定的页面。 类似这样的要求,一般会在升级公司相关业务时提出,对公司的公网IP可以正常,但是外部访问时,跳转到指定的维护页面。 这个我们可以根据源IP地址进行匹配,在此就不进行详细的讲解了。 通过上图,我们可以看到手机端访问http://http.ilanni.com/manager/status这个连接的话,是可以直接访问的。 通过上图,我们可以看到如果手机端访问的不是is_docs这个规则中定义的url话,则会全部跳转到http://www.ilanni.com这个地址的。 本文转自 烂泥行天下 51CTO博客,原文链接:http://blog.51cto.com/ilanni/1710624

优秀的个人博客,低调大师

新浪微博布局学习——妙用TabHost

正文 一、效果图 红色部分是本文要实现的目标。 二、实现 maintabs.xml <? xmlversion="1.0"encoding="UTF-8" ?> < TabHost android:id ="@android:id/tabhost" android:layout_width ="fill_parent" android:layout_height ="fill_parent" xmlns:android ="http://schemas.android.com/apk/res/android" > < LinearLayout android:orientation ="vertical" android:layout_width ="fill_parent" android:layout_height ="fill_parent" > < FrameLayout android:id ="@android:id/tabcontent" android:layout_width ="fill_parent" android:layout_height ="0.0dip" android:layout_weight ="1.0" /> < TabWidget android:id ="@android:id/tabs" android:visibility ="gone" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:layout_weight ="0.0" /> < RadioGroup android:gravity ="center_vertical" android:layout_gravity ="bottom" android:orientation ="horizontal" android:id ="@id/main_radio" android:background ="@drawable/maintab_toolbar_bg" android:layout_width ="fill_parent" android:layout_height ="wrap_content" > < RadioButton android:text ="@string/main_home" android:checked ="true" android:id ="@+id/radio_button0" android:layout_marginTop ="2.0dip" android:drawableTop ="@drawable/icon_1_n" style ="@style/main_tab_bottom" /> < RadioButton android:id ="@+id/radio_button1" android:layout_marginTop ="2.0dip" android:text ="@string/main_news" android:drawableTop ="@drawable/icon_2_n" style ="@style/main_tab_bottom" /> < RadioButton android:id ="@+id/radio_button2" android:layout_marginTop ="2.0dip" android:text ="@string/main_my_info" android:drawableTop ="@drawable/icon_3_n" style ="@style/main_tab_bottom" /> < RadioButton android:id ="@+id/radio_button3" android:layout_marginTop ="2.0dip" android:text ="@string/menu_search" android:drawableTop ="@drawable/icon_4_n" style ="@style/main_tab_bottom" /> < RadioButton android:id ="@+id/radio_button4" android:layout_marginTop ="2.0dip" android:text ="@string/more" android:drawableTop ="@drawable/icon_5_n" style ="@style/main_tab_bottom" /> </ RadioGroup > </ LinearLayout > </ TabHost > styles.xml < style name ="main_tab_bottom" > < item name ="android:textSize" > @dimen/bottom_tab_font_size </ item > < item name ="android:textColor" > #ffffffff </ item > < item name ="android:ellipsize" > marquee </ item > < item name ="android:gravity" > center_horizontal </ item > < item name ="android:background" > @drawable/home_btn_bg </ item > < item name ="android:paddingTop" > @dimen/bottom_tab_padding_up </ item > < item name ="android:layout_width" > fill_parent </ item > < item name ="android:layout_height" > wrap_content </ item > < item name ="android:button" > @null </ item > < item name ="android:singleLine" > true </ item > < item name ="android:drawablePadding" > @dimen/bottom_tab_padding_drawable </ item > < item name ="android:layout_weight" > 1.0 </ item > </ style > home_btn_bg.xml < selector xmlns:android ="http://schemas.android.com/apk/res/android" > < item android:state_focused ="true" android:state_enabled ="true" android:state_pressed ="false" android:drawable ="@drawable/home_btn_bg_s" /> < item android:state_enabled ="true" android:state_pressed ="true" android:drawable ="@drawable/home_btn_bg_s" /> < item android:state_enabled ="true" android:state_checked ="true" android:drawable ="@drawable/home_btn_bg_d" /> < item android:drawable ="@drawable/transparent" /> </ selector > 代码说明: 1. 需要注意的是他这里把TabWidget的Visibility设置成了gone!也就是默认难看的风格不见了:,取而代之的是5个带风格的单选按钮. 2. 注意为单选按钮设置的style,其中最重要的是为其background设置了home_btn_bg.xml,也就是自定义了选中效果。 Java文件 public class MainTabActivity extends TabActivity implements OnCheckedChangeListener{ private TabHostmHost; private IntentmMBlogIntent; private IntentmMoreIntent; private IntentmInfoIntent; private IntentmSearchIntent; private IntentmUserInfoIntent; @Override protected void onCreate(BundlesavedInstanceState){ super .onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.maintabs); // ~~~~~~~~~~~~初始化 this .mMBlogIntent = new Intent( this ,HomeListActivity. class ); this .mSearchIntent = new Intent( this ,SearchSquareActivity. class ); this .mInfoIntent = new Intent( this ,MessageGroup. class ); this .mUserInfoIntent = new Intent( this ,MyInfoActivity. class ); this .mMoreIntent = new Intent( this ,MoreItemsActivity. class ); initRadios(); setupIntent(); } /** *初始化底部按钮 */ private void initRadios(){ ((RadioButton)findViewById(R.id.radio_button0)).setOnCheckedChangeListener( this ); ((RadioButton)findViewById(R.id.radio_button1)).setOnCheckedChangeListener( this ); ((RadioButton)findViewById(R.id.radio_button2)).setOnCheckedChangeListener( this ); ((RadioButton)findViewById(R.id.radio_button3)).setOnCheckedChangeListener( this ); ((RadioButton)findViewById(R.id.radio_button4)).setOnCheckedChangeListener( this ); } /** *切换模块 */ @Override public void onCheckedChanged(CompoundButtonbuttonView, boolean isChecked){ if (isChecked){ switch (buttonView.getId()){ case R.id.radio_button0: this .mHost.setCurrentTabByTag( " mblog_tab " ); break ; case R.id.radio_button1: this .mHost.setCurrentTabByTag( " message_tab " ); break ; case R.id.radio_button2: this .mHost.setCurrentTabByTag( " userinfo_tab " ); break ; case R.id.radio_button3: this .mHost.setCurrentTabByTag( " search_tab " ); break ; case R.id.radio_button4: this .mHost.setCurrentTabByTag( " more_tab " ); break ; } } } private void setupIntent(){ this .mHost = getTabHost(); TabHostlocalTabHost = this .mHost; localTabHost.addTab(buildTabSpec( " mblog_tab " ,R.string.main_home, R.drawable.icon_1_n, this .mMBlogIntent)); localTabHost.addTab(buildTabSpec( " message_tab " ,R.string.main_news, R.drawable.icon_2_n, this .mInfoIntent)); localTabHost.addTab(buildTabSpec( " userinfo_tab " ,R.string.main_my_info, R.drawable.icon_3_n, this .mUserInfoIntent)); localTabHost.addTab(buildTabSpec( " search_tab " ,R.string.menu_search, R.drawable.icon_4_n, this .mSearchIntent)); localTabHost.addTab(buildTabSpec( " more_tab " ,R.string.more, R.drawable.icon_5_n, this .mMoreIntent)); } private TabHost.TabSpecbuildTabSpec(Stringtag, int resLabel, int resIcon, final Intentcontent){ return this .mHost .newTabSpec(tag) .setIndicator(getString(resLabel), getResources().getDrawable(resIcon)) .setContent(content); } 代码说明 1. 由于TabWidget被隐藏,所以相关的事件也会无效,这里取巧用RadioGroup与RadioButton的特性来处理切换,然后监听事件调用setCurrentTabByTag来切换Activity。 2. 注意即使TabWidget被隐藏,也要为其设置indicator,否则会保持。 三、总结 在这之前如果要做这种效果我恐怕第一时间就会想到用ActivityGroup来做,主要是因为TabHost的TabWidget非常难看,用起来也不方便。其实从源码可以看出,TabActivity也是继承自ActivityGroup,这里结合了单选按钮和TabHost,各取其长,有时间可以专门写一个这样的自定义控件:) 本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/582149,如需转载请自行联系原作者

优秀的个人博客,低调大师

Storm概念学习系列之事务

事务 这里的事务是专门针对Topology提出来的,是为了解决元组在处理失败重新发送后的一系列问题的。简而言之,事务拓扑(transactional topology)就是指Storm以并行和顺序处理混合的方式处理元组,一方面是处理消息,将消息分为一批批,并行处理同一批内的消息以及批与批之间的消息;另一方面是提交消息,按严格的顺序提交,总之实现对消息精确的处理。 (1)事务拓扑的特点 事务性拓扑这一特性使消息在语义上确保能够以安全的方式重发消息,并保证它们只被处理一次。在不支持事务性拓扑的情况下,无法在保证准确性、可扩展性、容错性的前提下完成计算。 (2)事务拓扑的目的 事务拓扑的目的是满足对消息处理有着极其严格要求的场景,如实时计算某个用户的页面点击次数,要求结果完全精确。 (3)事务拓扑的原理 事务拓扑是Storm 0.7引入的特性,0.8之后版本已经被封装为Trident,提供了更加方便和直观的接口。 Storm的事务拓扑是完全基于底层的Spout/Bolt/Acker原语实现的,通过一层巧妙的封装得出一个优雅的实现,这也是Storm最大的魅力之一。 Storm使用ZooKeeper储存事务元数据,默认就是拓扑使用的ZooKeeper。可以通过修改transactional.zookeeper.servers和transactional.zookeeper.port配置参数键指定其他的ZooKeeper。 在使用事务性拓扑时,数据源要能够重发,有时候甚至要重复多次,因此需要确认数据源Spout是否具备这项能力。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5989741.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

学习OpenStack之 (0):基础知识

vi 方向键出现字母问题解决方法 执行命令 sudo apt-get remove vim-common 执行命令 sudo apt-get install vim 鼠标被virtualbox捕获无法释放 按右Control键可以释放鼠标 使服务在机器重启后自启动 sudo update-rc.d ssh defaults IP段表示方法 原来“/”后面的数字其实代表了掩码。正常情况下,掩码中的“1”是不可间断的,这样只要知道掩码中“1”的个数,就可以唯一地确定一个掩码。比如“/24”就表示掩码中有24个“1”,即“11111111 11111111 11111111 00000000”,用十进点分法表示就是“255.255.255.0”。 192.168.2.12与192.168.2.20 换成2进制 192.168.2.12二进制11000000.10101000.00000010.00001100 192.168.2.20二进制11000000.10101000.00000010.00010100 相与,有27位地址相同,所以可以写成192.168.2.12/27 主机位就是2的5次方,192168.2.12/27 有32个主机位 tar命令 tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个。下面的参数是根据需要在压缩或解压档案时可选的。 -z:有gzip属性的 -j:有bz2属性的 -Z:有compress属性的 -v:显示所有过程 -O:将文件解开到标准输出 下面的参数-f是必须的 -f: 使用档案名字,切记,这个参数是最后一个参数,后面只能接档案名。 # tar -cf all.tar *.jpg 这条命令是将所有.jpg的文件打成一个名为all.tar的包。-c是表示产生新的包,-f指定包的文件名。 # tar -rf all.tar *.gif 这条命令是将所有.gif的文件增加到all.tar的包里面去。-r是表示增加文件的意思。 # tar -uf all.tar logo.gif 这条命令是更新原来tar包all.tar中logo.gif文件,-u是表示更新文件的意思。 # tar -tf all.tar 这条命令是列出all.tar包中所有文件,-t是列出文件的意思 # tar -xf all.tar 这条命令是解出all.tar包中所有文件,-x是解开的意思 压缩 tar –cvf jpg.tar *.jpg //将目录里所有jpg文件打包成tar.jpg tar –czf jpg.tar.gz *.jpg //将目录里所有jpg文件打包成jpg.tar后,并且将其用gzip压缩,生成一个gzip压缩过的包,命名为jpg.tar.gz tar –cjf jpg.tar.bz2 *.jpg //将目录里所有jpg文件打包成jpg.tar后,并且将其用bzip2压缩,生成一个bzip2压缩过的包,命名为jpg.tar.bz2 tar –cZf jpg.tar.Z *.jpg //将目录里所有jpg文件打包成jpg.tar后,并且将其用compress压缩,生成一个umcompress压缩过的包,命名为jpg.tar.Z rar a jpg.rar *.jpg //rar格式的压缩,需要先下载rar for linux zip jpg.zip *.jpg //zip格式的压缩,需要先下载zip for linux 解压 tar –xvf file.tar //解压 tar包 tar -xzvf file.tar.gz //解压tar.gz tar -xjvf file.tar.bz2 //解压 tar.bz2 tar –xZvf file.tar.Z //解压tar.Z unrar e file.rar //解压rar unzip file.zip //解压zip 总结 1、*.tar 用 tar –xvf 解压 2、*.gz 用 gzip -d或者gunzip 解压 3、*.tar.gz和*.tgz 用 tar –xzf 解压 4、*.bz2 用 bzip2 -d或者用bunzip2 解压 5、*.tar.bz2用tar –xjf 解压 6、*.Z 用 uncompress 解压 7、*.tar.Z 用tar –xZf 解压 8、*.rar 用 unrar e解压 9、*.zip 用 unzip 解压 指定ubuntu的源,参考http://chenrongya.blog.163.com/blog/static/8747419620143185103297/ 配置静态ip地址 $sudo vi /etc/network/interfaces 原有内容只有如下两行: auto lo iface lo inet loopback 向末尾追加以下内容: auto eth0 iface eth0 inet static address 192.168.0.33 gateway 192.168.0.1 netmask 255.255.255.0 network 192.168.0.0 broadcast 192.168.0.255 然后保存退出; 修改机器名: 修改/etc/hostname 和 /etc/hosts,再重启机器 W: GPG error: http://ppa.launchpad.net lucid Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY A1715D88E1DF1F24 Google 之,在这篇文档里有提到解决方案: http://muzso.hu/2007/05/25/how-to-fix-no_pubkey-errors-in-apt-get-update-operations 具体的解决方法步骤是(注意下面的KEY 是根据每次报错而不同的,可能需要用实际报错的KEY替换命令中的KEY值): $ sudo gpg --keyserver keyserver.ubuntu.com --recv A1715D88E1DF1F24 $sudo gpg --export --armor A1715D88E1DF1F24 | sudo apt-key add - 注:上面第二个命令中的第二个sudo,因为sudo不能跨越Pipe,所以第二个命令也需要使用sudo 在ubuntu上安装ssh server 现象: ssh client无法连到ubuntu sammydeair:~ Sammy$ ssh -l s1 10.211.55.4 ssh: connect to host 10.211.55.4 port 22: Connection refused 查看: ubuntu上ssh local,同样错误,发现是openssh-server没安装 解决: $ sudo apt-getupdate //视网络情况会花比较长的时间 $ sudo apt-getupgrade $ sudo apt-get install openssh-server $sudo /etc/init.d/ssh start 在Mac上使用过要license的Parallels Desktop和免费的VirtualBox,比较结果如下: 1. VirtualBox对鼠标的捕获和控制更加友好,Parallels需要按键来释放鼠标,但是VirtualBox里面完全自动。 2. VirtualBox里面虚拟机的运行速度似乎更快,至少关机比Parallels快。 3.VirutalBox里面可以很方便地复制虚拟机,但是在Parallels Desktop里面不知道什么原因“克隆”菜单为灰色不可用。 4. VirtualBox里面多网卡配置更方便。 5. google查到的VirtualBox的文章比Parallels Desktop多得多 至少在我看来,免费的VirtualBox要比收费的Parallels要好些。接下里继续体会VirtualBox。 在Ubuntu里面配置静态IP使得可以连接外网 1. 关闭虚机,在VirtualBox里面,设置虚机的一个网卡为桥接模式 2. 查看主机的DNS server 3. 开虚机,运行ifconfig和route命令,查看该网卡自动获得的IP,netmask,gateway s1@compute1:~$ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0 10.0.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 4. 运行命令vi /etc/network/interfaces,设置静态IP,gateway,broadcast,netmask auto eth0 iface eth0 inet static address 192.168.1.15 netmask 255.255.255.0 gateway 192.168.1.1 5.配置DNS, 运行vi /etc/resolvconf/resolv.conf.d/tail, 从而在/etc/resolvconf/resolv.conf.d/目录下创建tail文件,写入 nameserver 192.168.1.1 然后重启,DNS生效 6.测试。ping www.sohu.com s1@compute1:~$ ping www.sohu.com PING fsh.a.sohu.com (114.80.130.88) 56(84) bytes of data. 64 bytes from www.sohu.com (114.80.130.88): icmp_seq=1 ttl=56 time=4.65 ms 64 bytes from www.sohu.com (114.80.130.88): icmp_seq=2 ttl=56 time=6.91 ms 64 bytes from www.sohu.com (114.80.130.88): icmp_seq=3 ttl=56 time=5.39 ms VirtualBox 虚拟机的几种网络连接方式 (1)NAT(网络地址转换模式):能从虚拟机访问外网,主机不能访问虚拟机。 网络地址转换( NAT )是最简单的方法从一个虚拟机访问外部网。通常,它并不要求在主机网络和客户机上做任何配置。基于这个原因,它是默认的网络模式 。 原理:客户机(即虚拟机)送出的网络帧被 VirtualBox 的 NAT 引擎收到,抽取 TCP/IP 数据,再通过主机的操作系统(即安装 VirtualBox 的操作系统)重新发送出去。送到在主机上的一个应用程序,或者到位于主机同一网络的另一台计算机上,它看起来好象是安装在主机上的程序 VirtualBox,通过一个属于主机的 IP 地址,把数据发送出去。VirtualBox 倾听到数据包裹的回复,通过客户机的私人网络重新包装和发送往客户机上。 效果:使用NAT模式,就是让虚拟系统借助NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网。但纯NAT模式下,宿主机不能访问虚拟机。 使用场景:如果你想利用安装一个新的虚拟系统,在虚拟系统中不用进行任何手工配置就能直接访问互联网,建议你采用NAT模式. (2)Bridged方式:虚拟机和主机拥有同样的网络功能,能互相访问。 用这种方式,虚拟系统的IP可设置成和本机系统在同一网段,虚拟系统相当于网络内的一台独立的机器,和本机一起插在一个Hub上,网络内其他机器可访问虚拟系统,虚拟系统也可访问网络内其他机器,当然和本机系统的双向访问也不成问题。 (3)内部网络:虚拟机之间可以互相访问,虚拟机不能访问外网,主机和虚机之间不能访问。 内网模式,顾名思义就是内部网络模式: 虚拟机与外网完全断开,只实现虚拟机于虚拟机之间的内部网络模式。 (1)虚拟机与主机的关系:不能相互访问,彼此不属于同一个网络,无法相互访问。 (2)虚拟机与网络中其他主机的关系:不能相互访问,理由同上。 (3)虚拟机与虚拟机的关系:可以相互访问,前提是在设置网络时,两台虚拟机设置同一网络名称。 (4)host-only方式 (主机模式):虚拟机不能访问外网,主机可以访问虚拟机。 Virtualbox在宿主机中模拟出一张专供虚拟机使用的网卡,所有虚拟机都是连接到该网卡上的,虚拟机可以通过该网卡IP访问宿主机,同时Virtualbox提供一个DHCP服务,虚拟机可以获得一个内部网IP,宿主机可以通过该IP访问虚拟机。如果单纯使用Host-only模式,则虚拟机不能连接外部公共网络。 (5)通用驱动 作用和效果:运行用于选择网卡驱动。该驱动是virtualbox内部自带的,或者是通过extensionpack添加进来的。此模式实际上很少用到 一般来说,Bridged方式最方便好用。但如果本机系统是win2000而网线没插(或根本没有网卡),网络非常可能不可用(大部分用PCI网卡的机器都如此),此时就只能用NAT方式或host-only,之前所说的那两块虚拟网卡就是适应这两种网络准备的。 使用NAT和host-only混合模式,使得虚拟机既能访问外网,主机也能访问虚机 在虚机关机状态下配置网络,网卡1使用NAT模式,网卡2使用host-only模式。 1. 检查宿主机上host-only adapter的网络设置 当添加多个网卡时,比如 eth0 是 NAT 模式用于虚机访问外网,eth1 是 host-only 模式用于宿主机访问虚机,eth2 是internal 模式用于虚机之间互访,需要注意 default gateway。设置不对的话,虚机是不能访问外网的。当专有 eth0 时候,default gw 是它自己,当增加 eth1 和 eth2 后,default gw 就跑到了 eth2上,而 eth2 是不能用于外网访问的。因此,此时需要手工修改 default gw,修改为: route del default gw 192.168.1.1 route add default gw 10.0.2.2 eth0 root@ceph1:~# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 10.0.2.2 0.0.0.0 UG 0 0 0 eth0 10.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth2 192.168.56.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 root@ceph1:~# ping www.sohu.com PING fhk.a.sohu.com (175.100.207.201) 56(84) bytes of data. 64 bytes from 175.100.207.201: icmp_seq=1 ttl=41 time=133 ms 64 bytes from 175.100.207.201: icmp_seq=2 ttl=41 time=69.9 ms 64 bytes from 175.100.207.201: icmp_seq=3 ttl=41 time=69.4 ms 64 bytes from 175.100.207.201: icmp_seq=4 ttl=41 time=68.5 ms 64 bytes from 175.100.207.201: icmp_seq=5 ttl=41 time=71.9 ms 注意 eth0 的 default gw 是 10.0.2.2 而不是 10.0.2.1. 2. 开启虚拟机配置网络 sudo vi /etc/network/interfaces sudo /etc/init.d/networking restart 可运行ifconfig查看ip 3. 可以从主机ping和ssh虚拟机了 本文转自SammyLiu博客园博客,原文链接:http://www.cnblogs.com/sammyliu/p/4139246.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

6、raid、lvm、while、until 学习笔记

Raid: Level仅用于标识磁盘组合方式的不同 raid0, raid1, raid5, raid10, raid50, jbod raid0:至少需要两块磁盘,不允许任何盘出错,没有容错能力,读写性能都提升,硬盘利用率100% raid1:至少需要两块磁盘,允许一块盘出错,镜像,硬件容错能力,读性能提升,写性能下降,硬盘利用率50% raid5:至少需要三块磁盘,允许一块盘出错,校验盘分布在各盘上,读写性能都提升,硬盘利用率(n-1)/n% raid10: 至少需要四块磁盘,允许不同组内各坏一块盘,读写性能都提升,硬盘利用率50%(先做raid1,再做raid0) jbod:在逻辑上把几个物理磁盘一个接一个串联到一起,从而提供一个大的逻辑磁盘。jbod上的数据简单的从第一个磁盘开始存储, 当第一个磁盘的存储空间用完后, 再依次从后面的磁盘开始存储数据。 mdadm: 模式化的工具 -A:装配模式 -C:创建模式 -F:监控模式 管理模式 -f模拟硬盘损坏 -r移除硬盘 -a添加硬盘 -C:创建模式 -a yes自动为创建的raid设备创建设备文件; -l 级别指定Raid级别 -n #用于创建RAID设备的设备个数; -x #用于创建RAID热备磁盘的个数; -c #指定分块大小,默认为512,单位为KB -D: 显示阵列的详细信息 --detail: -S /path/to/raid_device停止指定的RAID设备 -A /path/to/raid_device DEVICES使用指定的设备装配并启动指定的RAID设备 watch -n # 'COMMAND'每隔#执行一次指定的命令;单位为秒钟 wathc -n 1 'cat /proc/mdstat'每秒钟查看一次RAID的同步状态 练习:创建一个大小为4G的RAID5; 给其添加一个空闲盘,模拟损坏等; 停止raid; mdadm -C /dev/md5 -a yes -l 5 -n 3 -x 1 /dev/sdb{1,2,3,4} mdadm -D /dev/md5 cat /proc/mdstat mke2fs -t ext4 /dev/md5 mount /dev/md5 /mnt/ ls /mnt mdadm -f /dev/md5 /dev/sdb1 mdadm -r /dev/md5 /dev/sdb1 mdadm -a /dev/md5 /dev/sdb1 umount /mnt mdadm -S /dev/md5 mdadm -A /dev/md5 /dev/sdb{1,2,3,4} bash知识点:while循环和until循环 for varName in 列表; do 循环体 done 条件测试: 执行命令: 命令成功,条件测试成功;否则为失败; 根据$?, 状态返回值; 0表示命令执行成功,非0表示命令执行失败; 表达式: [ expression ] ` expression ` test expression while 条件测试; do 循环体 done while循环:条件测试成功,则循环;失败,则退出; 如何让while循环退出:在循环体中改变测试条件中用于控制循环次数的变量的值; 练习:求100以内所有正整数的和; declare -i sum=0 declare -i i=1 while [ $i -le 100 ]; do let sum+=$i let i++ done echo $sum 练习:通过键盘提示用户输入字符,将用户输入的小写字母转换为大写,转换一次之后,再次提醒,再输再转换;但输入quit表示退出; #!/bin/bash read -p "Enter a word: " word while [[ "$word" != "quit" ]]; do echo $word | tr 'a-z' 'A-Z' read -p "Enter a word again: " word done 练习:显示如下菜单给用户 cpu) print cpu information; mem) print memory information; disk) print disk infomation; quit) quit Enter your option: 根据用户的选择输出相应信息; 每次执行后,不退出,而由用户再次指定新的选项; #!/bin/bash # cat << EOF cpu) print cpu information; mem) print memory information; disk) print disk infomation; quit) quit EOF read -p "Enter your option: " option option=`echo $option | tr 'A-Z' 'a-z'` while [[ "$option" != "quit" ]]; do if [[ "$option" == "cpu" ]]; then cat /proc/cpuinfo elif [[ "$option" == "mem" ]]; then free -m elif [[ "$option" == "disk" ]]; then df -h else echo "Wrong option..." fi read -p "Enter your option again: " option option=`echo $option | tr 'A-Z' 'a-z'` done 练习:提示用户输入一个用户名,如果存在:显示用户UID和SHELL信息;否则,则显示无此用户; 显示完成之后,提示用户再次输入;如果是quit则退出; #!/bin/bash # read -p "Enter a user name: " userName while [[ "$userName" != "quit" ]]; do if [ -z "$userName" ]; then echo "User name null." elif id $userName &> /dev/null; then grep "^$userName\>" /etc/passwd | cut -d: -f3,7 else echo "No such user." fi read -p "Enter a user name again(quit to exit): " userName done 练习:提示用户输入一个用户名,判断用户是否登录了当前系统; 如果没有登录,则停止5秒钟之后,再次判断;直到用户登录系统,显示“用户来了”,而后退出; #!/bin/bash # read -p "Enter a user name: " userName while ! id $userName &> /dev/null; do read -p "Enter a user name again: " userName done while ! who | grep "^$userName" &> /dev/null; do echo "$userName is not here." sleep 5 done echo "$userName is on." #!/bin/bash # read -p "Enter a user name: " userName until [ -n "$userName" ] && id $userName &> /dev/null; do read -p "Enter a user name again: " userName done until who | grep "^$userName" &> /dev/null; do echo "$userName is not here." sleep 5 done echo "$userName is on." bash编程之until循环: until 测试条件; do 循环体 done 条件不满足,则循环;否则,退出; 练习:用until循环,求100以内所有正整数之和; #!/bin/bash declare -i sum=0 declare -i i=1 until [ $i -gt 100 ]; do let sum+=$i let i++ done echo $sum bash编程之组合测试条件深入探讨: 逻辑与:多个条件同时满足 [ CONDITION1 ] && [ CONDITION2 ] [ CONDITION1 -a CONDITION2 ] [[ CONDITION1 && CONDITION2 ]] 注意:前两个使用单或双中括号都可,但,&&不允许用于单中括号中,所以第三种只能用于双中括号中; 逻辑或:多个条件中有一个满足即为真; [ CONDITION1 ] || [ CONDITION2 ] [ CONDITION1 -o CONDITION2 ] [[ CONDITION1 || CONDITION2 ]] 注意:||不允许用于单中括号中; 德 摩根 定律 !(条件1 或 条件2) = !条件1 并且 !条件2 !(条件1 并且 条件2) = !条件1 或 !条件2 使用while循环一次读取文件的一行,直到文件尾部: while read line; do 循环体 done < /path/to/somefile 练习:取出当前系统上,默认shell为bash的用户 #!/bin/bash # while read line; do [[ `echo $line | cut -d: -f7` == "/bin/bash" ]] && echo $line | cut -d: -f1 done < /etc/passwd 练习:显示所有其ID号为偶数的用户; #!/bin/bash # while read line; do userID=`echo $line | cut -d: -f3` if [ $[$userID%2] -eq 0 ]; then echo -n "$userID: " echo $line | cut -d: -f1 fi done < /etc/passwd 练习:显示/etc/rc.d/rc.sysinit文件中,其总字符个数大于30的行; #!/bin/bash # while read line; do charCounts=`echo $line | wc -c` if [ $charCounts -gt 30 ]; then echo -n "$charCounts: " echo $line fi done < /etc/rc.d/rc.sysinit 练习:显示所有其UID和GID均为偶数的用户; #!/bin/bash # while read line; do userID=`echo $line | cut -d: -f3` groupID=`echo $line | cut -d: -f4` if [ $[$userID%2] -eq 0 ] && [ $[$groupID%2] -eq 0 ]; then echo -n "$userID, $groupID: " echo $line | cut -d: -f1 fi done < /etc/passwd 练习:显示/etc/rc.d/rc.sysinit文件中,其总字符个数大于30且非以“#”开头的行; #!/bin/bash # while read line; do charCounts=`echo $line | wc -c` if [ $charCounts -gt 30 ] && [[ "$line" =~ ^[^#] ]] ; then echo -n "$charCounts: " echo $line fi done < /etc/rc.d/rc.sysinit 练习:写一个脚本,完成如下任务 1、提示用户输入一个磁盘设备文件路径; 如果用户给定的路径文件不存在或不是一个块设备文件,则提示用户重新输入,直到输入正确为止,或者输入quit以9为退出码结束脚本; 2、提示用户“下面的操作会清空磁盘中的数据,并提问是否继续” 如果用户给出字符y或单词yes,则继续,否则,则提供以8为退出码结束脚本; 3、将用户指定的磁盘上的分区清空,而后创建两个主分,大小分别为100M和512M; 4、格式化此两个分区; 5、将第一个分区挂载至/mnt/boot目录;第二个分区挂载至/mnt/sysroot目录; #!/bin/bash echo -n -e "\033[31mEnter a disk path: \033[0m" read diskPath while [ $diskPath != "quit" ];do if ! [ -b $diskPath ];then echo -n -e "\033[31mEnter a disk path again: \033[0m" read diskPath else echo -n -e "\033[31mFlow action clear disk data y | n:\033[0m" read option if [[ $option == "n" ]];then exit 8 elif [[ $option == "y" ]];then dd if=/dev/zero of=$diskPath bs=512 count=1 &> /dev/null echo "n p 1 +100M n p 2 +512M w" | fdisk $diskPath &> /dev/null if mount | grep /mnt/boot &> /dev/null;then umount /mnt/boot fi if mount | grep /mnt/sysroot &> /dev/null;then umount /mnt/sysroot fi mke2fs -t ext4 ${diskPath}1 &> /dev/null mke2fs -t ext4 ${diskPath}2 &> /dev/null if ! [ -e /mnt/boot ];then mkdir /mnt/boot fi if ! [ -e /mnt/sysroot ];then mkdir /mnt/sysroot fi mount ${diskPath}1 /mnt/boot mount ${diskPath}2 /mnt/sysroot echo -e "\033[32mFinished !\033[0m" exit 0 else echo "Unkown option!" fi fi done exit 9 LVM: Logical Volume Manager 设备文件:/dev/卷组名/逻辑卷名 /dev/mapper/卷组名-逻辑卷名 物理卷管理命令:pv pvcreate创建 pvremove移除 pvscan, pvs, pvdisplay查看 pvmove 迁移 卷组的管理命令:vg vgcreate创建 vgremove移除 vgscan, vgs, vgdisplay查看 vgextend, vgreduce扩展、缩减 vgcreate, -s: PE大小, 默认4M #vgcreate -s 4M vg_name 逻辑卷的管理命令:lv lvcreate创建 lvremove移除 lvscan, lvdisplay, lvs 查看 lvextend, lvreduce 扩展、缩减 lvcreate -L :空间大小 -n : lv名称 # lvcreate -L Size -n Name vg_name 扩展卷组: 1、准备要添加的物理卷; 2、扩展卷组: 添加物理卷至卷组中; # vgextend vg_name /path/to/pv_device 缩减卷组: 1、确定要移除的物理卷的总空间大小,要小于VG当前的可用空间大小; 2、将要移除的物理卷上的所有PE移动至其它PV # pvmove /path/to/pv_device 3、缩减vg # vgreduce vg_name /path/to/pv_device 逻辑卷扩展的步骤: 1、先确定扩展的大小;并确保所属的卷组有足够的剩余空间; 2、扩展物理边界: # lvextend -L [+]Size /path/to/lv_device 3、扩展逻辑边界: # resize2fs /path/to/lv_device 缩减逻辑卷的步骤: 1、卸载卷,并执行强制检测 # e2fsck -f /path/to/lv_device 2、缩减逻辑边界: # resize2fs /path/to/lv_device SIZE 3、缩减物理边界: # lvreduce -L [-]Size /path/to/lv_device 快照卷:逻辑卷的一种,通常为只读(通常用于数据备份) # lvcreate -s -L Size -n Name -p r /path/to/original_lv_device 练习: 1、创建一个由两个物理卷组成大小为20G的卷组myvg,要求PE大小16M;而后新建 大小为7G逻辑卷mylv1,要求其文件系统为ext4,块大小为2048,且开机能自动挂载至/users; 2、新建用户openstack,其家目录为/users/openstack,而后切换至openstack用户,复制一些文件至其家目录中; 3、缩减mylv1至5G大小;而后切换至openstack用户,确保其数据没有丢失; 4、对mylv1创建快照卷snap-mylv1,并通过其备份数据至/tmp/user.tar.bz2; pvcreate /dev/sdb{1,2} vgcreate -s 16M myvg /dev/sdb{1,2} lvcreate -L 7G -n mylv1 myvg mke2fs -t ext4 -b 2048 /dev/myvg/mylv1 mkdir /users blkid /dev/myvg/mylv1 echo UUID=c457275b-5aa6-42d7-b770-5d40f44a17f4 /users ext4 defaults 0 0 >> /etc/fstab mount -a useradd -d /users/openstack openstack su - openstack cp /etc/fstab ./ umount /users e2fsck -f /dev/myvg/mylv1 resize2fs /dev/myvg/mylv1 5G lvreduce -L 5G /dev/myvg/mylv1 mount -a su - openstack cat fstab lvcreate -s -p r -L 1M -n snap-mylv1 /dev/myvg/mylv1 mount /dev/myvg/snap-mylv1 /mnt tar jcf /tmp/user.tar.bz2 /mnt umount /mnt lvremove /dev/myvg/snap-mylv1 本文转自开源殿堂 51CTO博客,原文链接:http://blog.51cto.com/kaiyuandiantang/1942533,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android学习笔记(一) 使用选择部件

ListActivity的使用 extend Activity package com.example.listtest; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { TextView selection; ListView list; String[] items={"t0","t1","t2","t3","t4"}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,items)); selection=(TextView)findViewById(R.id.textView1); list=(ListView)findViewById(R.id.listView1); //绑定数据 list.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,items)); list.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView< ?> arg0, View arg1, int position,long id){ selection.setText(items[position]); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } } extend ListActivity spinner的使用 package com.example.test2; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.TextView; public class MainActivity extends Activity { TextView text; Spinner sp; private String[] items={"t0","t1","t2","t3","t4"}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text=(TextView)findViewById(R.id.textView1); sp=(Spinner)findViewById(R.id.spinner1); ArrayAdapter<String> aa=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,items); aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); sp.setAdapter(aa); sp.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView< ?> parent, View v, int position, long id){ text.setText(items[position]); } public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub text.setText("Nothing selected!"); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } } GridView的使用 package com.example.test3; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.GridView; import android.widget.TextView; public class MainActivity extends Activity { TextView selection; GridView grid; String[] items={"t0","t1","t2","t3","t4","t5","t6","7t","t8","t9","t10","t11","t12","t13","t14","t15","t16","t17","t18","t19",}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); selection=(TextView)findViewById(R.id.textView1); grid=(GridView)findViewById(R.id.gridView1); grid.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,items)); grid.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub selection.setText(items[arg2]); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } } AutoCompleteTextView package com.example.test5; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.MenuItem; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.TextView; import android.support.v4.app.NavUtils; import android.text.Editable; import android.text.TextWatcher; public class MainActivity extends Activity implements TextWatcher{ TextView selection; AutoCompleteTextView edit; String[] items={"teacher","core","popular","wherese","compromise","teeth"}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); selection=(TextView)findViewById(R.id.textView1); edit=(AutoCompleteTextView)findViewById(R.id.autoCompleteTextView1); edit.addTextChangedListener(this); edit.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,items)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } public void afterTextChanged(Editable s) { // TODO Auto-generated method stub } public void beforeTextChanged(CharSequence s, int start, int count, int after) { // TODO Auto-generated method stub } public void onTextChanged(CharSequence s, int start, int before, int count) { // TODO Auto-generated method stub selection.setText(edit.getText()); } } 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/archive/2013/05/09/3068353.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

学习iOS【3】数组、词典和集合

一、数组 1.不可变数组NSArray arrayWithObjects:使用一组对象作为元素创建不可变数组,注意数组的最后一个值需要指定为nil,用来表示参数的结束,但是nil并不会存储在数组中。 objectAtIndex:获取指定索引位置的数组元素。 @[elm1,elm2….elmn]:另外一种创建数组的简便方式,不需要以nil作为结尾元素; array[index]:另外一种获取指定索引位置元素的方式。 count:数组中元素个数。 int main(int argc, const char * argv[]) { @autoreleasepool { /*不可变数组*/ //创建不可变数组 方式一 NSArray *arr=[NSArray arrayWithObjects:@"周一",@"周二",@"周三",@"周四",@"周五",@"周六",@"周日",nil]; for(int i=0;i<[arr count];i++){ NSLog(@"%@",[arr objectAtIndex:i]); } //创建不可变数组 方式二 NSArray *arr1=@[@"周一",@"周二",@"周三",@"周四",@"周五",@"周六",@"周日"]; for(int i=0;i<[arr1 count];i++){ NSLog(@"%@",arr1[i]); } } } 2.可变数组NSMutableArray NSMutableArray array方法创建空的可变数组,数组元素个数未定,可以随着需要增长; addObject:向可变数组结尾添加元素; insertObject:obj atIndex:i :将对象obj插入数组的第i个元素。 removeObjectAtIndex:i 删除数组中第i个元素。 replaceObjectAtIndex:i withObject:obj 将数组中序号为i的对象用obj替换。 使用NSLog格式化%@可以显示整个数组,它实际上会调用每个元素的description方法。 int main(int argc, const char * argv[]) { @autoreleasepool { /*可变数组*/ NSMutableArray *marr=[NSMutableArray array]; for (int i=0; i<3; i++) { marr[i]=@(i+1); } [marr addObject:@(4)]; for (int i=0; i<[marr count]; i++) { NSLog(@"%@",marr[i]); } NSLog(@"%@",marr); } } 二、词典对象(dictionary) 词典也有两种类型:不可变词典NSDictionary和可变词典NSMutableDictionary。 1.不可变词典NSDictionary NSDictionary dictionaryWithObjectsAndKeys:创建不可变词典,参数是值-键对组合(注意顺序),以nil结尾。 allKeys:返回一个数组包含词典中的所有键; count:返回词典中的记录数; objectForKey:返回key的值对象。 int main(int argc, const char * argv[]) { @autoreleasepool { /*不可变词典*/ NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys:@"学生",@"1",@"教师",@"2", nil]; for (NSString *key in dic) { NSLog(@"key:%@ value:%@",key,[dic objectForKey:key]); } } } 2.可变词典NSMutableDictionary NSMutableDictionary dictionary:创建一个可变词典; setObject:forKey:把键值对添加到可变词典中; removeAllObjects:删除词典中所有的记录; removeObjectForKey:删除词典中的指定键key对应的记录; int main(int argc, const char * argv[]) { @autoreleasepool { /*可变词典*/ //创建可变词典对象 NSMutableDictionary *mdic=[NSMutableDictionary dictionary]; //添加键值对 [mdic setObject:@"学生" forKey:@"1"]; mdic[@"2"]=@"教师"; //显示键值对 NSLog(@"key:1 value is:%@",[mdic objectForKey:@"1"]);//key:1 value is:学生 NSLog(@"key:2 value is:%@",mdic[@"2"]);//key:2 value is:教师 //删除 [mdic removeObjectForKey:@"1"]; NSLog(@"mdic count:%lu",[mdic count]);//mdic count:1 [mdic removeAllObjects]; NSLog(@"mdic count:%lu",[mdic count]);//mdic count:0 } } 三、集合对象(set) set是一组单值对象集合。 1.NSSet 不可变词典 setWithObjects:以一个nil为结尾的对象数组创建一个集合。 containObject:检测某个对象是否包含在集合中。 count:集合成员个数。 2.NSMutableSet 可变词典 addObject:向集合中添加对象; removeObject:从集合中删除对象; removeAllObjects:删除集合中所有对象; unionSet:求两个集合的并集; intersectSet:求两个集合的交集 3.实例 首先我们自定义分类为NSSet添加自定义方法print。 NSSet+Printing.h #import <Foundation/Foundation.h> @interface NSSet (Printing) -(void)print; @end NSSet+Printing.m #import "NSSet+Printing.h" @implementation NSSet (Printing) -(void)print{ NSLog(@"------"); for(NSNumber *item in self){ NSLog(@"%li",(long)[item integerValue]); } } @end main.m #import <Foundation/Foundation.h> #import "NSSet+Printing.h" int main(int argc, const char * argv[]) { @autoreleasepool { //创建不可变集合 NSSet *set=[NSSet setWithObjects:@"1",@"3",@"5", @"7",nil]; //创建可变集合 NSMutableSet *mset=[NSMutableSet setWithObjects:@"1",@"2",@"3",@"4",@"5", nil]; //输出 [set print]; [mset print]; //成员测试 if([set containsObject:@"7"]==YES){ NSLog(@"set contain 7"); }else{ NSLog(@"set does not contain 7"); } //添加对象 [mset addObject:@"6"]; [mset print]; //移除对象 [mset removeObject:@"6"]; //求并集 [mset unionSet:set]; [mset print]; [mset print]; //求交集 [mset intersectSet:set]; [mset print]; } } 本文转自 陈敬(Cathy) 博客园博客,原文链接: http://www.cnblogs.com/janes/p/5467317.html ,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册