
暂无个人介绍
from:http://blogs.msdn.com/b/slavao/archive/2005/02/11/371063.aspx SQLOS's memory manager consists of several components such as memory nodes, memory clerks, memory caches, and memory objects. Fig 1. depicts memory manager components and their relationship: ---------------- | Memory Object | ---------------- | | V ---------------- | Page Allocator | ---------------- / \ / \ \/ \/ --------------- --------------- | Memory Clerk | | Caches | --------------- --------------- \ / \/ \/ ---------------- | Memory Node | ---------------- Fig. 1 Memory Node A memory node is not exposed to memory manager clients. It is internal SQLOS's object. The major goal for a memory node is to provide locality of allocation. It consists of several memory allocators. There are three major types of allocators. The first type is a set of page allocators. The second type is virtual allocator leveraging Windows VirtualAlloc APIs. The third type is a shared memory allocator which is fully based on Window's file mapping APIs. The page allocators are the most commonly used allocators in SQLOS memory manager. The reason they are called page allocators is because they allocate memory in multiple of SQLOS's page. A size of a page is 8k, the same as a size of database page in SQL Server. As you will learn further this is not coincidence. There are four different types of page allocators. Single page allocator, multi page allocator, large page allocator and reserved page allocator. Single page allocator can only provide one page at the time. Multiple page allocator, as you might guess, provides a set of pages at the time. Large page allocator could be used to allocate large pages. SQLOS and SQL Server use large pages to minimize TLB misses when accessing hot data structures. Currently large pages are supported only on IA64 or x64 hardware with at least 8GB of RAM. A size of a large page on IA64 is 16MB. The last type of page allocators reserved could be used to allocate special set of pages reserved for emergency, i.e. when SQLOS is low on memory. Fig2. shows the memory node and its allocators. ---------------------- ---------------- --------------------------- | Large Page Allocator |<--------| Memory Node |--------->| Reserved Page Allocator | --------------------- / ---------------- \ --------------------------- / | \ / | \ / | \ / | \ \/ \/ \/ -------------------- ---------------------- ---------------------- | VM & SM Allocator | | Single Page Allocator | | Multi Page Allocator | -------------------- ---------------------- ---------------------- Fig. 2 At this point SQL Server doesn't have a dmv, dynamic management view, that would dump a set of all memory nodes and information about their allocators. Dbcc memorystatus, discussed further, comes pretty close but it dumps information about cpu nodes not about memory nodes. You might remember that CPU nodes are proper subset of memory nodes. It means that information presented by dbcc memorystatus is sufficient to understand memory distribution on the system. Memory Clerks Memory nodes are hidden from memory manager users. If a client of memory manager needs to allocate memory it first creates a memory clerk. There are four types of memory clerks such as generic, cache store, user store and object store. The latter three a bit convoluted. Along with memory clerk functionality they provide data caching. One can think of a memory clerk as a bag of statistics. It supports the same type of allocators as memory nodes as well as it enables large memory consumers to hook into memory brokerage infrastructure. (I will describe infrastructure in one of the next posts). There are several global memory clerks provided by SQLOS. SQLOS's middle and large memory consumers are encouraged to use their own clerk so that one could understand memory consumption by a component. Memory clerks infrastructure enables us to track and control amount of memory consumed by a memory component. Each CPU node has a list of memory clerks that we can safely walk during runtime. SQL Server implements sys.dm_os_memory_clerks dmv to dump clerk information. In addition combined clerk information could be derived from dbcc memory status. Memory objects SQLOS's memory object is a heap. A memory object requires a memory clerk to allocate its memory. We support three types of memory objects. A variable memory objects is a regular heap. An incremental memory object is a mark/shrink heap. This allocation policy is very handy during compilations and execution processes. Usually both of the processes happen in two phases. First phase is to grow memory usage and the second is to shrink memory usage. If the process is isolated we don't have to call any of destructors when freeing memory. It significantly improves performance. The last type of memory object is fixed size. As you can guess components can use such policy when they need to allocate objects of a given size. A payload for a given memory object is 8kb. It is exactly the same as a SQLOS's page size. It also means that a memory object could be created from memory clerk leveraging single page allocator. (This is yet another very important point! Keep this in mind until I will cover SQL Server's Buffer Pool) SQL Server exposes a dmv to dump all memory objects in its process: sys.dm_os_memory_objects. If you notice both memory clerks and memory objects dmvs expose page allocator column. Also I depicted page allocator in Fig.1. Under the hood memory object uses memory clerks's page allocator interface to allocate pages. This is useful to know when you want to join memory clerk and memory object dmvs. So far I have described how SQLOS's memory manager structured inside. Now it is time to start talking how all this fits into SQL Server. Buffer Pool Now we got to the point where the life becomes very interesting. In this part all the pieces that I covered so far including memory management should start fall in their places. Remember SQL Server has two memory settings that you can control using sp_conifigure. They are max and min server memory. I am not sure if you know but these two setting really control the size of the buffer pool. They do not control overall amount of physical memory consumed by SQL Server. In reality we can't control amount of memory consumed by SQL Server because there could be external components loaded into server's process. When SQL Server starts, during initialization, Buffer Pool first decides how much of VAS it needs to reserve for its usage. It bases its decision on the amount of physical memory, RAM, present on the box. If amount of physical memory is equal or larger than amount of VAS it can use, remember that VAS is limited resource especially on x86, it will leave 256MB of VAS for external components plus a number of threads SQL Server is configured to use multiplied by 512KB. You might remember that 512KB is SQL Server's thread stack size. In default configuration with physical memory larger than 2GB, Buffer Pool will leave 256MB+256*512KB = 384MB of VAS space. Some people name this region as MemToLeave but in reality it is in correct. SQL Server might end up using this part of VAS itself and I will show you how it could happen latter on. You might also remember -g parameter that some people recommend to use when SQL Server starts outputting "Can't Reserve Virtual Address Space" errors. First 256MB is exactly what -g parameter controls. If you specify -g 512MB, amount of VAS that BP won't use is 512MB+256*512KB = 640MB. There is no point in specifying -g 256MB. This input parameter is the same as default value. Once BP decides amount of VAS it will use. It reserves all of it right a way. To observe such behavior you might want to monitor SQL Server's virtual bytes from perfmon or you could use vasummary view I talked about in my previous posts. In normal case Buffer Pool can't get this much memory in one chunk so if you take a closer look at SQL Server's VAS you will see several large regions reserved. This behavior is very different from many other servers that you might have seen. Some people report it as a VAS leak in SQL Server. In reality this behavior is by design. Buffer Pool commits pages on demand. Depending on internal memory requirements and external memory state, it calculates its target, amount of memory it thinks it should commit before it can get into memory pressure. To keep system out of paging target is constantly recalculated. Target memory can't exceed max memory that represents max server memory settings. Even if you set min server memory equal to max server memory Buffer Pool will only commit its memory on demand. You can observe this behavior by monitoring corresponding profiler event. The size of SQL Server database page is 8KB. Buffer Pool is a cache of data pages. Consequently Buffer Pool operates on pages of 8KB in size. It commits and decommits memory blocks of 8KB granularity only. If external components decide to borrow memory out of Buffer Pool they can only get blocks of 8KB in size. These blocks are not continues in memeory. Interesting, right? It means that Buffer Pool can be used as underneath memory manager forSQL Server components as long as they allocate buffers of 8KB. (Sometimes pages allocated from BP are referred as stolen) Here is where SQLOS and Buffer Pool meet. See Fig.3 ----------------- | Memory Node | ----------------- | | V ------------------------ | Single Page Allocator | ------------------------ | | V ----------------- | Buffer Pool | ----------------- Fig. 3 SQLOS' memory manager can be dynamically configured to use specific single page allocator. This is exactly what SQL Server does during a startup it configures Buffer Pool to be SQLOS's single page allocator. From that point on all dynamic single page allocations are provided by Buffer Pool. For example remember that memory object's payload is 8KB. When a component creates a memory object the allocation is served by SQLOS's single page allocator which is BP. When describing the memory manager I mentioned that every large component has its own memory clerk. It means that Buffer Pool has its own memory clerk as well. How is it possible, BP leverages SQLOS memory clerk but SQLOS' memory manager relies on BP? This is common chicken and egg problem that you often can observe in operating systems. The key here is that Buffer Pool never uses any type of page allocator from SQLOS. It only leverages Virtual and AWE SQLOS's interfaces. ----------------- | Buffer Pool | ----------------- | | V -------------------------- | Memory Clerk (VM/AWE) | -------------------------- | | V ----------------- | Memory Node | ----------------- Fig. 4 All SQL Server's components optimized for 8KB allocations so that they can allocate memory through SQLOS's single page allocator and consequently through Buffer Pool. However there are cases when a component requires large buffers. If it happens allocation will be either satisfied by memory node's multi page allocator or by virtual allocator. As you might guess that memory will be allocated outside of Buffer Pool. This is exactly why I don’t like term MemToLeave, SQL Server does allocate memory out of that area! Buffer Pool and AWE mechanism When describing SQLOS memory manager and Buffer Pool, the discussion would be incomplete without describtion of how AWE fits in all of this. It is really important to understand how Buffer Pool allocates its memory when SQL Server configured to use AWE mechanisms. First, please remember, BP leverages SQLOS's memory clerk interfaces to allocate both VAS and physical pages through AWE. Second, there are several differences that you need to keep in mind. First BP reserves VAS in 4MB chunks instead of "single" large region. This enables SQL Server to release VAS when process is under VAS pressure. (We didn't have all bits and pieces to do this when server is not configured to use AWE mechanisms). Then it allocates all of its memory using AWE mechanism on demand. This is very big difference between SQL2000 and Yukon. In SQL Server 2000 BP would allocate all of its memory when using AWE mechanism right a way. Buffer Pool is a preferred memory allocator for the whole server. In AWE mode it allocates its memory leveraging AWE mechanism. It means that all allocations allocated through SQLOS's single page allocator will come from pages allocated through AWE. This is what many people really missing. Let me make the point again: When Server is configured for AWE mode, most of it allocations are allocated through AWE mechanism. This is exactly the reason why you won't see private bytes and memory usage growing for SQL Server in this mode. Since data pages are use relative addressing, i.e. self contained, Buffer Pool can map and unmap them into and out of process's VAS. Other components could have done the same if they were not relying on the actual allocation address. Unfortunately there are no components right now other than BP that can take advantage of AWE mechanism. Future posts I haven't completed discussion about SQLOS memory management yet . There is still much to talk about. In my next posts I will cover SQLOS caches and handling of memory pressure. It is also really important to look at dbcc memory status and related dmvs. 本文转自 Fanr_Zh 博客园博客,原文链接:http://www.cnblogs.com/Amaranthus/archive/2011/12/07/2279414.html,如需转载请自行联系原作者
虽然网上有很多python开发环境搭建的文章,不过重复造轮子还是要的,记录一下过程,方便自己以后配置,也方便正在学习中的同事配置他们的环境。 1.准备好安装包 1)上python官网下载python运行环境(https://www.python.org/downloads/),目前比较稳定的是python-3.5.2 2)上pycharm官网下载最新版的IDE(http://www.jetbrains.com/pycharm/download/#section=windows),官网提供了mac、windows和linux三种版本,我下的是pycharm-community-2016.2.3.exe 3)上postgresql官司网下载最新版的数据库(https://www.postgresql.org/download/windows/ 打开页面后,点击Download the installer进入下载页,然后选择版本和操作系统,再点击下载),我下的是postgresql-9.6.5-1-windows-x64.exe 2.安装软件 1)安装python运行环境 双击python-3.5.2.exe 一般采用自定义安装比较好,不然自动安装会把环境安装到个人目录里,有时要找起来很麻烦 另外第二个红框前面的勾记录打上,不然需要手动在windows环境变量的路径中添加python安装路径 这里将安装路径手动修改一下,可以安装到C盘也可以安装到D盘 完成安装 然后我们打开CMD,在里面输入python,就可以直接进入进行编码了 我们可以输入print('hello world!')来测试一下python运行,如下图 如果输入python出现下面错误 那就得手动将python安装路径添加到系统环境变量中 打开开始菜单,对计算机点右键=》属性 选中后点击编辑,在最后面分别添加 ;C:\Python\Scripts\;C:\Python\; 这是刚才的安装路径 然后打开新的CMD(要开新的cmd才有效),输入python就可以看到刚才的提示进入编码界面了 2)安装pycharm IDE软件 双击pycharm-community-2016.2.3.exe,一般按正常的默认安装项就可以了 这里是选择IDE编辑界面皮肤的,一般来说使用黑底灰字看起来没那么刺眼,对眼好一点,这里选择以后还可以在里面设置。 提交后安装成功。 汉化方法 到网上下载个汉化包改名为resources_cn.jar,然后直接复制到安装路径下的lib文件夹里,重新打开IDE就自动汉化了 想要取消汉化,只需要将这个文件删除,重新打开IDE就自动恢复英文版本 建议不要进行汉化,因为汉化后IDE有一些功能使用不了或点击不了 要配置编辑界面皮肤,可按下面进行配置。一般字体按默认项会比较小,也可以按下面的配置修改大一些。 这里的列表项选择可以使用不同的皮肤 使用默认项时,字体大小无法直接进行修改,点击Save As... 另存为后就可以修改 另存为后现在就可以直接修改了 3)安装postgresql数据库 双击安装文件,然后按默认项安装就可以了 最后一步这个勾最好去掉,不然会弹出安装各种插件的窗口,一般来说那些插件我们暂时都用不上,不用进行安装 3.安装python各种包 安装包有两种方法,一种是使用命令行,一种是IDE选择安装 1)命令行安装方式 打开cmd,输入pip install flask (你要安装的包名称),按回车就开始进入安装了 等一会就安装成功了 一般我们需要将pip升级到最新版本,这样可以减少安装问题的出现 在cmd中输入下面命令,就会启动pip升级 1 pip install https://pypi.python.org/packages/11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/pip-9.0.1.tar.gz#md5=35f01da33009719497f01a4ba69d63c9 我们在cmd中输入:pip --version 就可以看到当前的pip版本了 万一pip升级失败,也不用怕,可以到python官网进行下载安装包进行安装升级 在浏览器地址栏中输入:https://pypi.python.org/pypi/pip 下载安装包,并解压到C盘根目录 在DOS下输入下图命令,进入pip-9.0.1文件夹,然后输入:python setup.py install 进入pip安装 完成pip升级操作 2)IDE安装方式 打开IDE,点击:File => Default Settings 然后选择Project Interpreter,就可以看到已经安装好的python包列表了,点击右上角的+进入安装包选择界面 在顶部搜索框里输入想要安装的包名称,就可以搜索到安装包,然后选择它,点击左下角的Install Package,IDE就开始进入下载安装了,如果出现由于网络原因造成安装失败,可以点击其他项后再点回来,然后点安装,多次后就可以安装成功,反复进行后还是无法安装成功的,可以点击查看出错原因,也可以使用命令方式进行,直接看到出错原因。 完成以上操作后,就可以开始开发pythont程序了 本文转自 AllEmpty 博客园博客,原文链接:http://www.cnblogs.com/EmptyFS/p/6184627.html,如需转载请自行联系原作者
在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势。本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病。 Android应用开发在一般情况下,常规的开发方式和代码架构就能满足我们的普通需求。但是有些特殊问题,常常引发我们进一步的沉思。我们从沉思中产生顿悟,从而产生新的技术形式。 如何开发一个可以自定义控件的Android应用?就像eclipse一样,可以动态加载插件;如何让Android应用执行服务器上的不可预知的代码?如何对Android应用加密,而只在执行时自解密,从而防止被破解?…… 熟悉Java技术的朋友,可能意识到,我们需要使用类加载器灵活的加载执行的类。这在Java里已经算是一项比较成熟的技术了,但是在Android中,我们大多数人都还非常陌生。 类加载机制 Dalvik虚拟机如同其他Java虚拟机一样,在运行程序时首先需要将对应的类加载到内存中。而在Java标准的虚拟机中,类加载可以从class文 件中读取,也可以是其他形式的二进制流,因此,我们常常利用这一点,在程序运行时手动加载Class,从而达到代码动态加载执行的目的 然而Dalvik虚拟机毕竟不算是标准的Java虚拟机,因此在类加载机制上,它们有相同的地方,也有不同之处。我们必须区别对待 例如,在使用标准Java虚拟机时,我们经常自定义继承自ClassLoader的类加载器。然后通过defineClass方法来从一个二进制流中加 载Class。然而,这在Android里是行不通的,大家就没必要走弯路了。参看源码我们知道,Android中ClassLoader的 defineClass方法具体是调用VMClassLoader的defineClass本地静态方法。而这个本地方法除了抛出一个 “UnsupportedOperationException”之外,什么都没做,甚至连返回值都为空 [cpp] view plain copy static void Dalvik_java_lang_VMClassLoader_defineClass(const u4* args,JValue* pResult){ Object* loader = (Object*) args[0]; StringObject* nameObj = (StringObject*) args[1]; const u1* data = (const u1*) args[2]; int offset = args[3]; int len = args[4]; Object* pd = (Object*) args[5]; char* name = NULL; name = dvmCreateCstrFromString(nameObj); LOGE("ERROR: defineClass(%p, %s, %p, %d, %d, %p)\n",loader, name, data, offset, len, pd); dvmThrowException("Ljava/lang/UnsupportedOperationException;","can't load this type of class file"); free(name); RETURN_VOID(); } Dalvik虚拟机类加载机制 那如果在Dalvik虚拟机里,ClassLoader不好使,我们如何实现动态加载类呢?Android为我们从ClassLoader派生出了两个 类:DexClassLoader和PathClassLoader。其中需要特别说明的是PathClassLoader中一段被注释掉的代码: [java] view plain copy /* --this doesn't work in current version of Dalvik-- if (data != null) { System.out.println("--- Found class " + name + " in zip[" + i + "] '" + mZips[i].getName() + "'"); int dotIndex = name.lastIndexOf('.'); if (dotIndex != -1) { String packageName = name.substring(0, dotIndex); synchronized (this) { Package packageObj = getPackage(packageName); if (packageObj == null) { definePackage(packageName, null, null, null, null, null, null, null); } } } return defineClass(name, data, 0, data.length); } */ 这从另一方面佐证了defineClass函数在Dalvik虚拟机里确实是被阉割了。而在这两个继承自ClassLoader的类加载器,本质上是重载了ClassLoader的findClass方法。在执行loadClass时,我们可以参看ClassLoader部分源码: [java] view plain copy protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { Class<?> clazz = findLoadedClass(className); if (clazz == null) { try { clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { // Don't want to see this. } if (clazz == null) { clazz = findClass(className); } } return clazz; } 因 此DexClassLoader和PathClassLoader都属于符合双亲委派模型的类加载器(因为它们没有重载loadClass方法)。也就是 说,它们在加载一个类之前,回去检查自己以及自己以上的类加载器是否已经加载了这个类。如果已经加载过了,就会直接将之返回,而不会重复加载。 DexClassLoader 和PathClassLoader其实都是通过DexFile这个类来实现类加载的。这里需要顺便提一下的是,Dalvik虚拟机识别的是dex文件,而 不是class文件。因此,我们供类加载的文件也只能是dex文件,或者包含有dex文件的.apk或.jar文件。 也许有人想到,既然 DexFile可以直接加载类,那么我们为什么还要使用ClassLoader的子类呢?DexFile在加载类时,具体是调用成员方法 loadClass或者loadClassBinaryName。其中loadClassBinaryName需要将包含包名的类名中的”.”转换 为”/”我们看一下loadClass代码就清楚了: [java] view plain copy public Class loadClass(String name, ClassLoader loader) { String slashName = name.replace('.', '/'); return loadClassBinaryName(slashName, loader); } 在这段代码前有一段注释,截取关键一部分就是说:If you are not calling this from a class loader, this is most likely not going to do what you want. Use {@link Class#forName(String)} instead. 这就是我们需要使用ClassLoader子类的原因。至于它是如何验证是否是在ClassLoader中调用此方法的,我没有研究,大家如果有兴趣可以 继续深入下去。 有一个细节,可能大家不容易注意到。PathClassLoader是通过构造函数new DexFile(path)来产生DexFile对象的;而DexClassLoader则是通过其静态方法loadDex(path, outpath, 0)得到DexFile对象。这两者的区别在于DexClassLoader需要提供一个可写的outpath路径, 用来释放.apk包或者.jar包中的dex文件。换个说法来说,就是PathClassLoader不能主动从zip包中释放出dex,因此只支持直接 操作dex格式文件,或者已经安装的apk(因为已经安装的apk在cache中存在缓存的dex文件)。而DexClassLoader可以支 持.apk、.jar和.dex文件,并且会在指定的outpath路径释放出dex文件。 另外,PathClassLoader在加载类时调用的是DexFile的loadClassBinaryName,而DexClassLoader调用的是loadClass。因此,在使用PathClassLoader时类全名需要用”/”替换”.” 实际操作 使用到的工具都比较常规:javac、dx、eclipse等其中dx工具最好是指明--no-strict,因为class文件的路径可能不匹配 加 载好类后,通常我们可以通过Java反射机制来使用这个类但是这样效率相对不高,而且老用反射代码也比较复杂凌乱。更好的做法是定义一个 interface,并将这个interface写进容器端。待加载的类,继承自这个interface,并且有一个参数为空的构造函数,以使我们能够通 过Class的newInstance方法产生对象然后将对象强制转换为interface对象,于是就可以直接调用成员方法了,下面是具体的实现步骤 了:第一步: 编写好动态代码类: [java] view plain copy package com.dynamic.interfaces; import android.app.Activity; /** * 动态加载类的接口 */ public interface IDynamic { /**初始化方法*/ public void init(Activity activity); /**自定义方法*/ public void showBanner(); public void showDialog(); public void showFullScreen(); public void showAppWall(); /**销毁方法*/ public void destory(); } 实现类代码如下: [java] view plain copy package com.dynamic.impl; import android.app.Activity; import android.widget.Toast; import com.dynamic.interfaces.IDynamic; /** * 动态类的实现 * */ public class Dynamic implements IDynamic{ private Activity mActivity; @Override public void init(Activity activity) { mActivity = activity; } @Override public void showBanner() { Toast.makeText(mActivity, "我是ShowBannber方法", 1500).show(); } @Override public void showDialog() { Toast.makeText(mActivity, "我是ShowDialog方法", 1500).show(); } @Override public void showFullScreen() { Toast.makeText(mActivity, "我是ShowFullScreen方法", 1500).show(); } @Override public void showAppWall() { Toast.makeText(mActivity, "我是ShowAppWall方法", 1500).show(); } @Override public void destory() { } } 这样动态类就开发好了 第二步: 将上面开发好的动态类打包成.jar,这里要注意的是只打包实现类Dynamic.java,不打包接口类IDynamic.java, 然后将打包好的jar文件拷贝到android的安装目录中的platform-tools目录下,使用dx命令:(我的jar文件是dynamic.jar) dx --dex --output=dynamic_temp.jar dynamic.jar 这样就生成了dynamic_temp.jar,这个jar和dynamic.jar有什么区别呢? 其 实这条命令主要做的工作是:首先将dynamic.jar编译成dynamic.dex文件(Android虚拟机认识的字节码文件),然后再将 dynamic.dex文件压缩成dynamic_temp.jar,当然你也可以压缩成.zip格式的,或者直接编译成.apk文件都可以的,这个后面 会说到。 到这里还不算完事,因为你想想用什么来连接动态类和目标类呢?那就是动态类的接口了,所以这时候还要打个.jar包,这时候只需要打接口类IDynamic.java了 然后将这个.jar文件引用到目标类中,下面来看一下目标类的实现: [java] view plain copy package com.jiangwei.demo; import java.io.File; import java.util.List; import android.app.Activity; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.dynamic.interfaces.IDynamic; import dalvik.system.DexClassLoader; import dalvik.system.PathClassLoader; public class AndroidDynamicLoadClassActivity extends Activity { //动态类加载接口 private IDynamic lib; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //初始化组件 Button showBannerBtn = (Button) findViewById(R.id.show_banner_btn); Button showDialogBtn = (Button) findViewById(R.id.show_dialog_btn); Button showFullScreenBtn = (Button) findViewById(R.id.show_fullscreen_btn); Button showAppWallBtn = (Button) findViewById(R.id.show_appwall_btn); /**使用DexClassLoader方式加载类*/ //dex压缩文件的路径(可以是apk,jar,zip格式) String dexPath = Environment.getExternalStorageDirectory().toString() + File.separator + "Dynamic.apk"; //dex解压释放后的目录 //String dexOutputDir = getApplicationInfo().dataDir; String dexOutputDirs = Environment.getExternalStorageDirectory().toString(); //定义DexClassLoader //第一个参数:是dex压缩文件的路径 //第二个参数:是dex解压缩后存放的目录 //第三个参数:是C/C++依赖的本地库文件目录,可以为null //第四个参数:是上一级的类加载器 DexClassLoader cl = new DexClassLoader(dexPath,dexOutputDirs,null,getClassLoader()); /**使用PathClassLoader方法加载类*/ //创建一个意图,用来找到指定的apk:这里的"com.dynamic.impl是指定apk中在AndroidMainfest.xml文件中定义的<action name="com.dynamic.impl"/> Intent intent = new Intent("com.dynamic.impl", null); //获得包管理器 PackageManager pm = getPackageManager(); List<ResolveInfo> resolveinfoes = pm.queryIntentActivities(intent, 0); //获得指定的activity的信息 ActivityInfo actInfo = resolveinfoes.get(0).activityInfo; //获得apk的目录或者jar的目录 String apkPath = actInfo.applicationInfo.sourceDir; //native代码的目录 String libPath = actInfo.applicationInfo.nativeLibraryDir; //创建类加载器,把dex加载到虚拟机中 //第一个参数:是指定apk安装的路径,这个路径要注意只能是通过actInfo.applicationInfo.sourceDir来获取 //第二个参数:是C/C++依赖的本地库文件目录,可以为null //第三个参数:是上一级的类加载器 PathClassLoader pcl = new PathClassLoader(apkPath,libPath,this.getClassLoader()); //加载类 try { //com.dynamic.impl.Dynamic是动态类名 //使用DexClassLoader加载类 //Class libProviderClazz = cl.loadClass("com.dynamic.impl.Dynamic"); //使用PathClassLoader加载类 Class libProviderClazz = pcl.loadClass("com.dynamic.impl.Dynamic"); lib = (IDynamic)libProviderClazz.newInstance(); if(lib != null){ lib.init(AndroidDynamicLoadClassActivity.this); } } catch (Exception exception) { exception.printStackTrace(); } /**下面分别调用动态类中的方法*/ showBannerBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if(lib != null){ lib.showBanner(); }else{ Toast.makeText(getApplicationContext(), "类加载失败", 1500).show(); } } }); showDialogBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if(lib != null){ lib.showDialog(); }else{ Toast.makeText(getApplicationContext(), "类加载失败", 1500).show(); } } }); showFullScreenBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if(lib != null){ lib.showFullScreen(); }else{ Toast.makeText(getApplicationContext(), "类加载失败", 1500).show(); } } }); showAppWallBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if(lib != null){ lib.showAppWall(); }else{ Toast.makeText(getApplicationContext(), "类加载失败", 1500).show(); } } }); } } 这里面定义了一个IDynamic接口变量,同时使用了DexClassLoader和PathClassLoader来加载类,这里面先来说一说DexClassLoader方式加载: [java] view plain copy //定义DexClassLoader //第一个参数:是dex压缩文件的路径 //第二个参数:是dex解压缩后存放的目录 //第三个参数:是C/C++依赖的本地库文件目录,可以为null //第四个参数:是上一级的类加载器 DexClassLoader cl = new DexClassLoader(dexPath,dexOutputDirs,null,getClassLoader()); 上面已经说了,DexClassLoader是继承ClassLoader类的,这里面的参数说明: 第一个参数是:dex压缩文件的路径:这个就是我们将上面编译后的dynamic_temp.jar存放的目录,当然也可以是.zip和.apk格式的 第二个参数是:dex解压后存放的目录:这个就是将.jar,.zip,.apk文件解压出的dex文件存放的目录,这个就和PathClassLoader方法有区别了,同时你也可以看到PathClassLoader方法中没有这个参数,这个也真是这两个类的区别: PathClassLoader 不能主动从zip包中释放出dex,因此只支持直接操作dex格式文件,或者已经安装的apk(因为已经安装的apk在手机的data/dalvik目录 中存在缓存的dex文件)。而DexClassLoader可以支持.apk、.jar和.dex文件,并且会在指定的outpath路径释放出dex文 件。 然 而我们可以通过DexClassLoader方法指定解压后的dex文件的存放目录,但是我们一般不这么做,因为这样做无疑的暴露了dex文件,所以我们 一般不会将.jar/.zip/.apk压缩文件存放到用户可以察觉到的位置,同时解压dex的目录也是不能让用户看到的。 第三个参数和第四个参数用到的不是很多,所以这里就不做太多的解释了。 这里还要注意一点就是PathClassLoader方法的时候,第一个参数是dex存放的路径,这里传递的是: [java] view plain copy //获得apk的目录或者jar的目录 String apkPath = actInfo.applicationInfo.sourceDir; 指定的apk安装路径,这个值只能这样获取,不然会加载类失败的 第三步: 运行目标类: 要做的工作是: 如果用的是DexClassLoader方式加载类:这时候需要将.jar或者.zip或者.apk文件放到指定的目录中,我这里为了方便就放到sd卡的根目录中 如果用的是PathClassLoader方法加载类:这时候需要先将Dynamic.apk安装到手机中,不然找不到这个activity,同时要注意的是: [java] view plain copy //创建一个意图,用来找到指定的apk:这里的"com.dynamic.impl是指定apk中在AndroidMainfest.xml文件中定义的<action name="com.dynamic.impl"/> Intent intent = new Intent("com.dynamic.impl", null); 这里的com.dynamic.impl是一个action需要在指定的apk中定义,这个名称是动态apk和目标apk之间约定好的 运行结果 点击showBanner显示一个Toast,成功的运行了动态类中的代码! 其实更好的办法就是将动态的.jar.zip.apk文件从网络上获取,安全可靠,同时本地的目标项目不需要改动代码就可以执行不同的逻辑了 1、运行这段代码时4.0.1以上版本会报:java.lang.IllegalArgumentException: optimizedDirectory not readable/writable: /storage/sdcard0 可以通过这个授权解决: 1 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 2、授权之后又会报:java.lang.IllegalArgumentException: Optimized data directory /storage/sdcard0 is not owned by the current user. Shared storage cannot protect your application from code injection attacks. 这个问题的原因是:在4.1系统由于This class loader requires an application-private, writable directory to cache optimized classes为了防止一下问题: External storage does not provide access controls necessary to protect your application from code injection attacks. 所以加了一个判断Libcore.os.getuid() != Libcore.os.stat(parent).st_uid判断两个程序是不是同一个uid 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private DexFile(String sourceName, String outputName, int flags) throws IOException { if (outputName != null) { try { String parent = new File(outputName).getParent(); if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) { throw new IllegalArgumentException("Optimized data directory " + parent + " is not owned by the current user. Shared storage cannot protect" + " your application from code injection attacks."); } } catch (ErrnoException ignored) { // assume we'll fail with a more contextual error later } } mCookie = openDexFile(sourceName, outputName, flags); mFileName = sourceName; guard.open("close"); //System.out.println("DEX FILE cookie is " + mCookie); } 解决方法是:指定dexoutputpath为APP自己的缓存目录 1 2 File dexOutputDir = context.getDir("dex", 0); DexClassLoader dexClassLoader = new DexClassLoader(dexPath,dexOutputDir.getAbsolutePath(),null,getClassLoader()); 关于代码加密的一些设想 最初设想将dex文件加密,然后通过JNI将解密代码写在Native层。解密之后直接传上二进制流,再通过defineClass将类加载到内存中。 现在也可以这样做,但是由于不能直接使用defineClass,而必须传文件路径给dalvik虚拟机内核,因此解密后的文件需要写到磁盘上,增加了被破解的风险。 Dalvik虚拟机内核仅支持从dex文件加载类的方式是不灵活的,由于没有非常深入的研究内核,我不能确定是Dalvik虚拟机本身不支持还是 Android在移植时将其阉割了。不过相信Dalvik或者是Android开源项目都正在向能够支持raw数据定义类方向努力。 我们可以在文档中看到Google说:Jar or APK file with "classes.dex". (May expand this to include "raw DEX" in the future.);在Android的Dalvik源码中我们也能看到RawDexFile的身影(不过没有具体实现) 在RawDexFile出来之前,我们都只能使用这种存在一定风险的加密方式。需要注意释放的dex文件路径及权限管理,另外,在加载完毕类之后,除非出于其他目的否则应该马上删除临时的解密 借鉴:http://blog.csdn.net/jiangwei0910410003/article/details/17679823 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/5249615.html,如需转载请自行联系原作者
一、起源: 先看效果,在linearLayout中添加了4个Fragment,然后点击替换一次确替换了两个Fragment,引发了我的研究兴趣; 第一次启动 点击一次 点击两次 点击三次 代码很简单 activity onCreate 方法中添加了4个Fragment FragmentTransaction transaction =manager.beginTransaction(); transaction.add(R.id.content,fragment1,"a"); transaction.add(R.id.content,fragment1_2,"b"); transaction.add(R.id.content,fragment1_3,"c"); transaction.add(R.id.content,fragment1_4,"d"); transaction.commit(); replace 按钮监听事件中添加了如下代码 Fragment2 fragment2_1 =newFragment2(); FragmentTransaction transaction=manager.beginTransaction(); transaction.replace(R.id.content,fragment2_1,"kk"); transaction.commit(); 二、探究transaction.replace到底做了什么 探究源码得知FragmentTransaction 对象是在FragmentManagerImpl 类中的beginTransaction()方法中产生的; @Override publicFragmentTransaction beginTransaction() { returnnewBackStackRecord(this); } 这才发现BackStackRecord产生的对象才是我们真正使用的FragmentTransaction,那BackStackRecord.replace() 方法究竟做了啥,让我们一探究竟; publicFragmentTransactionreplace(intcontainerViewId, Fragment fragment, String tag) { doAddOp(containerViewId, fragment, tag,OP_REPLACE); return this; } public FragmentTransactionadd(intcontainerViewId, Fragment fragment, String tag) { doAddOp(containerViewId, fragment, tag,OP_ADD); return this; } 可以看到add和 replace 方法都没有自己去处理而是交给doAddOp处理,doAddOp()简化代码如下 privatevoiddoAddOp(intcontainerViewId, Fragment fragment, String tag,int opcmd){ fragment.mFragmentManager = mManager; if (tag!=null) { fragment.mTag = tag; } if(containerViewId != 0) { fragment.mContainerId = fragment.mFragmentId =containerViewId; } Op op =new Op(); op.cmd =opcmd; op.fragment =fragment; addOp(op); } 我们发现,add 和replace 方法都是进行了fragment对象的tag、mFragmentId、mContainerId的赋值,mContainerId是容器id,也就是说每一个fragment 都有保留它被添加的容器的id,也就是我们replace传入的R.id,content; 再看看OP static final class Op { Op next; Op prev; int cmd; Fragment fragment; int enterAnim; int exitAnim; int popEnterAnim; int popExitAnim; ArrayList<Fragment> removed; } Op其实就是保存我们处理动作的一个对象,经过一系列追踪发现,最终在BackStackRecord.run()中处理了这个对象;具体的追踪过程可以参考:https://zhuanlan.zhihu.com/p/20660984 处理源码如下: switch (op.cmd) { caseOP_ADD: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.addFragment(f,false); } break; caseOP_REPLACE: { Fragment f = op.fragment; if (mManager.mAdded !=null) { for (int i=0;i<mManager.mAdded.size(); i++) { Fragment old =mManager.mAdded.get(i); if(FragmentManagerImpl.DEBUG) Log.v(TAG, "OP_REPLACE: adding=" + f + "old=" + old); if (f == null ||old.mContainerId == f.mContainerId) { if (old== f) { op.fragment = f =null; } else { if (op.removed ==null) { op.removed =newArrayList<Fragment>(); } op.removed.add(old); old.mNextAnim = op.exitAnim; if (mAddToBackStack) { old.mBackStackNesting += 1; if(FragmentManagerImpl.DEBUG) Log.v(TAG,"Bump nesting of " + old +" to " + old.mBackStackNesting); } mManager.removeFragment(old,mTransition,mTransitionStyle); } } } } if (f !=null) { f.mNextAnim = op.enterAnim; mManager.addFragment(f,false); } } break; 好了终于找到replace的真正处理之处,我们精练出关键代码再看看: switch (op.cmd) { caseOP_ADD: { Fragment f = op.fragment; mManager.addFragment(f,false); } break; caseOP_REPLACE: { Fragment f = op.fragment; if (mManager.mAdded !=null) { for (int i=0;i<mManager.mAdded.size(); i++) { Fragment old =mManager.mAdded.get(i); if (f == null ||old.mContainerId == f.mContainerId) { if (old== f) { op.fragment = f =null; } else { mManager.removeFragment(old,mTransition,mTransitionStyle); } } } } if (f !=null) { mManager.addFragment(f,false); } } break; 可以看到 1、add方法就是调用了fragmentmanager的添加方法; 2、replace 则是先删除fragmentmanager中所有已添加的fragment中,容器id与当前要添加的fragment的容器id相同的fragment;然后再添加当前fragment; 3、由于添加的时候都是在一个LinearLayout 中,那么所有的 fragment的容器Id都是一样的; 得出结论: replace 会删除LinearLayout中所有fragment ,然后再添加传入fragment对象; 好,问题来了,最开始的图片点击第一次删除的是fragment1和fragment1_3 ,第二次只删除了fragment1_3,并没有删除全部,这又是为什么; 带着疑问的态度进行了一次调试,在调试中终于找到了原因,问题就在这段代码: for (int i=0; i<mManager.mAdded.size(); i++) { Fragment old = mManager.mAdded.get(i); if (f ==null ||old.mContainerId == f.mContainerId) { mManager.removeFragment(old,mTransition, mTransitionStyle); } } mManager.mAdded 是一个ArrayList<Fragment> 列表,在遍历的时候调用了mManager.removeFragment方法,而该方法调用了ArrayList的remove方法; public void removeFragment(Fragmentfragment, int transition, inttransitionStyle) { mAdded.remove(fragment); } 也就是说在用for循环遍历ArrayList列表的时候使用了remove;这是开始怀恋我们的Java老师的了,list遍历列表要删除元素我们要用iterator.remove(); For循环遍历过程删除会造成ArrayList.size()不断变小,所以造成删除不完全的问题;你是否也被坑过。。。 笔记建议 Android此处可以将 mManager.mAdded复制一份再遍历,就不会有这个问题了(亲测有效); ArrayList<Fragment> list=new ArrayList<Fragment>(mManager.mAdded ) ; for (int i=0; i<list.size();i++) { Fragment old = list.get(i); if (f ==null ||old.mContainerId == f.mContainerId) { mManager.removeFragment(old,mTransition, mTransitionStyle); } } 三、总结 用于我们常常使用FrameLayout 做容器fragment都掩盖了下面其他Fragment,大部分情况下看不到此类问题,看不到不表示不存在,笔者建议,遇到此类还是手动去调用remove+add方法,一定要使用replace()可以去修改源码,如果你不嫌麻烦的话。。。 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/6245968.html,如需转载请自行联系原作者
Rebound是什么? Rebound是一个来自 Facebook 公司的 Java物理和动画库。Rebound spring 模型可用于创建动画,让你感觉很自然。 Rebound的运作原理是什么? Rebound拥有两个参数:tension、friction。 tension是张力,拉力。 friction是摩擦力。 演示: tension:50,friction:1 rebound_t50_f1.gif 拉力为50时,摩擦为1。摩擦对拉力的损耗十分小,可以看出图片是经历了弹簧式的来回放大缩小,直到拉力耗尽到停止。同理,当摩擦力为0的时候,力不会被损耗,将会一直运动下去。 tension:50,friction:15 rebound_t50_f15.gif 拉力为50时,摩擦为15。我们模拟将图片缩小到最小,在某一个瞬间释放。会看到摩擦对拉力的损耗十分大,甚至没有回弹。 代码编写 MainActivity关键代码 /** * 弹簧动画 * * @param v 动画View * @param from 开始参数 * @param to 结束参数 * @param tension 拉力系数 * @param friction 摩擦力系数 */ private void animateViewDirection(final View v, float from, float to, int tension, int friction) { //从弹簧系统创建一个弹簧 Spring spring = springSystem.createSpring(); //设置弹簧的开始参数 spring.setCurrentValue(from); //查看源码可知 //public static SpringConfig defaultConfig = fromOrigamiTensionAndFriction(40.0D, 7.0D); //弹簧的默认拉力是40,摩擦是7。这里设置为我们seekBar选择的拉力和摩擦参数 spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(tension, friction)); //给弹簧添加监听,动态设置控件的状态 spring.addListener(new SimpleSpringListener() { @Override public void onSpringUpdate(Spring spring) { //设置图片的X,Y的缩放 //还可以设置setAlpha,setTranslationX...综合形成复杂的动画 v.setScaleX((float) spring.getCurrentValue()); v.setScaleY((float) spring.getCurrentValue()); } }); //设置结束时图片的参数 spring.setEndValue(to); } Demo展示 rebound_demo.gif 然而你们觉得 image 看看github大牛用rebound做的动画 rebound_demo_2.gif Rebound只是一个简单的物理模型,最终想法和效果由我们自己控制 参考资料 Github:Rebound Github 官网:Rebound 源码下载 coding公开项目地址:https://git.coding.net/fanming/rebound-demo.git 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/7079822.html,如需转载请自行联系原作者
JVM内存模型 Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是: 1. 程序计数器 2. Java虚拟机栈 3. 本地方法栈 4. 堆 5. 方法区。 下面对这五个区域展开深入的介绍。 1. 程序计数器 1.1. 什么是程序计数器? 程序计数器是一块较小的内存空间,可以把它看作当前线程正在执行的字节码的行号指示器。也就是说,程序计数器里面记录的是当前线程正在执行的那一条字节码指令的地址。 注:但是,如果当前线程正在执行的是一个本地方法,那么此时程序计数器为空。 1.2. 程序计数器的作用 程序计数器有两个作用: 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。 1.3. 程序计数器的特点 是一块较小的存储空间 线程私有。每条线程都有一个程序计数器。 是唯一一个不会出现OutOfMemoryError的内存区域。 生命周期随着线程的创建而创建,随着线程的结束而死亡。 2. Java虚拟机栈(JVM Stack) 2.1. 什么是Java虚拟机栈? Java虚拟机栈是描述Java方法运行过程的内存模型。 Java虚拟机栈会为每一个即将运行的Java方法创建一块叫做“栈帧”的区域,这块区域用于存储该方法在运行过程中所需要的一些信息,这些信息包括: 局部变量表 存放基本数据类型变量、引用类型的变量、returnAddress类型的变量。 操作数栈 动态链接 方法出口信息 等 当一个方法即将被运行时,Java虚拟机栈首先会在Java虚拟机栈中为该方法创建一块“栈帧”,栈帧中包含局部变量表、操作数栈、动态链接、方法出口信息等。当方法在运行过程中需要创建局部变量时,就将局部变量的值存入栈帧的局部变量表中。 当这个方法执行完毕后,这个方法所对应的栈帧将会出栈,并释放内存空间。 注意:人们常说,Java的内存空间分为“栈”和“堆”,栈中存放局部变量,堆中存放对象。 这句话不完全正确!这里的“堆”可以这么理解,但这里的“栈”只代表了Java虚拟机栈中的局部变量表部分。真正的Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。 2.2. Java虚拟机栈的特点 局部变量表的创建是在方法被执行的时候,随着栈帧的创建而创建。而且,局部变量表的大小在编译时期就确定下来了,在创建的时候只需分配事先规定好的大小即可。此外,在方法运行的过程中局部变量表的大小是不会发生改变的。 Java虚拟机栈会出现两种异常:StackOverFlowError和OutOfMemoryError。 a) StackOverFlowError: 若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。 b) OutOfMemoryError: 若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。 Java虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。 注:StackOverFlowError和OutOfMemoryError的异同? StackOverFlowError表示当前线程申请的栈超过了事先定好的栈的最大深度,但内存空间可能还有很多。 而OutOfMemoryError是指当线程申请栈时发现栈已经满了,而且内存也全都用光了。 3. 本地方法栈 3.1. 什么是本地方法栈? 本地方法栈和Java虚拟机栈实现的功能类似,只不过本地方法区是本地方法运行的内存模型。 本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。 方法执行完毕后相应的栈帧也会出栈并释放内存空间。 也会抛出StackOverFlowError和OutOfMemoryError异常。 4. 堆 4.1. 什么是堆? 堆是用来存放对象的内存空间。 几乎所有的对象都存储在堆中。 4.2. 堆的特点 线程共享 整个Java虚拟机只有一个堆,所有的线程都访问同一个堆。而程序计数器、Java虚拟机栈、本地方法栈都是一个线程对应一个的。 在虚拟机启动时创建 垃圾回收的主要场所。 可以进一步细分为:新生代、老年代。 新生代又可被分为:Eden、From Survior、To Survior。 不同的区域存放具有不同生命周期的对象。这样可以根据不同的区域使用不同的垃圾回收算法,从而更具有针对性,从而更高效。 堆的大小既可以固定也可以扩展,但主流的虚拟机堆的大小是可扩展的,因此当线程请求分配内存,但堆已满,且内存已满无法再扩展时,就抛出OutOfMemoryError。 5. 方法区 5.1. 什么是方法区? Java虚拟机规范中定义方法区是堆的一个逻辑部分。 方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。 5.2. 方法区的特点 线程共享 方法区是堆的一个逻辑部分,因此和堆一样,都是线程共享的。整个虚拟机中只有一个方法区。 永久代 方法区中的信息一般需要长期存在,而且它又是堆的逻辑分区,因此用堆的划分方法,我们把方法区称为老年代。 内存回收效率低 方法区中的信息一般需要长期存在,回收一遍内存之后可能只有少量信息无效。 对方法区的内存回收的主要目标是:对常量池的回收 和 对类型的卸载。 Java虚拟机规范对方法区的要求比较宽松。 和堆一样,允许固定大小,也允许可扩展的大小,还允许不实现垃圾回收。 5.3. 什么是运行时常量池? 方法区中存放三种数据:类信息、常量、静态变量、即时编译器编译后的代码。其中常量存储在运行时常量池中。 我们一般在一个类中通过public static final来声明一个常量。这个类被编译后便生成Class文件,这个类的所有信息都存储在这个class文件中。 当这个类被Java虚拟机加载后,class文件中的常量就存放在方法区的运行时常量池中。而且在运行期间,可以向常量池中添加新的常量。如:String类的intern()方法就能在运行期间向常量池中添加字符串常量。 当运行时常量池中的某些常量没有被对象引用,同时也没有被变量引用,那么就需要垃圾收集器回收。 6. 直接内存 直接内存是除Java虚拟机之外的内存,但也有可能被Java使用。 在NIO中引入了一种基于通道和缓冲的IO方式。它可以通过调用本地方法直接分配Java虚拟机之外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象直接操作该内存,而无需先将外面内存中的数据复制到堆中再操作,从而提升了数据操作的效率。 直接内存的大小不受Java虚拟机控制,但既然是内存,当内存不足时就会抛出OOM异常。 综上所述 Java虚拟机的内存模型中一共有两个“栈”,分别是:Java虚拟机栈和本地方法栈。 两个“栈”的功能类似,都是方法运行过程的内存模型。并且两个“栈”内部构造相同,都是线程私有。 只不过Java虚拟机栈描述的是Java方法运行过程的内存模型,而本地方法栈是描述Java本地方法运行过程的内存模型。 Java虚拟机的内存模型中一共有两个“堆”,一个是原本的堆,一个是方法区。方法区本质上是属于堆的一个逻辑部分。堆中存放对象,方法区中存放类信息、常量、静态变量、即时编译器编译的代码。 堆是Java虚拟机中最大的一块内存区域,也是垃圾收集器主要的工作区域。 程序计数器、Java虚拟机栈、本地方法栈是线程私有的,即每个线程都拥有各自的程序计数器、Java虚拟机栈、本地方法区。并且他们的生命周期和所属的线程一样。 而堆、方法区是线程共享的,在Java虚拟机中只有一个堆、一个方法栈。并在JVM启动的时候就创建,JVM停止才销毁。 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/8036468.html,如需转载请自行联系原作者
The following example shows how you can add custom animation and effects when displaying a tool tip in Flex <?xml version="1.0" encoding="utf-8"?><!-- http://blog.flexexamples.com/2007/09/04/adding-animations-and-effects-to-flex-tool-tips/ --><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" verticalAlign="middle" backgroundColor="white" creationComplete="init()"> <mx:Script> <![CDATA[ import mx.managers.ToolTipManager; private function init():void { ToolTipManager.hideDelay = 2000; ToolTipManager.showEffect = rotate; ToolTipManager.hideEffect = zoom; } ]]> </mx:Script> <mx:Style> @font-face { src: url("./fonts/arial.ttf"); fontFamily: "ArialEmbedded"; } ToolTip { fontFamily: ArialEmbedded; } </mx:Style> <mx:Rotate id="rotate" /> <mx:Zoom id="zoom" /> <mx:Button label="Roll over me to see tool tip" toolTip="The quick brown fox" /></mx:Application> 本文转自 OldHawk 博客园博客,原文链接:http://www.cnblogs.com/taobataoma/archive/2008/01/13/1037095.html,如需转载请自行联系原作者
在网上找到的源码,是beta版的,但由于beta与正式版在类上有很大的区别,所以不能直接使用,我在flex3正式版下修改过了,没有bug。在使用前,请按以下骤执行:1.创建一个名为testair的FLEX项目(AIR程序)2.编辑testair-app.xml并设置SystemChrome为none(这样可以获得较酷的程序皮肤)3.复制代码到testair.mxml中(并保存)编译,ok,运行。 本文转自 OldHawk 博客园博客,原文链接:http://www.cnblogs.com/taobataoma/archive/2008/03/05/1091524.html,如需转载请自行联系原作者
最近想整理一些词库,懒得手动找,又怕手一哆嗦有遗漏,决定写程序完成吧。 首先将数据用GridView控件显示到页面上,效果如下: 接下来将GridView中的内容导出到Excel,方法如下: /// <summary> /// 由GridView导出Excel /// </summary> /// <param name="ctl">GridView控件ID</param> /// <param name="FileName">导出Excel名称</param> private void ToExcel(Control ctl, string FileName) { HttpContext.Current.Response.Charset = "UTF-8"; HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8; HttpContext.Current.Response.ContentType = "application/ms-excel"; HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + "" + FileName); ctl.Page.EnableViewState = false; System.IO.StringWriter tw = new System.IO.StringWriter(); HtmlTextWriter hw = new HtmlTextWriter(tw); ctl.RenderControl(hw); HttpContext.Current.Response.Write(tw.ToString()); HttpContext.Current.Response.End(); } 在按钮上添加事件来导出Excel。注意,因为GridView是有分页和排序设置的,为了能够显示完整的数据,要先取消分页排序,导出之后再恢复设置。代码如下: protected void btnExport_Click(object sender, EventArgs e) { gvWord.AllowPaging = false; gvWord.AllowSorting = false; Display(); ToExcel(gvWord, "word.xls"); gvWord.AllowSorting = true; gvWord.AllowPaging = true; Display(); } 可是运行之后报错: 类型“GridView”的控件“GridView1”必须放在具有 runat=server 的窗体标记内。 添加重写方法: public override void VerifyRenderingInServerForm(Control control) { //base.VerifyRenderingInServerForm(control); } 完成后效果如下: 这下可以让程序帮我整理了,省了一笔麻烦啊。 本文转自 陈敬(Cathy) 博客园博客,原文链接:http://www.cnblogs.com/janes/archive/2011/01/05/1926161.html,如需转载请自行联系原作者
1 2 3 4 5 6 7 8 9 10 http_build_query() <?php $data = array('foo'=>'bar', 'baz'=>'boom', 'cow'=>'milk', 'php'=>'hypertext processor'); echo http_build_query($data); foo=bar&baz=boom&cow=milk&php=hypertext+processor ?> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mktime() <?php // 输出:October 3, 1975 was on a Friday echo "Oct 3, 1975 was on a ".date("l", mktime(0,0,0,10,3,1975)) . "<br><br>"; //在进行日期计算和验证时会用到 mktime() 函数 //它会对超出范围的输入值自动计算正确的值: echo date("M-d-Y",mktime(0,0,0,12,36,2001)) . "<br>"; echo date("M-d-Y",mktime(0,0,0,14,1,2001)) . "<br>"; echo date("M-d-Y",mktime(0,0,0,1,1,2001)) . "<br>"; echo date("M-d-Y",mktime(0,0,0,1,1,99)) . "<br>"; ?> Oct 3, 1975 was on a Friday Jan-05-2002 Feb-01-2002 Jan-01-2001 Jan-01-1999 $today=mktime(0,0,0,date('m'),date('d'),date('Y')); 1 2 3 4 5 6 7 8 9 10 mb_strlen <?php //测试时文件的编码方式要是UTF8 $str='中文a字1符'; echo strlen($str).'<br>';//14 echo mb_strlen($str,'utf8').'<br>';//6 echo mb_strlen($str,'gbk').'<br>';//8 echo mb_strlen($str,'gb2312').'<br>';//10 ?> 1 2 3 4 5 6 7 8 9 10 11 12 strip_tags() <?php $text = '<p>Test paragraph.</p><!-- Comment --> <a href="#fragment">Other text</a>'; echo strip_tags($text); echo " "; // 允许 <p> 和 <a> echo strip_tags($text, '<p><a>'); ?> Test paragraph. Other text <p>Test paragraph.</p> <a href="#fragment">Other text</a> 1 2 3 4 5 6 7 8 9 10 11 array_push() <?php $a=array(); array_push($a,"blue","yellow"); print_r($a); ?> Array ( [0] => blue [1] => yellow ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 array_merge() <?php $a1=array("red","green"); $a2=array("blue","yellow"); print_r(array_merge($a1,$a2)); ?> Array ( [0] => red [1] => green [2] => blue [3] => yellow ) 1 2 3 4 5 mb_substr() <?php $aaa = "this这是中文字符串"; echo mb_substr($aaa,0,6,'UTF-8');//输出值为: this这是 1 2 3 4 strtotime <?php echo strtotime(date("Y-m-d",time())); //1483632000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 intval() floatval() strval() <?php $str="123.9abc"; $int = intval($str); var_dump($int); $float = floatval($str); var_dump($float); $str=strval($str); var_dump($str); ?> int(123) float(123.9) string(8) "123.9abc" 本文转自ning1022 51CTO博客,原文链接:http://blog.51cto.com/ning1022/1889697,如需转载请自行联系原作者
1:安装http,mod_dav_svn,让http支持svn yum install httpd apr apr-util httpd-devel mod_dav_svn mod_auth_mysql 2:检查模块是否存在 cd /etc/httpd/modules/ && ls mod_dav_svn.so mod_auth_mysql.so mod_dav_svn.so mod_auth_mysql.so 3:创建SVN的http加密文件 htpasswd -cm /data/svnroot/conf/svnpasswdfile admin htpasswd -m /data/svnroot/conf/svnpasswdfile test1 htpasswd -m /data/svnroot/conf/svnpasswdfile test2 创建SVN的明文密码文件vim passwd [users] test = svnpasswd test1 = svnpasswd test2 = svnpasswd 注意: /data/svnroot/conf/目录下面passwd文件是svnserve独立服务器使用的认证文件,密码没有加密,明文显示。 /data/svnroot/conf/目录下面http_passwd文件是Apache的http模式使用的认证文件,密码使用MD5加密。 passwd和http_passwd文件中,账号密码必须设置相同。 4:配置http 你会发现路径/etc/httpd/conf.d/多了几个文件,因为我们在yum的时候已经安装完成了 auth_mysql.conf README subversion.conf welcome.conf 直接配置subversion.conf,内容如下 LoadModule dav_svn_module modules/mod_dav_svn.so LoadModule authz_svn_module modules/mod_authz_svn.so <Location /svn> DAV svn SVNParentPath /data/svnroot AuthType Basic AuthName "Authorization SVN" AuthzSVNAccessFile /data/svnroot/conf/authz AuthUserFile /data/svnroot/conf/svnpasswdfile Require valid-user </Location> 5:重启动http /etc/init.d/httpd restart 6:svn服务器如果要具体配置权限文件和密码文件,需要在每个新建的库conf目录中修改svnserve.conf配置;如果库很多的话每个都要做修改很麻烦。 7:所有库共用一套密码文件和权限文件 svnserve -d -r /data/svnroot --config-file /data/svnroot/conf/svnserve.conf --listen-port 3690 未完待续。。。 本文转自卫庄的痛 51CTO博客,原文链接:http://blog.51cto.com/crfsz/1831072,如需转载请自行联系原作者
在AD中批量添加多个用户帐号 作者:许本新 在前面给大家介绍了怎么在网络中批量安装操作系统,今天我又要给大家介绍如何在AD中批量创建用户帐号的文章了,在我发布新文章的时候请大家多多的鼓励一下和支持一下。 如果我们要想批量的创建帐号的话,我们可以首先利用文字编辑程序将这些帐号建立到纯文本文件内,然后再利用windows server 2003中所提供的CSVDE.EXE或LDIFDE.EXE将文本中的帐号导入到AD中的某个位置中。 不过在批量创建用户帐号前,我们需要提出几点注意事项: 1、在利用CSVDE.EXE或LDIFDE.EXE创建用户帐号的时候,必须要指明用户帐号建立到何处。 2、必须要在文本中包含对象类型。 3、要有用户登录名。 4、要有UPN名 5、还可以设置一些用户帐号的相关信息(这一项不是必须的)。 6、不过批量创建帐号也有不足之处,那就是这些用户帐号都不能设置密码,不过可以禁用这些帐号。 一、利用CSVDE.EXE来实现批量用户帐号的创建 下面我们首先来介绍一下如何使用CSVDE.EXE来创建批量用户帐号,我们首先要将创建的用户帐号以文本的方式编辑出来,然后再利用CSVDE.EXE导入到AD中指定的位置中。编辑文本如图一 图一(图可点击放大) 记事本中内容说明: DN的内容有: CN=许本新,OU=业务部,DC=wg0502,DC=com.对象的路径 objectClass表示: user,对象种类. sAMAccountName表示: peter,就是"用户登录名" userPrincipalName表示: [email]peter@wg0502.com[/email],就是UPN displayName表示: 许本新,显示名称. userAccountControl 514,表示禁用此帐号(512表示启用) 文本文件创建好后,我门就打开"开始菜单"→"运行"→输入"cmd"进入CMD界面. 如图二操作: 图二(图可点击放大) 最后我们打开AD看看帐号,批量帐号已经出来了,并且都是禁用的,如图三 图三(图可点击放大) 这样以来我们就实现了利用CSVDE.EXE创建批量用户帐号了.二、利用LDIFDE.EXE来实现批量用户帐号的创建。 这种方法与上面介绍的方法有点相似。首先也是将用户帐号,写入到记事本中,然后利用LDIFDE.EXE将用户帐号导入到AD中去。只是文本书写的方式有点不太相同。如图四 图四 然后利用LDIFDE -i -f C:\user2.txt(user2.txt路径) 另外我们还可以利用LDIFDE来修改用户帐号. 本文转自xubenxin 51CTO博客,原文链接:http://blog.51cto.com/windows/15912,如需转载请自行联系原作者
stream editor d命令 sed '1,8d' /etc/fstab 删除fstab的1到8行 a命令i命令 sed '/^UUID/a \hello \hello2' /etc/fstab 行首匹配到UUID的后面添加两行hello ],a换成i行前添加 c命令,替换符合条件的行 w命令,保存符合条件至另一个文件 sed '/^UUID/w /tmp/fstab.txt' /etc/fstab =命令,为模式空间中的行打印行号 -r命令,读取制定文件的文本流至模式空间中的指定行 sed '6r /etc/fstab' /tmp/fstab /etc/fstab的文件流至fstab的第六行后 !命令,取反条件 !d 查找替换,S///,S@@@,S### g行内全局替换 i忽略字符大小写 p显示替换成功的行 w将替换成功的结果保存至文件 sed 's@^UUID@uuid@g' /etc/fstab 将fstab的行首UUID改为uuid pattem space 模式 空间 hold space 保持空间 高级命令可以调用hold space h将pattem space内容覆盖至hold space H将pattem space内容追加至hold space g将hold space内容覆盖至pattem space G将hold space内容追加至pattem space x将hold space与pattem space内容对调 n将匹配到的行的下一行至pattem space N追加匹配到的行的下一行至pattem space d删除pattem space的行 D删除所有pattem space的行 sed -n 'n;p' FILE 显示偶数行 sed 'n;d' FILE显示奇数行 sed '1!G;h;$!d' FILE 逆向显示内容 sed '$!N;$!d' FILE 最后2行 sed '$!d' FILE 最后1行 sed ‘G’ FILE 每一行加空白行 本文转自echoroot 51CTO博客,原文链接:http://blog.51cto.com/echoroot/1930612,如需转载请自行联系原作者
转载地址:http://blog.csdn.net/xinguan1267/article/details/16982479 1:load Average 1.1:什么是Load?什么是Load Average? Load 就是对计算机干活多少的度量(WikiPedia:the system Load is a measure of the amount of work that a compute system is doing) 简单的说是进程队列的长度。Load Average 就是一段时间(1分钟、5分钟、15分钟)内平均Load。【参考文章:unix Load Average Part1:How It Works】 1.2:查看指令: w or uptime or procinfo or top load average: 0.02, 0.27, 0.17 1 per/minute 5 per/minute 15 per/minute 1.3:如何判断系统是否已经Over Load? 对一般的系统来说,根据cpu数量去判断。如果平均负载始终在1.2一下,而你有2颗cup的机器。那么基本不会出现cpu不够用的情况。也就是Load平均要小于Cpu的数量 1.4:Load与容量规划(Capacity Planning) 一般是会根据15分钟那个load 平均值为首先。 1.5:Load误解: 1:系统load高一定是性能有问题。 真相:Load高也许是因为在进行cpu密集型的计算 2:系统Load高一定是CPU能力问题或数量不够。 真相:Load高只是代表需要运行的队列累计过多了。但队列中的任务实际可能是耗Cpu的,也可能是耗i/0及其他因素的。 3:系统长期Load高,首先增加CPU 真相:Load只是表象,不是实质。增加CPU个别情况下会临时看到Load下降,但治标不治本。 2:在Load average 高的情况下如何鉴别系统瓶颈。 是CPU不足,还是io不够快造成或是内存不足? 2.1:查看系统负载vmstat Vmstat procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 0 0 100152 2436 97200 289740 0 1 34 45 99 33 0 0 99 0 procs r 列表示运行和等待cpu时间片的进程数,如果长期大于1,说明cpu不足,需要增加cpu。 b 列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等。 cpu 表示cpu的使用状态 us 列显示了用户方式下所花费 CPU 时间的百分比。us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,需要考虑优化用户的程序。 sy 列显示了内核进程所花费的cpu时间的百分比。这里us + sy的参考值为80%,如果us+sy 大于 80%说明可能存在CPU不足。 wa 列显示了IO等待所占用的CPU时间的百分比。这里wa的参考值为30%,如果wa超过30%,说明IO等待严重,这可能是磁盘大量随机访问造成的,也可能磁盘或者磁盘访问控制器的带宽瓶颈造成的(主要是块操作)。 id 列显示了cpu处在空闲状态的时间百分比 system 显示采集间隔内发生的中断数 in 列表示在某一时间间隔中观测到的每秒设备中断数。 cs列表示每秒产生的上下文切换次数,如当 cs 比磁盘 I/O 和网络信息包速率高得多,都应进行进一步调查。 memory swpd 切换到内存交换区的内存数量(k表示)。如果swpd的值不为0,或者比较大,比如超过了100m,只要si、so的值长期为0,系统性能还是正常 free 当前的空闲页面列表中内存数量(k表示) buff 作为buffer cache的内存数量,一般对块设备的读写才需要缓冲。 cache: 作为page cache的内存数量,一般作为文件系统的cache,如果cache较大,说明用到cache的文件较多,如果此时IO中bi比较小,说明文件系统效率比较好。 swap si 由内存进入内存交换区数量。 so由内存交换区进入内存数量。 IO bi 从块设备读入数据的总量(读磁盘)(每秒kb)。 bo 块设备写入数据的总量(写磁盘)(每秒kb) 这里我们设置的bi+bo参考值为1000,如果超过1000,而且wa值较大应该考虑均衡磁盘负载,可以结合iostat输出来分析。 2.2:查看磁盘负载iostat 每隔2秒统计一次磁盘IO信息,直到按Ctrl+C终止程序,-d 选项表示统计磁盘信息, -k 表示以每秒KB的形式显示,-t 要求打印出时间信息,2 表示每隔 2 秒输出一次。第一次输出的磁盘IO负载状况提供了关于自从系统启动以来的统计信息。随后的每一次输出则是每个间隔之间的平均IO负载状况。 iostat -x 1 10 Linux 2.6.18-92.el5xen 02/03/2009 avg-cpu: %user %nice %system %iowait %steal %idle 1.10 0.00 4.82 39.54 0.07 54.46 Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util sda 0.00 3.50 0.40 2.50 5.60 48.00 18.48 0.00 0.97 0.97 0.28 sdb 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdc 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdd 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sde 0.00 0.10 0.30 0.20 2.40 2.40 9.60 0.00 1.60 1.60 0.08 sdf 17.40 0.50 102.00 0.20 12095.20 5.60 118.40 0.70 6.81 2.09 21.36 sdg 232.40 1.90 379.70 0.50 76451.20 19.20 201.13 4.94 13.78 2.45 93.16 rrqm/s: 每秒进行 merge 的读操作数目。即 delta(rmerge)/s wrqm/s: 每秒进行 merge 的写操作数目。即 delta(wmerge)/s r/s: 每秒完成的读 I/O 设备次数。即 delta(rio)/s w/s: 每秒完成的写 I/O 设备次数。即 delta(wio)/s rsec/s: 每秒读扇区数。即 delta(rsect)/s wsec/s: 每秒写扇区数。即 delta(wsect)/s rkB/s: 每秒读K字节数。是 rsect/s 的一半,因为每扇区大小为512字节。(需要计算) wkB/s: 每秒写K字节数。是 wsect/s 的一半。(需要计算) avgrq-sz: 平均每次设备I/O操作的数据大小 (扇区)。delta(rsect+wsect)/delta(rio+wio) avgqu-sz: 平均I/O队列长度。即 delta(aveq)/s/1000 (因为aveq的单位为毫秒)。 await: 平均每次设备I/O操作的等待时间 (毫秒)。即 delta(ruse+wuse)/delta(rio+wio) svctm: 平均每次设备I/O操作的服务时间 (毫秒)。即 delta(use)/delta(rio+wio) %util: 一秒中有百分之多少的时间用于 I/O 操作,或者说一秒中有多少时间 I/O 队列是非空的。即 delta(use)/s/1000 (因为use的单位为毫秒) 如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘 可能存在瓶颈。 idle小于70% IO压力就较大了,一般读取速度有较多的wait. 同时可以结合vmstat 查看查看b参数(等待资源的进程数)和wa参数(IO等待所占用的CPU时间的百分比,高过30%时IO压力高) 另外还可以参考 一般: svctm < await (因为同时等待的请求的等待时间被重复计算了), svctm的大小一般和磁盘性能有关:CPU/内存的负荷也会对其有影响,请求过多也会间接导致 svctm 的增加。 await: await的大小一般取决于服务时间(svctm) 以及 I/O 队列的长度和 I/O 请求的发出模式。 如果 svctm 比较接近 await,说明I/O 几乎没有等待时间; 如果 await 远大于 svctm,说明 I/O队列太长,应用得到的响应时间变慢, 如果响应时间超过了用户可以容许的范围,这时可以考虑更换更快的磁盘,调整内核 elevator算法,优化应用,或者升级 CPU。 队列长度(avgqu-sz)也可作为衡量系统 I/O 负荷的指标,但由于 avgqu-sz 是按照单位时间的平均值,所以不能反映瞬间的 I/O 洪水。 别人一个不错的例子.(I/O 系统 vs. 超市排队) 举一个例子,我们在超市排队 checkout 时,怎么决定该去哪个交款台呢? 首当是看排的队人数,5个人总比20人要快吧?除了数人头,我们也常常看看前面人购买的东西多少,如果前面有个采购了一星期食品的大妈,那么可以考虑换个队排了。还有就是收银员的速度了,如果碰上了连钱都点不清楚的新手,那就有的等了。另外,时机也很重要,可能 5分钟前还人满为患的收款台,现在已是人去楼空,这时候交款可是很爽啊,当然,前提是那过去的 5 分钟里所做的事情比排队要有意义(不过我还没发现什么事情比排队还无聊的)。 I/O 系统也和超市排队有很多类似之处: r/s+w/s 类似于交款人的总数 平均队列长度(avgqu-sz)类似于单位时间里平均排队人的个数 平均服务时间(svctm)类似于收银员的收款速度 平均等待时间(await)类似于平均每人的等待时间 平均I/O数据(avgrq-sz)类似于平均每人所买的东西多少 I/O 操作率 (%util)类似于收款台前有人排队的时间比例。 我们可以根据这些数据分析出 I/O 请求的模式,以及 I/O 的速度和响应时间。 下面是别人写的这个参数输出的分析 iostat -x 1 avg-cpu: %user %nice %sys %idle 16.24 0.00 4.31 79.44 Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util /dev/cciss/c0d0 0.00 44.90 1.02 27.55 8.16 579.59 4.08 289.80 20.57 22.35 78.21 5.00 14.29 /dev/cciss/c0d0p1 0.00 44.90 1.02 27.55 8.16 579.59 4.08 289.80 20.57 22.35 78.21 5.00 14.29 /dev/cciss/c0d0p2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 上面的 iostat 输出表明秒有 28.57 次设备 I/O 操作: 总IO(io)/s = r/s(读) +w/s(写) = 1.02+27.55 = 28.57 (次/秒) 其中写操作占了主体 (w:r = 27:1)。 平均每次设备 I/O 操作只需要 5ms 就可以完成,但每个 I/O 请求却需要等上 78ms,为什么? 因为发出的 I/O 请求太多 (每秒钟约 29 个),假设这些请求是同时发出的,那么平均等待时间可以这样计算: 平均等待时间 = 单个 I/O 服务时间 ( 1 + 2 + ... + 请求总数-1) / 请求总数 应用到上面的例子: 平均等待时间 = 5ms (1+2+...+28)/29 = 70ms,和 iostat 给出的78ms 的平均等待时间很接近。这反过来表明 I/O 是同时发起的。 每秒发出的 I/O 请求很多 (约 29 个),平均队列却不长 (只有 2 个 左右),这表明这 29 个请求的到来并不均匀,大部分时间 I/O 是空闲的。 一秒中有 14.29% 的时间 I/O 队列中是有请求的,也就是说,85.71% 的时间里 I/O 系统无事可做,所有 29 个 I/O 请求都在142毫秒之内处理掉了。 delta(ruse+wuse)/delta(io) = await = 78.21 => delta(ruse+wuse)/s=78.21 delta(io)/s = 78.2128.57 =2232.8,表明每秒内的I/O请求总共需要等待2232.8ms。所以平均队列长度应为 2232.8ms/1000ms = 2.23,而iostat 给出的平均队列长度 (avgqu-sz) 却为 22.35,为什么?! 因为 iostat 中有 bug,avgqu-sz值应为 2.23,而不是 22.35。 本文转自027ryan 51CTO博客,原文链接:http://blog.51cto.com/ucode/2061141,如需转载请自行联系原作者
约瑟夫问题:转载自 约瑟夫问题 据说着名犹太历史/数学家约瑟夫(Josephus)有过以下的故事:在罗马人占领乔塔帕特後,40个犹太士兵与约瑟夫躲到一个洞中,眼见脱逃无望,一群人决定集体自杀,约瑟夫建议自杀方式,41个人排成圆圈,由第1个人开始报数,每报数到5的人就必须自杀,然後由下一个重新报数,直到所有人都自杀身亡为止。如果你是约瑟夫,你应该在哪个位置才能活下来(最后只剩下你)? 我的答案: 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 package p1; import java.util.LinkedList; import java.util.List; public class KillSelf { //构造链式列表,用来模拟人。 private static List<String> list = new LinkedList<String>(); //记忆自杀那个人前后的人集合有序子列表 private static List<String> listBefore,listAfter; //自杀那个人的编号从1开始 private static String killedNum = null; private static int KILL_INDEX = 4; //记录自杀的总人数 private static int sum = 0; public static void main(String[] args) { //记住每个从最开始的编号 for(int i = 1;i <= 41;i++) { list.add(i+""); } //其实自杀的过程,是一个循环的过程,所以用循环来解决。 while(true) { //获取自杀位置前后的子集 if(list.size()>=5) //当人数大于等于5个人时 { listBefore = new LinkedList<String>(list.subList(0, KILL_INDEX)); //不能直接用subList的返回值,要包装一下 listAfter = new LinkedList<String>(list.subList(KILL_INDEX+1, list.size())); }else if(list.size() > 1 && list.size() < 5) //当人数多于1个人但是少于5个人时 { KILL_INDEX = 5%list.size()-1; //这个判断很巧妙 if(KILL_INDEX > 0 && KILL_INDEX <list.size()-1) { listBefore = new LinkedList<String>(list.subList(0, KILL_INDEX)); //不能直接用subList的返回值,要包装一下 listAfter = new LinkedList<String>(list.subList(KILL_INDEX+1, list.size())); }else if(KILL_INDEX == 0) { listBefore.clear(); listAfter = new LinkedList<String>(list.subList(KILL_INDEX+1, list.size())); }else if(KILL_INDEX == list.size()-1) { listBefore = new LinkedList<String>(list.subList(0, KILL_INDEX)); listAfter.clear(); } }else break; //将子集的后与前连接起来,更新总的集合 killedNum = list.get(KILL_INDEX); sum++; System.out.println("编号" + killedNum + "已自杀!-----自杀总人数达" + sum); //更新list list.clear(); list.addAll(listAfter); list.addAll(listBefore); System.out.println("剩余人员编号:"+list); System.out.println(""); } System.out.println(""); System.out.println("结论:处在"+list.get(0)+"号才不会自杀"); } } 但是网上的帖子,几行代码就解决问题了,这就是算法的魅力! 本文转自屠夫章哥 51CTO博客,原文链接:http://blog.51cto.com/4259297/1658382,如需转载请自行联系原作者
Android中常见的动画有:帧动画、补间动画、属性动画 个个击破: 1.帧动画(Drawable Animation) 通过加载一些图片资源,将它们按顺序展示出来,就像放电影一样。通过AnimationDrawable这个 类来实现。实现步骤: 1)创建res/drawable/目录,即在res文件夹下创建drawable文件夹。 将准备加载的图片资源放到drawable文件夹下,并在drawable目录下新建一个XML文件,用来链 接资源并定义动画的属性,格式如下: 1 2 3 4 5 6 7 <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true" > <item android:drawable="@drawable/girl_1" android:duration="200" /> ... </animation-list> oneshot属性表示是否循环播放动画 duration属性表示每张图片显示的时长,单位毫秒。 2)将XML与ImageView结合并得到动画对象 这是初始化动作,一般放在Activity的onCreate方法中。 1 2 iv_play.setBackgroundResource(R.drawable.my_anim2); final AnimationDrawable animation = (AnimationDrawable) iv_play.getBackground(); 3) 开始动画 1 2 3 4 5 6 new Thread(){ public void run() { SystemClock.sleep(1000); animation.start(); }; }.start(); 官方文档着重强调了start()方法不能写在Activity的onCreate方法中,你可以在Activity的 onWindowFocusChanged方法中调用start方法。 其实呢,官方文档的这种说法不是特别准确。准确地来说,不是start方法不能在Activity的 onCreate方法中执行,而是start方法不能执行太快,因为动画可能还没有附加到Activity上。 如果非要在在Activity的onCreate方法中执行,只有单独给start()方法创建一个子线程,让线程 sleep一小会儿,就达到了延迟执行start方法的目的。 这个就和MediaPlayer的start方法很相似,原理基本是一样的。 2.补间动画(View Animation) 补间动画就是在View对象上完成一些位置、大小、旋转、透明的变化,从而形成动画的效果。虽然 View出现了动画,但是并没有改变控件的真正坐标。 通过查阅官方文档,发现View有一个方法startAnimation,说明任何的View的对象都可以实现补间 动画的效果。 和Day10多媒体学的Matrix矩阵定义图片几种效果相似,补间动画有有5种: 上面这5个动画类,都是Animation的子类。根据动画的对象的获取方式不同,补间动画分为2类。 2-1:动画的获取 第1种方式)通过构造函数来构造动画对象 XxxAnimation xxx = new XxxAnimation(指定动画的参数,不同的动画不一样。); xxx.setYyy(设置持续时长、重复次数、重复模式等属性); 动画合集对象的获取 AnimationSet set = new AnimationSet(true); set.add(XxxAnimation); //可以添加任意多个动画,也可以再是合集。 ■绽放动画 + 透明动画合集 缩放:就是宽高的变化 new ScaleAnimation(fromX, toX, fromY, toY, pivotXType, pivotXValue, pivotYType, pivotYValue); fromX:表示缩放开始的宽1.0f表示控件原始宽,0.5f表示控件原始宽的一半。 toX:表示缩放结束的宽1.0f表示控件原始宽,0.5f表示控件原始宽的一半。 fromY:表示缩放开始的高1.0f表示控件原始宽,0.5f表示控件原始高的一半。 toY:表示缩放结束的高1.0f表示控件原始高,0.5f表示控件原始高的一半。 pivotXType,pivotYType:缩放基点X和Y的坐标参考系 RALATIVE_TO_SELF,表示以自身为参考 RALATIVE_TO_PARENT,表示以父控件为参考 ABSOLUTE,以绝对坐标系为参考,即屏幕 pivotXValue,pivotYValue:绽放基点X坐标和Y坐标 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 得到气泡的视图 View view_popWindow = View.inflate(getBaseContext(), R.layout.view_g3_appmanager_popwindow, null); // 为气泡设置动画合集 透明 + 缩放 AlphaAnimation alphaAnimation = new AlphaAnimation(0.3f, 1.0f); alphaAnimation.setDuration(200); ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 1.0f, 0.5f, 1.0f, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(200); AnimationSet animationSet = new AnimationSet(true); animationSet.addAnimation(alphaAnimation); animationSet.addAnimation(scaleAnimation); view_popWindow.startAnimation(animationSet); 第2种方式)通过AnimationUtils这个工具类来获取动画对象 首先,应创建res/anim/这个目录,即在res文件夹下新建一个anim文件夹。 新建动画的XML文件,用上面列出的标签,定义动画的参数和属性。 其次,在java代码获取XML动画资源。 Animation aa = AnimationUtils.loadAnimation(上下文对象, R.anim.XML文件名); 官方文档有这样一句十分重要的话:As with defining a layout, an XML file is recommended because it's more readable, reusable, and swappable than hard-coding the animation。它的意思推荐开发者使用这种方式定义补间动画,因为它 的阅读性、利用性、交换性(没有明白)比较强。 android Animation动画的xml使用 http://www.2cto.com/kf/201411/352237.html 2-2:动画的启动 与帧动画的启动方式不一样,帧动画是直接通过动画对象来启动的,而补间动画的启动是通过 View对象的startAnimation方法启动的。 1 iv_show.startAnimation(aa); 3.属性动画(Property Animation) API11以上版本才可以使用,可以使用nineoldandroids-2.4.0.jar包 ViewHolder.setXxx(View,) 来设置View的属性动画来兼容低版本手机。 官方文档花了很大的篇幅来说属性动画,说它的功能十分的强大,还将其与补间动画作了一下 比较。其实顾名思义,我们就能明白属性动画的特点。与补间不同,补间动画只是纯粹地让View对 象产生动画的效果,本身View对象没有发生任何的改变。而属性动画不仅可以让View对象,也可以让 not-view对象产生动画效果,而且最重要的一点,属性动画会修改对象的属性。 View.setXxx() 属性动画常和类型估值器TypeEvaluator(和值动画一样都位于android.animation包下)一起使用 ArgbEvaluator 颜色过度器 。。。 4.属性动画 Android属性动画深入分析:让你成为动画牛人 http://www.2cto.com/kf/201401/270169.html Android 动画详解之属性动画(Property Animation) http://www.2cto.com/kf/201411/353170.html 4-1.值动画(ValueAnimator ) API11之后方可使用 //利用静态方法创建值动画对象 ValueAnimator animator = ValueAnimator.ofFloat(0.0f,1.0f); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float percent = (Float) animation.getAnimatedValue(); //根据这个百分比,做自己想做的事情。 } }); //持续时长 animator.setDuration(500); //插值器 //Overshoot 橡皮筋效果,过了又弹回来 //CycleInterpolator 循环加速器,让动画连续执行多次 animator.setInterpolator(new OvershootInterpolator(2)); animator.start(); 本文转自屠夫章哥 51CTO博客,原文链接:http://blog.51cto.com/4259297/1679852,如需转载请自行联系原作者
看到很多的APP,都有PagerSlidingTab这个控件,而且风格都不一样,所以我决定研究一番。 1.老师给了个控件PagerSlidingTab,假如Tab只有2个的时候,标题并没有占满全屏。那怎改? 2.如果想要有自己的效果,那么就得理解源码,修改源码。 源码怎么看:不可能全部看完,抓住主要的,自己关心的地方。否则看源码就是一件痛苦的事情。 1)首先看PagerSlidingTab这个类的继承关系,发现它继承自HorizontalScrollView -->FrameLayout-->ViewGroup。 2)看PagerSlidingTab构造函数,会发现标题其实是水平的LinearLayout,源码中用 tabsContainer表示。 3)我想,标题没有居中,也就是子View没有添加权重。于是Ctrl + F,在类里搜索tabsContainer。 发现addTextTab和addIconTab两个方法中tabsContainer会有添加子View,于是Ctrl + F,再搜索 addTextTab方法,找到方法在哪里被调用。 1 2 3 4 5 6 7 8 9 for (int i = 0; i < tabCount; i++) { if (pager.getAdapter() instanceof IconTabProvider) { addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i)); } else { addTextTab(i, pager.getAdapter().getPageTitle(i).toString()); } } 发现和ViewPager的适配器有关,而平常我们会使用PagerAdapter,所以addTextTab 会被调用。 4)于是在 addTextTab 方法添加子View的时候为子View添加了权重 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void addTextTab(final int position, String title) { TextView tab = new TextView(getContext()); tab.setText(title); tab.setFocusable(true); tab.setGravity(Gravity.CENTER); tab.setSingleLine(); //我给子View添加的权重 tab.setLayoutParams(new LinearLayout.LayoutParams(0,LayoutParams.MATCH_PARENT,1.0f)); tab.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { pager.setCurrentItem(position); } }); tabsContainer.addView(tab); } 5)但是遗憾的是,运行结果还是一个样。那怎么办? 后来在onMeasure方法中发现了惊天大秘密: 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 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (!shouldExpand || MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) { return; } int myWidth = getMeasuredWidth(); int childWidth = 0; for (int i = 0; i < tabCount; i++) { childWidth += tabsContainer.getChildAt(i).getMeasuredWidth(); } if (!checkedTabWidths && childWidth > 0 && myWidth > 0) { if (childWidth <= myWidth) { for (int i = 0; i < tabCount; i++) { tabsContainer.getChildAt(i).setLayoutParams(expandedTabLayoutParams); } } checkedTabWidths = true; } } 发现在此方法里其实就是对我所说的这个问题的控制,shouldExpand 就是控制标题是否平均分配 而这个属性在XML或者set方法里都可以设置。默认是false,不会平均分配。 虽然绕来绕去,改个属性就能解决问题,但还是收获不少。 3.PagerSlidingTab的其他属性 <declare-styleable name="PagerSlidingTab"> <attr name="indicatorColor" format="color" /> 指针也就是滑动块的颜色 <attr name="underlineColor" format="color" /> 滑动条与View之间那条线颜色 <attr name="underlineHeight" format="dimension" /> 滑动条与View之间那条线高度 <attr name="dividerColor" format="color" /> 滑动块之间竖直分隔线 <attr name="indicatorHeight" format="dimension" /> 滑动块的高度 <attr name="pst_dividerPadding" format="dimension" /> <attr name="tabPaddingLeftRight" format="dimension" /> <attr name="scrollOffset" format="dimension" /> <attr name="tabBackground" format="reference" /> <attr name="shouldExpand" format="boolean" /> 导航条是否平均分配宽度 <attr name="pst_textAllCaps" format="boolean" /> </declare-styleable> 还有和字体颜色和大小相关的属性,并没有写在attrs.xml中,不过可以通过set方法进行设置,上面 的属性也都有对应的set方法。 源码中 1 tab.setTextColor(i==0?getResources().getColor(R.color.slidingtab_indicatorcolor):tabTextColor); 就是设置字体的颜色,即当前导航条字体颜色与其它导航条字体颜色。 另外有一点让人费解的就是导航条的背景色怎么设置的? 1 app:tabBackground="@color/gray" 只要给导航条添加了背景色,下面的滑动块就不显示了,求路过的帮忙解答一下啊? 本文转自屠夫章哥 51CTO博客,原文链接:http://blog.51cto.com/4259297/1707011,如需转载请自行联系原作者
运维离不开自动化,python的发展更是给自动化注入了一剂兴奋剂;还记得当时公司年会,大家都在嗨皮,苦逼的运维攻城狮还在卖力的给一个大客户手动开通500台云主机的情形,现在想想好傻O(∩_∩)O哈哈~。如果早点接触pyVmomi,就不至于这么苦逼了。 pyVmomi is the Python SDK for the VMware vSphere API that allows you to manage ESX, ESXi, and vCenter.官方如是说。自己这里写篇博客整理一下,也希望对还停留在手工时代的同学有所帮助。 坏境配置: 1、网络环境: 安装pyvmomi的server和VMware vCenter 网络打通; 2、系统环境: pyvmomi用pip安装,所以需要有python和pip;pyvmomi 6.0.0需要的python版本支持为2.7, 3.3 和 3.4, 支持的vSphere 版本为:6.0, 5.5, 5.1 和 5.0。 安装如下: 1 2 3 4 $sudo apt-get install python-pip $sudo pip install pyvmomi $sudo pip freeze | grep pyvmomi #查看安装的pyvmomi版本,现在是6.0版本 pyvmomi==6.0.0 #如果已经安装过,升级用pip install --upgrade pyvmomi 或者也可以下载源码包安装,https://github.com/vmware/pyvmomi.git: 1 $sudo python setup.py install 3、pyvmomi提供了一些社区样本项目,可以参考编写自己的代码: 1 git clone https://github.com/vmware/pyvmomi-community-samples.git 4、下面是 pyvmomi给出的获取所有vm的脚本: 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 #!/usr/bin/env python # VMware vSphere Python SDK # Copyright (c) 2008-2015 VMware, Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Python program for listing the vms on an ESX / vCenter host """ from __future__ import print_function from pyVim.connect import SmartConnect, Disconnect import argparse import atexit import getpass import ssl def GetArgs(): """ Supports the command-line arguments listed below. """ parser = argparse.ArgumentParser( description='Process args for retrieving all the Virtual Machines') parser.add_argument('-s', '--host', required=True, action='store', help='Remote host to connect to') parser.add_argument('-o', '--port', type=int, default=443, action='store', help='Port to connect on') parser.add_argument('-u', '--user', required=True, action='store', help='User name to use when connecting to host') parser.add_argument('-p', '--password', required=False, action='store', help='Password to use when connecting to host') args = parser.parse_args() return args def PrintVmInfo(vm, depth=1): """ Print information for a particular virtual machine or recurse into a folder with depth protection """ maxdepth = 10 # if this is a group it will have children. if it does, recurse into them # and then return if hasattr(vm, 'childEntity'): if depth > maxdepth: return vmList = vm.childEntity for c in vmList: PrintVmInfo(c, depth+1) return summary = vm.summary print("Name : ", summary.config.name) print("Path : ", summary.config.vmPathName) print("Guest : ", summary.config.guestFullName) annotation = summary.config.annotation if annotation != None and annotation != "": print("Annotation : ", annotation) print("State : ", summary.runtime.powerState) if summary.guest != None: ip = summary.guest.ipAddress if ip != None and ip != "": print("IP : ", ip) if summary.runtime.question != None: print("Question : ", summary.runtime.question.text) print("") def main(): """ Simple command-line program for listing the virtual machines on a system. """ args = GetArgs() if args.password: password = args.password else: password = getpass.getpass(prompt='Enter password for host %s and ' 'user %s: ' % (args.host,args.user)) context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.verify_mode = ssl.CERT_NONE si = SmartConnect(host=args.host, user=args.user, pwd=password, port=int(args.port), sslContext=context) if not si: print("Could not connect to the specified host using specified " "username and password") return -1 atexit.register(Disconnect, si) content = si.RetrieveContent() for child in content.rootFolder.childEntity: if hasattr(child, 'vmFolder'): datacenter = child vmFolder = datacenter.vmFolder vmList = vmFolder.childEntity for vm in vmList: PrintVmInfo(vm) return 0 # Start program if __name__ == "__main__": main() 5、执行之后输出格式如下: 参考资料: http://vmware.github.io/pyvmomi-community-samples/#getting-started https://github.com/vmware/pyvmomi https://pypi.python.org/pypi/pyvmomi 本文转自Jx战壕 51CTO博客,原文链接:http://blog.51cto.com/xujpxm/1742101,如需转载请自行联系原作者
CentOS添加静态路由支持多网卡多网关 之前一直没有配置过两个网卡分别使用不同的IP,走不同的网关,google了下就有了下面的手工添加路由的脚本: #!/bin/sh ip route add 10.1.1.0/24 dev br0 src 10.1.1.10 table bond0 ip route add default via 10.1.1.1 dev br0 table bond0 ip rule add from 10.1.1.10/32 table bond0 ip rule add to 10.1.1.10/32 table bond0 ip route add 192.168.1.0/24 dev br1 src 192.168.1.10 table bond1 ip route add default via 192.168.1.1 dev br1 table bond1 ip rule add from 192.168.1.10/32 table bond1 ip rule add to 192.168.1.10/32 table bond1 后来想了想这样的问题系统肯定已经支持得很好了,只是没有找到配置方法,于是找了下红帽的文档,发现可以像下面这样配置: 配置静态路由 一个网卡的话不需要静态路由的,如果多个网卡的话可以手工配置静态路由,特别是多个网卡走不同的子网的时候。 route -n 查看当前路由信息 静态路由配置文件路径 /etc/sysconfig/network-scripts/route-interface_name 就和网卡的配置文件路径结构差不多,比如ifcfg-eth0变成了route-eth0 eth0网卡的静态路由就保存在这个文件里面。这个文件可以有两种格式:IP命令参数格式 和 网络/掩码指令格式 IP命令参数模式: 1)第一行定义默认路由: default via X.X.X.X dev interface X.X.X.X 是默认路由的IP. interface是可以连接到默认路由的网卡接口名. 2)静态路由一行一个: X.X.X.X/X via X.X.X.X dev interface X.X.X.X/X 是网络和掩码. X.X.X.X 和 interface 是各自网段的网关IP和网卡接口. 配置示例 route-eth0: 默认网关 192.168.0.1, 接口eth0. 两条静态路由到 10.10.10.0/24 和172.16.1.0/24 : default via 192.168.0.1 dev eth0 10.10.10.0/24 via 10.10.10.1 dev eth1 172.16.1.0/24 via 192.168.0.1 dev eth0 网络/掩码指令格式: route-interface文件的第二种格式.下面是样板: ADDRESS0=X.X.X.XNETMASK0=X.X.X.XGATEWAY0=X.X.X.X ADDRESS0=X.X.X.X静态路由的网络编号. NETMASK0=X.X.X.X 为上面那行设置子网掩码 . GATEWAY0=X.X.X.X 能够连接到 ADDRESS0=X.X.X.X 这个网络的网关 配置示例 route-eth0: 默认网关 192.168.0.1, 接口 eth0. 两条到10.10.10.0/24 和172.16.1.0/24 的静态路由: ADDRESS0=10.10.10.0 NETMASK0=255.255.255.0 GATEWAY0=10.10.10.1 ADDRESS1=172.16.1.0 NETMASK1=255.255.255.0 GATEWAY1=192.168.0.1 ADDRESS0, ADDRESS1, ADDRESS2, 这样的编号必须是一个接一个的数字. 如果有dhcp的话,配置静态路由没有必要的。 #!/bin/sh ip route add 125.77.198.192/27 dev em1 src 125.77.198.198 table dianxin ip route add default via 125.77.198.193 dev em1 table dianxin ip rule add from 125.77.198.198/32 table dianxin ip rule add to 125.77.198.198/32 table dianxin ip route add 36.250.75.192/26 dev em3 src 36.250.75.216 table liantong ip route add default via 36.250.75.193 dev em3 table liantong ip rule add from 36.250.75.216/32 table liantong ip rule add to 36.250.75.216/32 table liantong 本文转自flyingzf 51CTO博客,原文链接:http://blog.51cto.com/flyingzf/1329944,如需转载请自行联系原作者
已测试,兼容各浏览器。 第一个: <script language="JavaScript"> var timedate= new Date("January 1,2013"); var now = new Date(); var date = timedate.getTime() - now.getTime(); alert(now.getTime()); var startTime = new Date(); var EndTime=startTime.getTime()+60*1000; var submitcount = 1; function GetRTime(){ var NowTime = new Date(); var nMS =EndTime - NowTime.getTime(); var nH=Math.floor(nMS/(1000*60*60)) % 24; var nM=Math.floor(nMS/(1000*60)) % 60; var nS=Math.floor(nMS/1000) % 60; document.getElementById("RemainH").innerHTML=nH; document.getElementById("RemainM").innerHTML=nM; document.getElementById("RemainS").innerHTML=nS; if ((nM==0 && nS==0) || nS<0 || nM<0) { if (submitcount) { document.getElementById("allst").submit(); document.getElementById("jiaojuan").disabled='disabled'; submitcount=0; } }else{ if (submitcount) setTimeout("GetRTime()",1000); } } window.onload=GetRTime; </script> <b>还剩:</b><strong id="RemainH">0</strong>时<strong id="RemainM">0</strong>分<strong id="RemainS">0</strong>秒 第二个: <script type="text/javascript"> var $ = function(id){ return document.getElementById(id)}; function getDate(t){ with(t)return [getFullYear(),'年' ,('0'+(getMonth()+1)).slice(-2),'月' ,('0'+getDate()).slice(-2),'日 ' ,('0'+getHours()).slice(-2),': ' ,('0'+getMinutes()).slice(-2),': ' ,('0'+getSeconds()).slice(-2)].join(''); } function getDiffDate(m){ m-=(D=parseInt(m/86400000))*86400000; m-=(H=parseInt(m/3600000))*3600000; S=parseInt((m-=(M=parseInt(m/60000))*60000)/1000); return D+'天'+H+'时'+M+'分'+S+'秒'; } window.onload = function(){ setInterval(function(){ $("ospanTime").innerHTML = getDate(new Date()); $("diffTime").innerHTML = getDiffDate(new Date('2012/12/24')-new Date()); }, 1000); } </script> 当前时间:<span id="ospanTime" style="color:#FF0000;font-weight:bold"></span><br/> 距离2012年12月24日:<span id="diffTime" style="color:#FF0000;font-weight:bold"></span> 第三个(需要在<body>中加入onload调用): <html> <head> <title>倒计时测试</title> <!--倒计时设置代码--> <script language="JavaScript"> <!-- hide script from old browser var DifferenceHour = -1 var DifferenceMinute = -1 var DifferenceSecond = -1 var Tday = new Date("July 1, 2013 00:00:00") //**倒计时时间点-注意格式 var daysms = 24 * 60 * 60 * 1000 var hoursms = 60 * 60 * 1000 var Secondms = 60 * 1000 var microsecond = 1000 function clock() { var time = new Date() var hour = time.getHours() var minute = time.getMinutes() var second = time.getSeconds() var timevalue = ""+((hour > 12) ? hour-12:hour) timevalue +=((minute < 10) ? ":0":":")+minute timevalue +=((second < 10) ? ":0":":")+second timevalue +=((hour >12 ) ? " PM":" AM") // document.formnow.now.value = timevalue var convertHour = DifferenceHour var convertMinute = DifferenceMinute var convertSecond = DifferenceSecond var Diffms = Tday.getTime() - time.getTime() DifferenceHour = Math.floor(Diffms / daysms) Diffms -= DifferenceHour * daysms DifferenceMinute = Math.floor(Diffms / hoursms) Diffms -= DifferenceMinute * hoursms DifferenceSecond = Math.floor(Diffms / Secondms) Diffms -= DifferenceSecond * Secondms var dSecs = Math.floor(Diffms / microsecond) if(convertHour != DifferenceHour) document.formnow.dd.value=DifferenceHour if(convertMinute != DifferenceMinute) document.formnow.hh.value=DifferenceMinute if(convertSecond != DifferenceSecond) document.formnow.mm.value=DifferenceSecond document.formnow.ss.value=dSecs document.getElementById("ddd").innerHTML=DifferenceHour; document.getElementById("hhh").innerHTML=DifferenceMinute; document.getElementById("mmm").innerHTML=DifferenceSecond; document.getElementById("sss").innerHTML=dSecs; // document.formnow.Tnow.value= DifferenceHour DifferenceMinute + DifferenceSecond + dSecs setTimeout("clock()",1000) } // end hiding --> </script> </head> <!--BODY里面的ONLOAD注意--> <body onload="clock();return true"> <!--实现显示--> 距离2013.07.01活动结束还有: <div style="font-size:30px;background:#369"> <span id="ddd"></span>天<span id="hhh"></span>小时<span id="mm"></span>分钟<span id="ss"></span>秒 <form name="formnow"> <input name="dd" type="text" style="border:0; color:red; width:15px">天 <input name="hh" type="text" style="border:0; color:red; width:15px">时 <input name="mm" type="text" style="border:0; color:red; width:15px">分 <input name="ss" type="text" style="border:0; color:red; width:15px">秒 </form> </div> </body> </html> 07月17日 今天找到了一个更好的,分享(精确到毫秒,很酷): <script language="JavaScript"> function ShowTimes(){ var AfterTime= new Date("July 18 00:00:00 2012"); LeaveTime = AfterTime - new Date(); LeaveDays=Math.floor(LeaveTime/(1000*60*60*24));//天 LeaveHours=Math.floor(LeaveTime/(1000*60*60)%24);//时 LeaveMinutes=Math.floor(LeaveTime/(1000*60)%60);//分 LeaveSeconds=Math.floor(LeaveTime/1000%60);//秒 var c=new Date(); var q=c.getMilliseconds(); if(q<10){ //因为毫秒为一位数时只占一个字符位置,会让毫秒二字变动位置 q="00"+c.getMilliseconds(); } if(q>=10 && q<100){ //因为毫秒为两位数时只占两个字符位置,会让毫秒二字变动位置 q="0"+c.getMilliseconds(); } if(LeaveDays<0){ document.getElementById("tian").innerHTML='00'; } else{ document.getElementById("tian").innerHTML=LeaveDays; } if(LeaveHours<0){ document.getElementById("shi").innerHTML='00'; } else{ document.getElementById("shi").innerHTML=LeaveHours; } if(LeaveMinutes<0){ document.getElementById("fen").innerHTML='00'; } else{ document.getElementById("fen").innerHTML=LeaveMinutes; } if(LeaveSeconds<0){ document.getElementById("miao").innerHTML='00'; } else{ document.getElementById("miao").innerHTML=LeaveSeconds; } hxtime.innerHTML="<font color=red>"+LeaveDays+"</font>天<font color=red>"+LeaveHours+"</font>时<font color=red>"+LeaveMinutes+"</font>分<font color=red>"+LeaveSeconds+"</font>秒<font color=red>"+q+"</font>毫秒"; } setInterval(ShowTimes,10); </script> <div id="hxtime"></div> <div id="tian"></div> <div id="shi"></div> <div id="fen"></div> <div id="miao"></div> 本文转自许琴 51CTO博客,原文链接:http://blog.51cto.com/xuqin/914800,如需转载请自行联系原作者
php读取目录中所有文件名(含子目录) 比如discuz读取用户图像很有意思! 路径没有保存到数据库,而是直接读取某文件夹下的图片文件,当然图像的命名是有一定规则的 比如:uid:251210 那么此用户的图像地址是: http://www.xxx.com/uc/data/avatar/000/25/12/10_avatar_middle.jpg <?php /*方法一*/ /*$dir="./ext/"; $file=scandir($dir); print_r($file);*/ /*方法二*/ /*$dir = "./ext/"; if (is_dir($dir)) { if ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { echo "filename: $file : filetype: " . filetype($dir . $file) . "<br>"; } closedir($dh); } }*/ function searchDir($path,&$data){ if(is_dir($path)){ $dp=dir($path); while($file=$dp->read()){ if($file!='.'&& $file!='..'){ searchDir($path.'/'.$file,$data); } } $dp->close(); } if(is_file($path)){ $data[]=$path; } } function getDir($dir){ $data=array(); searchDir($dir,$data); return $data; } echo '<pre />'; print_r(getDir('./user')); echo '<pre />'; ?> 本文转自许琴 51CTO博客,原文链接:http://blog.51cto.com/xuqin/925496,如需转载请自行联系原作者
上传文件HTML的输入标签FILE类型中的名称后要加[],作用是在HTML中向PHP建立数组,比如名称为pictures,多文件引用名称则为pictures[],实例如下: 代码: <form action="upload.php" method="post" enctype="multipart/form-data"> <p> <input type="file" name="pictures[]" /><br /> <input type="file" name="pictures[]" /><br /> <input type="file" name="pictures[]" /><br /> <input type="submit" value="上传" /> </p> </form> //手册中实例。 利用HTML文件建立数组的方法手册中是这样讲解的: 要使你的 <form> 结果被当成 array 发送到 PHP 脚本,要对 <input>,<select> 或者 <textarea> 单元这样命名: <input name="MyArray[]" /> <input name="MyArray[]" /> <input name="MyArray[]" /> <input name="MyArray[]" /> 注意变量名后的方括号,这使其成为一个数组。 可以通过给不同的单元分配相同的名字来把单元分组到不同的数组里: <input name="MyArray[]" /> <input name="MyArray[]" /> <input name="MyOtherArray[]" /> <input name="MyOtherArray[]" /> 这将产生两个数组,MyArray 和 MyOtherArray,并发送给 PHP 脚本。 还可以给数组分配指定的键名: <input name="AnotherArray[]" /> <input name="AnotherArray[]" /> <input name="AnotherArray[email]" /> <input name="AnotherArray[phone]" /> AnotherArray 数组将包含键名 0,1,email 和 phone。 注意: 指定数组的键名是 HTML 的可选项。如果不指定键名,则数组被按照单元在表单中出现的顺序填充。第一个例子将包含键名 0,1,2,3。 以上HTML点击上传后,通过$_FILES超级全局变量进行读取,$_FILES将会把HTTP POST 方法传递上来的文件信息组合成数组,一个文件数组形式为二维。二个以上文件数组形式为三维。 $_FILES的使用方法: $_FILES['userfile']['name'] 客户端机器文件的原名称。 $_FILES['userfile']['type'] 文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是“image/gif”。不过此 MIME 类型在 PHP 端并不检查,因此不要想当然认为有这个值。 $_FILES['userfile']['size'] 已上传文件的大小,单位为字节。 $_FILES['userfile']['tmp_name'] 文件被上传后在服务端储存的临时文件名。 $_FILES['userfile']['error'] 下面是一个文件上传,此文件上传后$_FILES数组内将会产生其信息,因为是一个文件所以是二维的,为了便于大家理解我们将$_FILES用PRINT_R输出查看其结构。 HTML文件: 代码: <form action="upload.php" method="post" enctype="multipart/form-data"> <p> <input type="file" name="pictures" /><br /> <input type="submit" value="上传" /> </p> </form> PHP接收文件: 代码: <?php print_r($_FILES); ?> 将其令存为UPLOAD.PHP,运行上面的HTML选择一个文件上传,比如文件名为Thumbs.db,在IE浏览器内单击“查看”,“源代码”。显示如下: Array ( [pictures] => Array ( [name] => Thumbs.db //原文件名 [type] => application/octet-stream //文件类型 [tmp_name] => D:\EasyPHP\\tmp\php64.tmp //临时存储目录及文件名 [error] => 0 //错误代码 0为上传成功 [size] => 23040 //文件大小 ) )根据此信息,结合上面$_FILES的使用方法,大家应该能理解的更深刻一些。 下面看一下多文件上传,三个文件名分别为FILE1.TXT,FILE2.TXT,FILE3.TXT,然后用PRINT_R输出查看其结构: HTML文件代码: 代码: <form action="upload.php" method="post" enctype="multipart/form-data"> <p> <input type="file" name="pictures[]" /><br /> <input type="file" name="pictures[]" /><br /> <input type="file" name="pictures[]" /><br /> <input type="submit" value="上传" /> </p> </form> PHP接收文件代码: <?php print_r($_FILES); ?> 查看源文件: Array ( [pictures] => Array ( [name] => Array ( [0] => file1.txt [1] => file2.txt [2] => file3.txt ) [type] => Array ( [0] => application/octet-stream [1] => application/octet-stream [2] => application/octet-stream ) [tmp_name] => Array ( [0] => D:\EasyPHP\\tmp\php47.tmp [1] => D:\EasyPHP\\tmp\php48.tmp [2] => D:\EasyPHP\\tmp\php49.tmp ) [error] => Array ( [0] => 0 [1] => 0 [2] => 0 ) [size] => Array ( [0] => 94289 [1] => 65536 [2] => 102400 ) ) ) 假设名为 /file1.txt 和 /file2.txt 的文件被提交,则 $_FILES['pictures']['name'][0] 的值将是 file1.txt,而 $_FILES['pictures']['name'][1] 的值将是 file2.txt。类似的,$_FILES['file2.txt']['size'][0] 将包含文件 file1.txt 的大小,依此类推 本文转自许琴 51CTO博客,原文链接:http://blog.51cto.com/xuqin/926896,如需转载请自行联系原作者
ini_set (PHP 4, PHP 5) ini_set — 为一个配置选项设置值 string ini_set ( string $varname , string $newvalue ) 设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。 参数: varname 不是所有有效的选项都能够用 ini_set() 来改变的。 这里有个有效选项的清单附录。 newvalue 选项新的值。 返回值: 成功时返回旧的值,失败时返回 FALSE。 例子: 1 2 3 4 5 6 7 <?php echo ini_get('display_errors');//ini_get() - 获取一个配置选项的值 if (!ini_get('display_errors')) { ini_set('display_errors', '1'); } echo ini_get('display_errors'); ?> 这里有个有效选项的清单附录: php.ini 配置选项列表 可以在 php.ini 中使用下列配置选项对 PHP 进行配置。 “可修改范围”列决定了该配置选项在什么情况下可以被设置。查看配置可被设定范围列表查看具体定义。 配置选项名字默认可修改范围更新日志allow_call_time_pass_reference"1"PHP_INI_PERDIR在 PHP 4.0.0 时是 PHP_INI_ALL。 在 PHP 5.4.0 中移除该选项。allow_url_fopen"1"PHP_INI_SYSTEM在 PHP <= 4.3.4 时是 PHP_INI_ALL。allow_url_include"0"PHP_INI_ALL在 PHP 5 时是 PHP_INI_SYSTEM。 从 PHP 5.2.0 起可用。always_populate_raw_post_data"0"PHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_ALL。 从 PHP 4.1.0 起可用。apc.cache_by_default"1"PHP_INI_ALL在 APC <= 3.0.12 时是 PHP_INI_SYSTEM。 从 APC 3.0.0 起可用。apc.enabled"1"PHP_INI_SYSTEM在 APC 2 时是 PHP_INI_SYSTEM。 在 APC <= 3.0.12 时是 PHP_INI_ALL。apc.enable_cli"0"PHP_INI_SYSTEM从 APC 3.0.7 起可用。apc.file_update_protection"2"PHP_INI_SYSTEM从 APC 3.0.6 起可用。apc.filtersNULLPHP_INI_SYSTEMapc.gc_ttl"3600"PHP_INI_SYSTEMapc.include_once_override"0"PHP_INI_SYSTEM从 APC 3.0.12 起可用。apc.localcache"0"PHP_INI_SYSTEM从 APC 3.0.14 起可用。apc.localcache.size"512"PHP_INI_SYSTEM从 APC 3.0.14 起可用。apc.max_file_size"1M"PHP_INI_SYSTEM从 APC 3.0.7 起可用。apc.mmap_file_maskNULLPHP_INI_SYSTEMapc.num_files_hint"1000"PHP_INI_SYSTEMapc.optimization"0"PHP_INI_ALL在 APC 2 时是 PHP_INI_SYSTEM。 在 APC 3.0.13 中移除该选项。apc.report_autofilter"0"PHP_INI_SYSTEM从 APC 3.0.11 起可用。apc.rfc1867"0"PHP_INI_SYSTEM从 APC 3.0.13 起可用。apc.rfc1867_freq"0"PHP_INI_SYSTEMapc.rfc1867_name"APC_UPLOAD_PROGRESS"PHP_INI_SYSTEMapc.rfc1867_prefix"upload_"PHP_INI_SYSTEMapc.shm_segments"1"PHP_INI_SYSTEMapc.shm_size"30"PHP_INI_SYSTEMapc.slam_defense"0"PHP_INI_SYSTEM从 APC 3.0.0 起可用。apc.stat"1"PHP_INI_SYSTEM从 APC 3.0.10 起可用。apc.stat_ctime"0"PHP_INI_SYSTEM从 APC 3.0.13 起可用。apc.ttl"0"PHP_INI_SYSTEM从 APC 3.0.0 起可用。apc.user_entries_hint"4096"PHP_INI_SYSTEM从 APC 3.0.0 起可用。apc.user_ttl"0"PHP_INI_SYSTEM从 APC 3.0.0 起可用。apc.write_lock"1"PHP_INI_SYSTEM从 APC 3.0.11 起可用。apd.bitmask"0"PHP_INI_ALL在 apd 0.9 中移除该选项。apd.dumpdirNULLPHP_INI_ALLapd.statement_tracing"0"PHP_INI_ALL从 apd 0.9 起可用。arg_separator"&"PHP_INI_ALL在 PHP 4.0.6 中移除该选项。arg_separator.input"&"PHP_INI_PERDIR从 PHP 4.0.5 起可用。arg_separator.output"&"PHP_INI_ALL从 PHP 4.0.5 起可用。asp_tags"0"PHP_INI_PERDIR在 PHP 4.0.0 时是 PHP_INI_ALL。assert.active"1"PHP_INI_ALLassert.bail"0"PHP_INI_ALLassert.callbackNULLPHP_INI_ALLassert.quiet_eval"0"PHP_INI_ALLassert.warning"1"PHP_INI_ALLasync_send"0"PHP_INI_ALL从 PHP 4.2.0 起可用。 在 PHP 4.3.0 中移除该选项。auto_append_fileNULLPHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_ALL。auto_detect_line_endings"0"PHP_INI_ALL从 PHP 4.3.0 起可用。auto_globals_jit"1"PHP_INI_PERDIR从 PHP 5.0.0 起可用。auto_prepend_fileNULLPHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_ALL。axis2.client_home"~/work/axisc/c/deply"PHP_INI_ALLaxis2.enable_exception"1"PHP_INI_ALLaxis2.enable_trace"1"PHP_INI_ALLaxis2.log_path"/tmp"PHP_INI_ALLbcmath.scale"0"PHP_INI_ALLbcompiler.enabled"1"PHP_INI_ALL从 bcompiler 0.8 起可用。birdstep.max_links"-1"PHP_INI_ALL从 PHP 4.2.0 起可用。blenc.key_file"/usr/local/etc/blenckeys"PHP_INI_ALLbrowscapNULLPHP_INI_SYSTEMcgi.check_shebang_line"1"PHP_INI_SYSTEM从 PHP 5.2.1 起可用。cgi.discard_path"0"PHP_INI_SYSTEM从 PHP 5.3.0 起可用。cgi.fix_pathinfo"1"PHP_INI_SYSTEM在 PHP <= 5.2.0 时是 PHP_INI_ALL。 从 PHP 4.3.0 起可用。cgi.force_redirect"1"PHP_INI_SYSTEM在 PHP <= 5.2.0 时是 PHP_INI_ALL。 从 PHP 4.2.0 起可用。cgi.nph"0"PHP_INI_ALL从 PHP 4.3.5 起可用。cgi.redirect_status_envNULLPHP_INI_SYSTEM在 PHP <= 5.2.0 时是 PHP_INI_ALL。 从 PHP 4.2.0 起可用。cgi.rfc2616_headers"0"PHP_INI_ALL从 PHP 4.3.0 起可用。child_terminate"0"PHP_INI_ALL从 PHP 4.0.5 起可用。cli.pager""PHP_INI_ALL从 PHP 5.4.0 起可用。cli.prompt"\\b \\> "PHP_INI_ALL从 PHP 5.4.0 起可用。cli_server.color"0"PHP_INI_ALL从 PHP 5.4.0 起可用。coin_acceptor.autoreset"On"PHP_INI_ALL在 coin_acceptor 0.2 中移除该选项。coin_acceptor.auto_initialize"Off"PHP_INI_ALL从 coin_acceptor 0.2 起可用。coin_acceptor.auto_reset"On"PHP_INI_ALL从 coin_acceptor 0.2 起可用。coin_acceptor.command_function"Off"PHP_INI_ALL从 coin_acceptor 0.3 起可用。coin_acceptor.delay"53132"PHP_INI_ALL在 coin_acceptor 0.2 中移除该选项。coin_acceptor.delay_coins"53132"PHP_INI_ALL从 coin_acceptor 0.2 起可用。coin_acceptor.delay_prom"55748"PHP_INI_ALL从 coin_acceptor 0.2 起可用。coin_acceptor.device"/dev/ttyS1"PHP_INI_ALL在 coin_acceptor 0.2 中移除该选项。coin_acceptor.lock_on_close"Off"PHP_INI_ALL从 coin_acceptor 0.2 起可用。coin_acceptor.start_unlocked"On"PHP_INI_ALL从 coin_acceptor 0.2 起可用。com.allow_dcom"0"PHP_INI_SYSTEM从 PHP 4.0.5 起可用。com.autoregister_casesensitive"1"PHP_INI_ALL在 PHP 4 时是 PHP_INI_SYSTEM。从 PHP 4.1.0 起可用。com.autoregister_typelib"0"PHP_INI_ALL在 PHP 4 时是 PHP_INI_SYSTEM。 从 PHP 4.1.0 起可用。com.autoregister_verbose"0"PHP_INI_ALL在 PHP 4 时是 PHP_INI_SYSTEM。 从 PHP 4.1.0 起可用。com.code_page""PHP_INI_ALL从 PHP 5.0.0 起可用。com.typelib_file""PHP_INI_SYSTEM从 PHP 4.0.5 起可用。crack.default_dictionaryNULLPHP_INI_PERDIR在 crack <= 0.2 时是 PHP_INI_SYSTEM。 从 PHP 4.0.5 起可用。 在 PHP 5.0.0 中移除该选项。daffodildb.default_host"localhost"PHP_INI_ALLdaffodildb.default_password"daffodil"PHP_INI_ALLdaffodildb.default_socketNULLPHP_INI_ALLdaffodildb.default_user"DAFFODIL"PHP_INI_ALLdaffodildb.port"3456"PHP_INI_ALLdate.default_latitude"31.7667"PHP_INI_ALL从 PHP 5.0.0 起可用。date.default_longitude"35.2333"PHP_INI_ALL从 PHP 5.0.0 起可用。date.sunrise_zenith"90.583333"PHP_INI_ALL从 PHP 5.0.0 起可用。date.sunset_zenith"90.583333"PHP_INI_ALL从 PHP 5.0.0 起可用。date.timezone""PHP_INI_ALL从 PHP 5.1.0 起可用。dba.default_handler""PHP_INI_ALL从 PHP 4.3.3 起可用。dbx.colnames_case"unchanged"PHP_INI_SYSTEM从 PHP 4.3.0 起可用。 在 PHP 5.1.0 中移除该选项。default_charset""PHP_INI_ALLdefault_mimetype"text/html"PHP_INI_ALLdefault_socket_timeout"60"PHP_INI_ALL从 PHP 4.3.0 起可用。define_syslog_variables"0"PHP_INI_ALL在 PHP 5.4.0 中移除该选项。detect_unicode"1"PHP_INI_ALL从 PHP 5.1.0 起可用。 本过时特性将肯定会在未来被移除。disable_classes""php.ini only从 PHP 4.3.2 起可用。disable_functions""php.ini only从 PHP 4.0.1 起可用。display_errors"1"PHP_INI_ALLdisplay_startup_errors"0"PHP_INI_ALL从 PHP 4.0.3 起可用。docref_ext""PHP_INI_ALL从 PHP 4.3.2 起可用。docref_root""PHP_INI_ALL从 PHP 4.3.0 起可用。doc_rootNULLPHP_INI_SYSTEMenable_dl"1"PHP_INI_SYSTEM本过时特性将肯定会在未来被移除。engine"1"PHP_INI_ALL从 PHP 4.0.5 起可用。error_append_stringNULLPHP_INI_ALLerror_logNULLPHP_INI_ALLerror_prepend_stringNULLPHP_INI_ALLerror_reportingNULLPHP_INI_ALLetpan.default.charset"utf-8"PHP_INI_ALLetpan.default.protocol"imap"PHP_INI_ALLexif.decode_jis_intel"JIS"PHP_INI_ALL从 PHP 4.3.0 起可用。exif.decode_jis_motorola"JIS"PHP_INI_ALL从 PHP 4.3.0 起可用。exif.decode_unicode_intel"UCS-2LE"PHP_INI_ALL从 PHP 4.3.0 起可用。exif.decode_unicode_motorola"UCS-2BE"PHP_INI_ALL从 PHP 4.3.0 起可用。exif.encode_jis""PHP_INI_ALL从 PHP 4.3.0 起可用。exif.encode_unicode"ISO-8859-15"PHP_INI_ALL从 PHP 4.3.0 起可用。exit_on_timeout""PHP_INI_ALL从 PHP 5.3 起可用。0expect.logfile""PHP_INI_ALLexpect.loguser"1"PHP_INI_ALLexpect.timeout"10"PHP_INI_ALLexpose_php"1"php.ini onlyextensionNULLphp.ini onlyextension_dir"/path/to/php"PHP_INI_SYSTEMfastcgi.impersonate"0"PHP_INI_SYSTEM在 PHP <= 5.2.0 时是 PHP_INI_ALL。 从 PHP 4.3.0 起可用。fastcgi.logging"1"PHP_INI_SYSTEM在 PHP <= 5.2.0 时是 PHP_INI_ALL。 从 PHP 4.4.0 起可用。fbsql.allow_persistant"1"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。 在 PHP 4.2.0 中移除该选项。fbsql.allow_persistent"1"PHP_INI_SYSTEM从 PHP 4.2.0 起可用。fbsql.autocommit"1"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.batchSize"1000"PHP_INI_SYSTEM从 PHP 4.2.0 起可用。 在 PHP 5.1.0 中移除该选项。fbsql.batchsize"1000"PHP_INI_ALL从 PHP 5.1.0 起可用。fbsql.default_database""PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.default_database_password""PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.default_hostNULLPHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.default_password""PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.default_user"_SYSTEM"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.generate_warnings"0"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.max_connections"128"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.max_links"128"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.max_persistent"-1"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.max_results"128"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。fbsql.mbatchSize"1000"PHP_INI_SYSTEM从 PHP 4.0.6 起可用。 在 PHP 4.2.0 中移除该选项。fbsql.show_timestamp_decimals"0"PHP_INI_SYSTEM从 PHP 5.1.5 起可用。file_uploads"1"PHP_INI_SYSTEM在 PHP <= 4.2.3 时是 PHP_INI_ALL。 从 PHP 4.0.3 起可用。filter.default"unsafe_raw"PHP_INI_PERDIR在 filter <= 0.9.4 时是 PHP_INI_ALL。 从 PHP 5.2.0 起可用。filter.default_flagsNULLPHP_INI_PERDIR在 filter <= 0.9.4 时是 PHP_INI_ALL。 从 PHP 5.2.0 起可用。from""PHP_INI_ALLgd.jpeg_ignore_warning"0"PHP_INI_ALL从 PHP 5.1.3 起可用。geoip.custom_directoryNULLPHP_INI_ALL从 geoip 1.0.1 起可用。geoip.database_standard"GeoIP.dat"PHP_INI_ALL在 geoip 1.0.1 中移除该选项。gpc_order"GPC"PHP_INI_ALL在 PHP 5.0.0 中移除该选项。hidef.ini_path(char*)default_ini_pathPHP_INI_SYSTEMhighlight.bg"#FFFFFF"PHP_INI_ALL在 PHP 5.4.0 中移除该选项。highlight.comment"#FF8000"PHP_INI_ALLhighlight.default"#0000BB"PHP_INI_ALLhighlight.html"#000000"PHP_INI_ALLhighlight.keyword"#007700"PHP_INI_ALLhighlight.string"#DD0000"PHP_INI_ALLhtml_errors"1"PHP_INI_ALL在 PHP <= 4.2.3 时是 PHP_INI_SYSTEM。 从 PHP 4.0.2 起可用。htscanner.config_file".htaccess"PHP_INI_SYSTEMhtscanner.default_docroot"/"PHP_INI_SYSTEMhtscanner.default_ttl"300"PHP_INI_SYSTEM从 htscanner 0.6.0 起可用。htscanner.stop_on_error"0"PHP_INI_SYSTEM从 htscanner 0.7.0 起可用。http.allowed_methods""PHP_INI_ALLAvailable since pecl_http 0.4.0. 在 pecl_http 1.0.0 中移除该选项。http.allowed_methods_log""PHP_INI_ALLAvailable since pecl_http 0.12.0. 在 pecl_http 1.0.0 中移除该选项。http.cache_log""PHP_INI_ALLAvailable since pecl_http 0.8.0. 在 pecl_http 1.0.0 中移除该选项。http.composite_log""PHP_INI_ALLAvailable since pecl_http 0.12.0. 在 pecl_http 1.0.0 中移除该选项。http.etag.mode"MD5"PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.etag_mode"MD5"PHP_INI_ALLAvailable since pecl_http 0.12.0. 在 pecl_http 1.0.0 中移除该选项。http.force_exit"1"PHP_INI_ALL从 pecl_http 0.18.0 起可用。http.log.allowed_methods""PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.log.cache""PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.log.composite""PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.log.not_found""PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.log.redirect""PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.ob_deflate_auto"0"PHP_INI_PERDIRAvailable since pecl_http 0.21.0. 在 pecl_http 1.0.0 中移除该选项。http.ob_deflate_flags"0"PHP_INI_ALLAvailable since pecl_http 0.21.0. 在 pecl_http 1.0.0 中移除该选项。http.ob_inflate_auto"0"PHP_INI_PERDIRAvailable since pecl_http 0.21.0. 在 pecl_http 1.0.0 中移除该选项。http.ob_inflate_flags"0"PHP_INI_ALLAvailable since pecl_http 0.21.0. 在 pecl_http 1.0.0 中移除该选项。http.only_exceptions"0"PHP_INI_ALL从 pecl_http 0.11.0 起可用。http.persistent.handles.ident"GLOBAL"PHP_INI_ALL从 pecl_http 1.5.0 起可用。http.persistent.handles.limit"-1"PHP_INI_SYSTEM从 pecl_http 1.5.0 起可用。http.redirect_log""PHP_INI_ALLAvailable since pecl_http 0.12.0. 在 pecl_http 1.0.0 中移除该选项。http.request.datashare.connect"0"PHP_INI_SYSTEM从 pecl_http 1.3.0 起可用。http.request.datashare.cookie"0"PHP_INI_SYSTEM从 pecl_http 1.3.0 起可用。http.request.datashare.dns"1"PHP_INI_SYSTEM从 pecl_http 1.3.0 起可用。http.request.datashare.ssl"0"PHP_INI_SYSTEM从 pecl_http 1.3.0 起可用。http.request.methods.allowed""PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.request.methods.custom""PHP_INI_PERDIR从 pecl_http 1.0.0 起可用。http.send.deflate.start_auto"0"PHP_INI_PERDIR从 pecl_http 1.0.0 起可用。http.send.deflate.start_flags"0"PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.send.inflate.start_auto"0"PHP_INI_PERDIR从 pecl_http 1.0.0 起可用。http.send.inflate.start_flags"0"PHP_INI_ALL从 pecl_http 1.0.0 起可用。http.send.not_found_404"1"PHP_INI_ALL从 pecl_http 1.0.0 起可用。hyerwave.allow_persistent"0"PHP_INI_SYSTEM在 PHP 4.3.2 中移除该选项。hyperwave.allow_persistent"0"PHP_INI_SYSTEM从 PHP 4.3.2 起可用。 在 PHP 5.0.0 中移除该选项。hyperwave.default_port"418"PHP_INI_ALL在 PHP 5.0.0 中移除该选项。ibase.allow_persistent"1"PHP_INI_SYSTEMibase.dateformat"%Y-%m-%d"PHP_INI_ALLibase.default_charsetNULLPHP_INI_ALL从 PHP 5.0.0 起可用。ibase.default_dbNULLPHP_INI_SYSTEM从 PHP 5.0.0 起可用。ibase.default_passwordNULLPHP_INI_ALLibase.default_userNULLPHP_INI_ALLibase.max_links"-1"PHP_INI_SYSTEMibase.max_persistent"-1"PHP_INI_SYSTEMibase.timeformat"%H:%M:%S"PHP_INI_ALLibase.timestampformat"%Y-%m-%d %H:%M:%S"PHP_INI_ALLibm_db2.binmode"1"PHP_INI_ALLibm_db2.i5_allow_commit"0"PHP_INI_SYSTEM从 ibm_db2 1.4.9 起可用。ibm_db2.i5_dbcs_alloc"0"PHP_INI_SYSTEM从 ibm_db2 1.5.0 起可用。ibm_db2.instance_nameNULLPHP_INI_SYSTEM从 ibm_db2 1.0.2 起可用。iconv.input_encoding"ISO-8859-1"PHP_INI_ALL从 PHP 4.0.5 起可用。iconv.internal_encoding"ISO-8859-1"PHP_INI_ALL从 PHP 4.0.5 起可用。iconv.output_encoding"ISO-8859-1"PHP_INI_ALL从 PHP 4.0.5 起可用。ifx.allow_persistent"1"PHP_INI_SYSTEM在 PHP 5.2.1 中移除该选项。ifx.blobinfile"1"PHP_INI_ALL在 PHP 5.2.1 中移除该选项。ifx.byteasvarchar"0"PHP_INI_ALL在 PHP 5.2.1 中移除该选项。ifx.charasvarchar"0"PHP_INI_ALL在 PHP 5.2.1 中移除该选项。ifx.default_hostNULLPHP_INI_SYSTEM在 PHP 5.2.1 中移除该选项。ifx.default_passwordNULLPHP_INI_SYSTEM在 PHP 5.2.1 中移除该选项。ifx.default_userNULLPHP_INI_SYSTEM在 PHP 5.2.1 中移除该选项。ifx.max_links"-1"PHP_INI_SYSTEM在 PHP 5.2.1 中移除该选项。ifx.max_persistent"-1"PHP_INI_SYSTEM在 PHP 5.2.1 中移除该选项。ifx.nullformat"0"PHP_INI_ALL在 PHP 5.2.1 中移除该选项。ifx.textasvarchar"0"PHP_INI_ALL在 PHP 5.2.1 中移除该选项。ignore_repeated_errors"0"PHP_INI_ALL从 PHP 4.3.0 起可用。ignore_repeated_source"0"PHP_INI_ALL从 PHP 4.3.0 起可用。ignore_user_abort"0"PHP_INI_ALLimlib2.font_cache_max_size"524288"PHP_INI_ALLimlib2.font_path"/usr/share/php/fonts/"PHP_INI_ALLimplicit_flush"0"PHP_INI_ALL在 PHP <= 4.2.3 时是 PHP_INI_PERDIR。include_path".;/path/to/php/pear"PHP_INI_ALLingres.allow_persistent"1"PHP_INI_SYSTEM从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。ingres.array_index_start"1"PHP_INI_ALL从 ingres 1.4.0 起可用。ingres.blob_segment_length"4096"PHP_INI_ALL从 ingres 1.2.0 起可用。ingres.cursor_mode"0"PHP_INI_ALL从 ingres 1.1 起可用。ingres.default_databaseNULLPHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。ingres.default_passwordNULLPHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。ingres.default_userNULLPHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。ingres.max_links"-1"PHP_INI_SYSTEM从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。ingres.max_persistent"-1"PHP_INI_SYSTEM从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。ingres.report_db_warnings"1"PHP_INI_ALL从 ingres 1.1 起可用。ingres.timeout"-1"PHP_INI_ALL从 ingres 1.4.0 起可用。ingres.trace_connect"0"PHP_INI_ALL从 ingres 1.2.1 起可用。ircg.control_user"nobody"PHP_INI_ALL从 PHP 5.0.0 起可用。 在 PHP 5.1.0 中移除该选项。ircg.keep_alive_interval"60"PHP_INI_ALL从 PHP 5.0.0 起可用。 在 PHP 5.1.0 中移除该选项。ircg.max_format_message_sets"12"PHP_INI_ALL从 PHP 5.0.0 起可用。 在 PHP 5.1.0 中移除该选项。ircg.shared_mem_size"6000000"PHP_INI_ALL从 PHP 5.0.0 起可用。 在 PHP 5.1.0 中移除该选项。ircg.work_dir"/tmp/ircg"PHP_INI_ALL从 PHP 5.0.0 起可用。 在 PHP 5.1.0 中移除该选项。last_modified"0"PHP_INI_ALL从 PHP 4.0.5 起可用。ldap.base_dnNULLPHP_INI_ALL在 PHP 4.2.0 中移除该选项。ldap.max_links"-1"PHP_INI_SYSTEMlog.dbm_dir""PHP_INI_ALL在 PHP 4.0.1 中移除该选项。log_errors"0"PHP_INI_ALLlog_errors_max_len"1024"PHP_INI_ALL从 PHP 4.3.0 起可用。magic_quotes_gpc"1"PHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_ALL。 从 PHP 5.3.0 起不推荐使用。 在 PHP 5.4.0 中移除该选项。magic_quotes_runtime"0"PHP_INI_ALL在 PHP 5.4.0 中移除该选项。magic_quotes_sybase"0"PHP_INI_ALL在 PHP 5.4.0 中移除该选项。mail.add_x_header"0"PHP_INI_PERDIR从 PHP 5.3.0 起可用。mail.force_extra_parametersNULLphp.ini only从 PHP 5.0.0 起可用。mail.log""PHP_INI_ALL从 PHP 5.3.0 起可用。mailparse.def_charset"us-ascii"PHP_INI_ALL从 PHP 4.1.0 起可用。 在 PHP 4.2.0 中移除该选项。maxdb.default_dbNULLPHP_INI_ALLmaxdb.default_hostNULLPHP_INI_ALLmaxdb.default_pwNULLPHP_INI_ALLmaxdb.default_userNULLPHP_INI_ALLmaxdb.long_readlen"200"PHP_INI_ALLmax_execution_time"30"PHP_INI_ALLmax_input_nesting_level"64"PHP_INI_PERDIR从 PHP 4.4 起可用。8 and PHP 5.2.3.max_input_vars1000PHP_INI_PERDIR从 PHP 5.3.9 起可用。max_input_time"-1"PHP_INI_PERDIR从 PHP 4.3.0 起可用。mbstring.detect_orderNULLPHP_INI_ALL从 PHP 4.0.6 起可用。mbstring.encoding_translation"0"PHP_INI_PERDIR从 PHP 4.3.0 起可用。mbstring.func_overload"0"PHP_INI_SYSTEM在 PHP <= 4.2.3 时是 PHP_INI_SYSTEM;从 PHP 4.3 起可用于 PHP_INI_SYSTEM | PHP_INI_PERDIR 。 through 5.2.6. 从 PHP 4.2.0 起可用。mbstring.http_input"pass"PHP_INI_ALL从 PHP 4.0.6 起可用。mbstring.http_output"pass"PHP_INI_ALL从 PHP 4.0.6 起可用。mbstring.internal_encodingNULLPHP_INI_ALL从 PHP 4.0.6 起可用。mbstring.language"neutral"PHP_INI_ALL 从 PHP 4.3.0 起可用;在 PHP <= 5.2.6 时是 PHP_INI_PERDIR 。 mbstring.script_encodingNULLPHP_INI_ALL从 PHP 4.3.0 起可用。mbstring.strict_detection"0"PHP_INI_ALL从 PHP 5.1.2 起可用。mbstring.substitute_characterNULLPHP_INI_ALL从 PHP 4.0.6 起可用。mcrypt.algorithms_dirNULLPHP_INI_ALL从 PHP 4.0.2 起可用。mcrypt.modes_dirNULLPHP_INI_ALL从 PHP 4.0.2 起可用。memcache.allow_failover"1"PHP_INI_ALL从 memcache 2.0.2 起可用。memcache.chunk_size"8192"PHP_INI_ALL从 memcache 2.0.2 起可用。memcache.default_port"11211"PHP_INI_ALL从 memcache 2.0.2 起可用。memcache.hash_function"crc32"PHP_INI_ALL从 memcache 2.2.0 起可用。memcache.hash_strategy"standard"PHP_INI_ALL从 memcache 2.2.0 起可用。memcache.max_failover_attempts"20"PHP_INI_ALL从 memcache 2.1.0 起可用。memory_limit"128M"PHP_INI_ALLmime_magic.debug"0"PHP_INI_SYSTEM从 PHP 5.0.0 起可用。mime_magic.magicfile"/path/to/php/magic.mime"PHP_INI_SYSTEM从 PHP 4.3.0 起可用。msql.allow_persistent"1"PHP_INI_ALLmsql.max_links"-1"PHP_INI_ALLmsql.max_persistent"-1"PHP_INI_ALLmssql.allow_persistent"1"PHP_INI_SYSTEMmssql.batchsize"0"PHP_INI_ALL从 PHP 4.0.4 起可用。mssql.charset""PHP_INI_ALL从 PHP 5.1.2 起可用。mssql.compatability_mode"0"PHP_INI_ALLmssql.connect_timeout"5"PHP_INI_ALLmssql.datetimeconvert"1"PHP_INI_ALL从 PHP 4.2.0 起可用。mssql.max_links"-1"PHP_INI_SYSTEMmssql.max_persistent"-1"PHP_INI_SYSTEMmssql.max_procs"-1"PHP_INI_ALL从 PHP 4.3.0 起可用。mssql.min_error_severity"10"PHP_INI_ALLmssql.min_message_severity"10"PHP_INI_ALLmssql.secure_connection"0"PHP_INI_SYSTEM从 PHP 4.3.0 起可用。mssql.textlimit"-1"PHP_INI_ALLmssql.textsize"-1"PHP_INI_ALLmssql.timeout"60"PHP_INI_ALL从 PHP 4.1.0 起可用。mysql.allow_persistent"1"PHP_INI_SYSTEMmysql.connect_timeout"60"PHP_INI_ALL在 PHP <= 4.3.2 时是 PHP_INI_SYSTEM。 从 PHP 4.3.0 起可用。mysql.default_hostNULLPHP_INI_ALLmysql.default_passwordNULLPHP_INI_ALLmysql.default_portNULLPHP_INI_ALLmysql.default_socketNULLPHP_INI_ALL从 PHP 4.0.1 起可用。mysql.default_userNULLPHP_INI_ALLmysql.max_links"-1"PHP_INI_SYSTEMmysql.max_persistent"-1"PHP_INI_SYSTEMmysql.trace_mode"0"PHP_INI_ALL从 PHP 4.3.0 起可用。mysqli.default_hostNULLPHP_INI_ALL从 PHP 5.0.0 起可用。mysqli.default_port"3306"PHP_INI_ALL从 PHP 5.0.0 起可用。mysqli.default_pwNULLPHP_INI_ALL从 PHP 5.0.0 起可用。mysqli.default_socketNULLPHP_INI_ALL从 PHP 5.0.0 起可用。mysqli.default_userNULLPHP_INI_ALL从 PHP 5.0.0 起可用。mysqli.max_links"-1"PHP_INI_SYSTEM从 PHP 5.0.0 起可用。mysqli.reconnect"0"PHP_INI_SYSTEM从 PHP 5.0.0 起可用。namazu.debugmode"0"PHP_INI_ALLnamazu.langNULLPHP_INI_ALLnamazu.loggingmode"0"PHP_INI_ALLnamazu.sortmethodNULLPHP_INI_ALLnamazu.sortorderNULLPHP_INI_ALLnsapi.read_timeout"60"PHP_INI_ALL从 PHP 4.3.3 起可用。oci8.default_prefetch"10"PHP_INI_SYSTEM从 PHP 5.1.2 起可用。oci8.max_persistent"-1"PHP_INI_SYSTEM从 PHP 5.1.2 起可用。oci8.old_oci_close_semantics"0"PHP_INI_SYSTEM从 PHP 5.1.2 起可用。oci8.persistent_timeout"-1"PHP_INI_SYSTEM从 PHP 5.1.2 起可用。oci8.ping_interval"60"PHP_INI_SYSTEM从 PHP 5.1.2 起可用。oci8.privileged_connect"0"PHP_INI_SYSTEM从 PHP 5.1.2 起可用。oci8.statement_cache_size"20"PHP_INI_SYSTEM从 PHP 5.1.2 起可用。odbc.allow_persistent"1"PHP_INI_SYSTEModbc.check_persistent"1"PHP_INI_SYSTEModbc.defaultbinmode"1"PHP_INI_ALLodbc.defaultlrl"4096"PHP_INI_ALLodbc.default_dbNULLPHP_INI_ALLodbc.default_pwNULLPHP_INI_ALLodbc.default_userNULLPHP_INI_ALLodbc.max_links"-1"PHP_INI_SYSTEModbc.max_persistent"-1"PHP_INI_SYSTEModbtp.datetime_format"object"PHP_INI_ALLodbtp.detach_default_queries"0"PHP_INI_ALLodbtp.guid_format"string"PHP_INI_ALL从 odbtp 1.1.3 起可用。odbtp.interface_file"/usr/local/share/odbtp.conf"PHP_INI_ALLodbtp.truncation_errors"1"PHP_INI_ALLopendirectory.default_separator"/"PHP_INI_ALL在 opendirectory 0.2.2 中移除该选项。opendirectory.max_refs"-1"PHP_INI_ALLopendirectory.separator"/"PHP_INI_ALL从 opendirectory 0.2.2 起可用。open_basedirNULLPHP_INI_ALL在 PHP < 5.2.3 时是 PHP_INI_SYSTEM。oracle.allow_persistent"-1"PHP_INI_ALL在 PHP 5.1.0 中移除该选项。oracle.max_links"-1"PHP_INI_ALL在 PHP 5.1.0 中移除该选项。oracle.max_persistent"-1"PHP_INI_ALL在 PHP 5.1.0 中移除该选项。output_buffering"0"PHP_INI_PERDIRoutput_handlerNULLPHP_INI_PERDIR从 PHP 4.0.4 起可用。pam.servicename"php"PHP_INI_ALLpcre.backtrack_limit"1000000"PHP_INI_ALL从 PHP 5.2.0 起可用。pcre.recursion_limit"100000"PHP_INI_ALL从 PHP 5.2.0 起可用。pdo.dsn.*php.ini only从 PHP 5.1.0 起可用。pdo_odbc.connection_pooling"strict"PHP_INI_ALL从 PHP 5.1.0 起可用。pdo_odbc.db2_instance_nameNULLPHP_INI_SYSTEM从 PHP 5.1.1 起可用。 本过时特性将肯定会在未来被移除。pfpro.defaulthost"test-payflow.verisign.com"PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。pfpro.defaultport"443"PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。pfpro.defaulttimeout"30"PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。pfpro.proxyaddress""PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。pfpro.proxylogon""PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。pfpro.proxypassword""PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。pfpro.proxyport""PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 5.1.0 中移除该选项。pgsql.allow_persistent"1"PHP_INI_SYSTEMpgsql.auto_reset_persistent"0"PHP_INI_SYSTEM从 PHP 4.2.0 起可用。pgsql.ignore_notice"0"PHP_INI_ALL从 PHP 4.3.0 起可用。pgsql.log_notice"0"PHP_INI_ALL从 PHP 4.3.0 起可用。pgsql.max_links"-1"PHP_INI_SYSTEMpgsql.max_persistent"-1"PHP_INI_SYSTEMphar.extract_list""PHP_INI_ALL从 phar 1.1.0 起可用。phar.readonly"1"PHP_INI_ALLphar.require_hash"1"PHP_INI_ALLenable_post_data_readingOnPHP_INI_PERDIR从 PHP 5.4.0 起可用。post_max_size"8M"PHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_SYSTEM。 从 PHP 4.0.3 起可用。precision"14"PHP_INI_ALLprinter.default_printer""PHP_INI_ALL从 PHP 4.0.6 起可用。 在 PHP 4.1.1 中移除该选项。python.append_path""PHP_INI_ALLpython.prepend_path"."PHP_INI_ALLrealpath_cache_size"16K"PHP_INI_SYSTEM从 PHP 5.1.0 起可用。realpath_cache_ttl"120"PHP_INI_SYSTEM从 PHP 5.1.0 起可用。register_argc_argv"1"PHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_ALL。register_globals"0"PHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_ALL。 从 PHP 5.3.0 起不推荐使用。 在 PHP 5.4.0 中移除该选项。register_long_arrays"1"PHP_INI_PERDIR从 PHP 5.0.0 起可用。 从 PHP 5.3.0 起不推荐使用。在 PHP 5.4.0 中移除该选项。report_memleaks"1"PHP_INI_ALL从 PHP 4.3.0 起可用。report_zend_debug"1"PHP_INI_ALL从 PHP 5.0.0 起可用。request_order""PHP_INI_PERDIR在 PHP 5.3.0 时增加runkit.internal_override"0"PHP_INI_SYSTEMrunkit.superglobal""PHP_INI_PERDIRsafe_mode"0"PHP_INI_SYSTEM在 PHP 5.4.0 中移除该选项。safe_mode_allowed_env_vars"PHP_"PHP_INI_SYSTEM在 PHP 5.4.0 中移除该选项。safe_mode_exec_dir""PHP_INI_SYSTEM在 PHP 5.4.0 中移除该选项。safe_mode_gid"0"PHP_INI_SYSTEM从 PHP 4.1.0 起可用。 在 PHP 5.4.0 中移除该选项。safe_mode_include_dirNULLPHP_INI_SYSTEM从 PHP 4.1.0 起可用。 在 PHP 5.4.0 中移除该选项。safe_mode_protected_env_vars"LD_LIBRARY_PATH"PHP_INI_SYSTEM在 PHP 5.4.0 中移除该选项。sendmail_fromNULLPHP_INI_ALLsendmail_path"/usr/sbin/sendmail -t -i"PHP_INI_SYSTEMserialize_precision"17"PHP_INI_ALL 从 PHP 4.3.2 起可用。 Until PHP 5.3.5, the default value was 100. session.auto_start"0"PHP_INI_ALLsession.bug_compat_42"1"PHP_INI_ALL从 PHP 4.3.0 起可用。 在 PHP 5.4.0 中移除该选项。session.bug_compat_warn"1"PHP_INI_ALL从 PHP 4.3.0 起可用。 在 PHP 5.4.0 中移除该选项。session.cache_expire"180"PHP_INI_ALLsession.cache_limiter"nocache"PHP_INI_ALLsession.cookie_domain""PHP_INI_ALLsession.cookie_httponly""PHP_INI_ALL从 PHP 5.2.0 起可用。session.cookie_lifetime"0"PHP_INI_ALLsession.cookie_path"/"PHP_INI_ALLsession.cookie_secure""PHP_INI_ALL从 PHP 4.0.4 起可用。session.entropy_file""PHP_INI_ALLsession.entropy_length"0"PHP_INI_ALLsession.gc_dividend"100"PHP_INI_ALL从 PHP 4.3.0 起可用。 在 PHP 4.3.2 中移除该选项。session.gc_divisor"100"PHP_INI_ALL从 PHP 4.3.2 起可用。session.gc_maxlifetime"1440"PHP_INI_ALLsession.gc_probability"1"PHP_INI_ALLsession.hash_bits_per_character"4"PHP_INI_ALL从 PHP 5.0.0 起可用。session.hash_function"0"PHP_INI_ALL从 PHP 5.0.0 起可用。session.name"PHPSESSID"PHP_INI_ALLsession.referer_check""PHP_INI_ALLsession.save_handler"files"PHP_INI_ALLsession.save_path""PHP_INI_ALLsession.serialize_handler"php"PHP_INI_ALLsession.use_cookies"1"PHP_INI_ALLsession.use_only_cookies"1"PHP_INI_ALL从 PHP 4.3.0 起可用。session.use_trans_sid"0"PHP_INI_ALL在 PHP <= 4.2.3 时是 PHP_INI_ALL。 在 PHP < 5 时是 PHP_INI_PERDIR。 从 PHP 4.0.3 起可用。session_pgsql.create_table"1"PHP_INI_SYSTEMsession_pgsql.db"host=localhost dbname=php_session user=nobody"PHP_INI_SYSTEMsession_pgsql.disable"0"PHP_INI_SYSTEMsession_pgsql.failover_mode"0"PHP_INI_SYSTEMsession_pgsql.gc_interval"3600"PHP_INI_SYSTEMsession_pgsql.keep_expired"0"PHP_INI_SYSTEMsession_pgsql.sem_file_name"/tmp/php_session_pgsql"PHP_INI_SYSTEMsession_pgsql.serializable"0"PHP_INI_SYSTEMsession_pgsql.short_circuit"0"PHP_INI_SYSTEMsession_pgsql.use_app_vars"0"PHP_INI_SYSTEMsession_pgsql.vacuum_interval"21600"PHP_INI_SYSTEMshort_open_tag"1"PHP_INI_ALL在 PHP 4.0.0 时是 PHP_INI_ALL。 在 PHP < 5.3.0 时是 PHP_INI_PERDIRsimple_cvs.authMethod"0"PHP_INI_ALLsimple_cvs.compressionLevel"0"PHP_INI_ALLsimple_cvs.cvsRoot"0"PHP_INI_ALLsimple_cvs.host"0"PHP_INI_ALLsimple_cvs.moduleName"0"PHP_INI_ALLsimple_cvs.userName"0"PHP_INI_ALLsimple_cvs.workingDir"0"PHP_INI_ALLSMTP"localhost"PHP_INI_ALLsmtp_port"25"PHP_INI_ALL从 PHP 4.3.0 起可用。soap.wsdl_cache"1"PHP_INI_ALL从 PHP 5.1.5 起可用。soap.wsdl_cache_dir"/tmp"PHP_INI_ALL从 PHP 5.0.0 起可用。soap.wsdl_cache_enabled"1"PHP_INI_ALL从 PHP 5.0.0 起可用。soap.wsdl_cache_limit"5"PHP_INI_ALL从 PHP 5.1.5 起可用。soap.wsdl_cache_ttl"86400"PHP_INI_ALL从 PHP 5.0.0 起可用。sql.safe_mode"0"PHP_INI_SYSTEMsqlite.assoc_case"0"PHP_INI_ALL从 PHP 5.0.0 起可用。sybase.allow_persistent"1"PHP_INI_ALL在 PHP <= 4.0.2 时是 PHP_INI_ALL。 在 PHP <= 4.0.3 时是 PHP_INI_SYSTEM。sybase.hostnameNULLPHP_INI_ALL在 PHP 4.0.2 中移除该选项。sybase.interface_file""PHP_INI_ALLsybase.login_timeout"0"PHP_INI_ALL在 PHP 4.0.2 中移除该选项。sybase.max_links"-1"PHP_INI_ALL在 PHP <= 4.0.2 时是 PHP_INI_ALL。 在 PHP <= 4.0.3 时是 PHP_INI_SYSTEM。sybase.max_persistent"-1"PHP_INI_ALL在 PHP <= 4.0.2 时是 PHP_INI_ALL。 在 PHP <= 4.0.3 时是 PHP_INI_SYSTEM。sybase.min_client_severity"10"PHP_INI_ALL在 PHP 4.0.2 中移除该选项。sybase.min_error_severity"10"PHP_INI_ALLsybase.min_message_severity"10"PHP_INI_ALLsybase.min_server_severity"10"PHP_INI_ALL在 PHP 4.0.2 中移除该选项。sybase.timeout"0"PHP_INI_ALL在 PHP 4.0.2 中移除该选项。sybct.allow_persistent"1"PHP_INI_SYSTEM在 PHP <= 4.0.2 时是 PHP_INI_ALL。 从 PHP 4.0.2 起可用。 在 PHP 4.0.3 中移除该选项。sybct.deadlock_retry_count"0"PHP_INI_ALL从 PHP 4.3.0 起可用。sybct.hostnameNULLPHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 4.0.3 中移除该选项。sybct.login_timeout"-1"PHP_INI_ALL从 PHP 4.0.2 起可用。sybct.max_links"-1"PHP_INI_SYSTEM在 PHP <= 4.0.2 时是 PHP_INI_ALL。 从 PHP 4.0.2 起可用。 在 PHP 4.0.3 中移除该选项。sybct.max_persistent"-1"PHP_INI_SYSTEM在 PHP <= 4.0.2 时是 PHP_INI_ALL。 从 PHP 4.0.2 起可用。 在 PHP 4.0.3 中移除该选项。sybct.min_client_severity"10"PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 4.0.3 中移除该选项。sybct.min_server_severity"10"PHP_INI_ALL从 PHP 4.0.2 起可用。 在 PHP 4.0.3 中移除该选项。sybct.packet_size"0"PHP_INI_ALL从 PHP 4.3.5 起可用。sybct.timeout"0"PHP_INI_ALL从 PHP 4.0.2 起可用。sysvshm.init_mem"10000"PHP_INI_ALLtidy.clean_output"0"PHP_INI_USER在 PHP 5 时是 PHP_INI_PERDIR。 从 PHP 5.0.0 起可用。tidy.default_config""PHP_INI_SYSTEM从 PHP 5.0.0 起可用。track_errors"0"PHP_INI_ALLtrack_vars"1"PHP_INI_ALL在 PHP 4.0.3 中移除该选项。unserialize_callback_funcNULLPHP_INI_ALL从 PHP 4.2.0 起可用。uploadprogress.file.filename_template"/tmp/upt_%s.txt"PHP_INI_ALLupload_max_filesize"2M"PHP_INI_PERDIR在 PHP <= 4.2.3 时是 PHP_INI_ALL。max_file_uploads20PHP_INI_SYSTEM从 PHP 5.2.12 起可用。upload_tmp_dirNULLPHP_INI_SYSTEMurl_rewriter.tags"a=href,area=href,frame=src,form=,fieldset="PHP_INI_ALL从 PHP 4.0.4 起可用。user_agentNULLPHP_INI_ALL从 PHP 4.3.0 起可用。user_dirNULLPHP_INI_SYSTEMuser_ini.cache_ttl"300"PHP_INI_SYSTEM从 PHP 5.3.0 起可用。user_ini.filename".user.ini"PHP_INI_SYSTEM从 PHP 5.3.0 起可用。valkyrie.auto_validate"0"PHP_INI_ALLvalkyrie.config_pathNULLPHP_INI_ALLvariables_order"EGPCS"PHP_INI_PERDIR在 PHP <= 5.0.5 时是 PHP_INI_ALL。velocis.max_links"-1"PHP_INI_ALL在 PHP 4.2.0 中移除该选项。vld.active"0"PHP_INI_SYSTEMvld.execute"1"PHP_INI_SYSTEM从 vld 0.8.0 起可用。vld.skip_append"0"PHP_INI_SYSTEM从 vld 0.8.0 起可用。vld.skip_prepend"0"PHP_INI_SYSTEM从 vld 0.8.0 起可用。windows_show_crt_warning"0"PHP_INI_ALL从 PHP 5.4.0 起可用。xbithack"0"PHP_INI_ALL从 PHP 4.0.5 起可用。xdebug.auto_profile"0"PHP_INI_ALL在 Xdebug 2.0.0 中移除该选项。xdebug.auto_profile_mode"0"PHP_INI_ALL在 Xdebug 2.0.0 中移除该选项。xdebug.auto_trace"0"PHP_INI_ALLxdebug.collect_includes"1"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.collect_params"0"PHP_INI_ALLxdebug.collect_return"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.collect_vars"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.default_enable"1"PHP_INI_ALL在 Xdebug 1 时是 PHP_INI_SYSTEM。xdebug.dump.COOKIENULLPHP_INI_ALLxdebug.dump.ENVNULLPHP_INI_ALLxdebug.dump.FILESNULLPHP_INI_ALLxdebug.dump.GETNULLPHP_INI_ALLxdebug.dump.POSTNULLPHP_INI_ALLxdebug.dump.REQUESTNULLPHP_INI_ALLxdebug.dump.SERVERNULLPHP_INI_ALLxdebug.dump.SESSIONNULLPHP_INI_ALLxdebug.dump_globals"1"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.dump_once"1"PHP_INI_ALLxdebug.dump_undefined"0"PHP_INI_ALLxdebug.extended_info"1"PHP_INI_SYSTEM从 Xdebug 2.0.0 起可用。xdebug.idekey""PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.manual_url"http://www.php.net"PHP_INI_ALLxdebug.max_nesting_level"100"PHP_INI_ALLxdebug.output_dir"/tmp"PHP_INI_PERDIR在 Xdebug <= 1.2.0 时是 PHP_INI_SYSTEM。 在 Xdebug 2.0.0 中移除该选项。xdebug.profiler_aggregate"0"PHP_INI_PERDIR从 Xdebug 2.0.0 起可用。xdebug.profiler_append"0"PHP_INI_PERDIR从 Xdebug 2.0.0 起可用。xdebug.profiler_enable"0"PHP_INI_PERDIR从 Xdebug 2.0.0 起可用。xdebug.profiler_enable_trigger"0"PHP_INI_PERDIR从 Xdebug 2.0.0 起可用。xdebug.profiler_output_dir"/tmp"PHP_INI_PERDIR从 Xdebug 2.0.0 起可用。xdebug.profiler_output_name"cachegrind.out.%p"PHP_INI_PERDIR从 Xdebug 2.0.0 起可用。xdebug.remote_autostart"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.remote_enable"0"PHP_INI_PERDIRxdebug.remote_handler"dbgp"PHP_INI_ALLxdebug.remote_host"localhost"PHP_INI_ALLxdebug.remote_log""PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.remote_mode"req"PHP_INI_ALLxdebug.remote_port"9000"PHP_INI_ALLxdebug.show_exception_trace"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.show_local_vars"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.show_mem_delta"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.trace_format"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.trace_options"0"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.trace_output_dir"/tmp"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.trace_output_name"trace.%c"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.var_display_max_children"128"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.var_display_max_data"512"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xdebug.var_display_max_depth"3"PHP_INI_ALL从 Xdebug 2.0.0 起可用。xmlrpc_errors"0"PHP_INI_SYSTEM从 PHP 4.1.0 起可用。xmlrpc_error_number"0"PHP_INI_ALL从 PHP 4.1.0 起可用。xmms.path"/usr/bin/xmms"PHP_INI_ALLxmms.session"0"PHP_INI_ALLy2k_compliance"1"PHP_INI_ALL在 PHP 5.4.0 中移除该选项。yami.response.timeout"5"PHP_INI_ALL从 yami 1.0.1 起可用。yaz.keepalive"120"PHP_INI_ALLyaz.log_fileNULLPHP_INI_ALL从 PHP 4.3.0 起可用。 在 PHP 5.0.0 中移除该选项。yaz.log_maskNULLPHP_INI_ALL从 yaz 1.0.3 起可用。yaz.max_links"100"PHP_INI_ALL从 PHP 4.3.0 起可用。 在 PHP 5.0.0 中移除该选项。zend.enable_gc"1"PHP_INI_ALL从 PHP 5.3.0 起可用。zend.multibyte"0"PHP_INI_PERDIR从 PHP 5.4.0 起可用。zend.script_encodingNULLPHP_INI_ALL从 PHP 5.4 起可用。0zend.signal_check"0"PHP_INI_SYSTEM从 PHP 5.4 起可用。0zend.ze1_compatibility_mode"0"PHP_INI_ALL从 PHP 5.0.0 起可用。 在 PHP 5.3.0 中移除该选项。zend_extensionNULLphp.ini onlyzend_extension_debugNULLphp.ini onlyzend_extension_debug_tsNULLphp.ini onlyzend_extension_tsNULLphp.ini onlyzlib.output_compression"0"PHP_INI_ALL从 PHP 4.0.5 起可用。zlib.output_compression_level"-1"PHP_INI_ALL从 PHP 4.3.0 起可用。zlib.output_handler""PHP_INI_ALL从 PHP 4.3.0 起可用。 本文转自许琴 51CTO博客,原文链接:http://blog.51cto.com/xuqin/1202662,如需转载请自行联系原作者
这两天一直在ajax的东西,昨天做一个小例子的时候发现了setTimeout这个函数,以前只知道setTimeinterval,发现这两个函数是有一些差别的。在网上搜了一下,作为备忘就转贴一下了。 window对象有两个主要的定时方法,分别是setTimeout 和 setInteval 他们的语法基本上相同,但是完成的功能取有区别。 setTimeout方法是定时程序,也就是在什么时间以后干什么。干完了就拉倒。 setInterval方法则是表示间隔一定时间反复执行某操作。 如果用setTimeout实现setInerval的功能,就需要在执行的程序中再定时调用自己才行。如果要清除计数器需要 根据使用的方法不同,调用不同的清除方法: 例如:tttt=setTimeout('northsnow()',1000); clearTimeout(tttt); 或者: tttt=setInterval('northsnow()',1000); clearInteval_r(tttt); 举一个例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id="liujincai"></div> <input type="button" name="start" value="start" type="button" name="stop" value="stop" language="javascript"> var intvalue=1; var timer2=null; function startShow() { liujincai.innerHTML=liujincai.innerHTML + "&nbsp;" + (intvalue ++).toString(); timer2=window.setTimeout("startShow()",2000); } function stop() { window.clearTimeout(timer2); } </script> 或者: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id="liujincai"></div> <input type="button" name="start" value="start" onclick='timer2=window.setInterval("startShow()",2000);//startShow();'> <input type="button" name="stop" value="stop" language="javascript"> var intvalue=1; var timer2=null; function startShow() { liujincai.innerHTML=liujincai.innerHTML + "&nbsp;" + (intvalue ++).toString(); } function stop() { window.clearInterval(timer2); } </script> 本文转自许琴 51CTO博客,原文链接:http://blog.51cto.com/xuqin/1339907,如需转载请自行联系原作者
jquery判断ie浏览器版本 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 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> <script type="text/javascript"> $(function() { var userAgent = window.navigator.userAgent.toLowerCase(); $.browser.msie10 = $.browser.msie && /msie 10\.0/i.test(userAgent); $.browser.msie9 = $.browser.msie && /msie 9\.0/i.test(userAgent); $.browser.msie8 = $.browser.msie && /msie 8\.0/i.test(userAgent); $.browser.msie7 = $.browser.msie && /msie 7\.0/i.test(userAgent); $.browser.msie6 = !$.browser.msie8 && !$.browser.msie7 && $.browser.msie && /msie 6\.0/i.test(userAgent); $(".info").html( "<h3>userAgent:</h3>" + userAgent + "<br />" + "<h3>Is IE 10?</h3>" + $.browser.msie10 + "<h3>Is IE 9?</h3>" + $.browser.msie9 + "<h3>Is IE 8?</h3>" + $.browser.msie8 + "<h3>Is IE 7?</h3>" + $.browser.msie7 + "<h3>Is IE 6?</h3>" + $.browser.msie6 ); }); </script> <body> <div class="info"></div> </body> 原文:http://www.iefans.net/jquery-pandan-ie-banben/ 本文转自许琴 51CTO博客,原文链接:http://blog.51cto.com/xuqin/1383635,如需转载请自行联系原作者
密码进行md5加密,并且带salt值。 例如username:name password:pass salt为username 则明文密码为 pass{name} 括弧中为salt对应的username,再对明文密码进行加密 springSecurity配置如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <authentication-manager alias="authenticationManager" > <authentication-provider ref="authenticationProvider"> </authentication-provider> </authentication-manager> <beans:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <beans:property name="userDetailsService" ref="myUserDetailService" /> <beans:property name="passwordEncoder" ref="passwordEncoder"/> <beans:property name="saltSource" ref="saltSource"/> </beans:bean> <beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"/> <beans:bean id="saltSource" class="org.springframework.security.authentication.dao.Reflec tionSaltSource"> <beans:property name="userPropertyToUse" value="username"/> </beans:bean> authenticationProvider的配置中加入passwordEncoder与saltSource两个属性 到此配置就结束了 同时,springSecurity提供了Md5PasswordEncoder类实现MD5加密 1 2 3 Md5PasswordEncoder md5 = new Md5PasswordEncoder(); String result = md5.encodePassword("user", "user"); System.out.println(result); md5.encodePassword两个参数中,前一个为password,后一个为salt盐值 同时,网站http://md5jiami.51240.com/ 也提供了在线加密的功能 本文转自布拉君君 51CTO博客,原文链接:http://blog.51cto.com/5148737/1615981,如需转载请自行联系原作者
1.用redis中的List可以实现队列,这样可以用来做消息处理和任务调度的队列 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 29 30 31 32 33 34 35 36 37 38 39 40 41 /** * */ package scheduleTest; import java.util.Random; import java.util.UUID; import redis.clients.jedis.Jedis; /** * 模拟一个生产者 * <p>Title: TaskProducer</p> * <p>Description: </p> * <p>Company: </p> * @author 夏 杰 * @date 2015年12月11日 下午4:26:48 * @vesion 1.0 */ public class TaskProducer implements Runnable{ Jedis jedis = new Jedis("120.55.195.177",6379); public void run() { Random random = new Random(); while(true){ try{ Thread.sleep(random.nextInt(600) + 600); // 模拟生成一个任务 UUID taskid = UUID.randomUUID(); //将任务插入任务队列:task-queue jedis.lpush("task-queue", taskid.toString()); System.out.println("插入了一个新的任务: " + taskid); }catch(Exception e){ e.printStackTrace(); } } } } 消费者模拟程序 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 51 52 53 54 55 56 57 58 /** * */ package scheduleTest; import java.util.Random; import redis.clients.jedis.Jedis; /** * 模拟消费者 * <p>Title: TaskConsumer</p> * <p>Description: </p> * <p>Company: </p> * @author 夏 杰 * @date 2015年12月11日 下午4:44:23 * @vesion 1.0 */ public class TaskConsumer implements Runnable { Jedis jedis = new Jedis("120.55.195.177",6379); public void run() { Random random = new Random(); while(true){ //从任务队列"task-queue"中获取一个任务,并将该任务放入暂存队列"tmp-queue" String taskid = jedis.rpoplpush("task-queue", "tmp-queue"); // 处理任务----纯属业务逻辑,模拟一下:睡觉 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //模拟成功和失败的偶然现象 if(random.nextInt(13) % 7 == 0){// 模拟失败的情况,概率为2/13 //将本次处理失败的任务从暂存队列"tmp-queue"中,弹回任务队列"task-queue" jedis.rpoplpush("tmp-queue", "task-queue"); System.out.println(taskid + "处理失败,被弹回任务队列"); } else {// 模拟成功的情况 // 将本次任务从暂存队列"tmp-queue"中清除 jedis.rpop("tmp-queue"); System.out.println(taskid+"处理成功,被清除"); } } } } 调度主程序 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 /** * */ package scheduleTest; /** * <p>Title: TaskShedulerSystem</p> * <p>Description: </p> * <p>Company: </p> * @author 夏 杰 * @date 2015年12月11日 下午4:19:09 * @vesion 1.0 */ public class TaskShedulerSystem { public static void main(String[] args) throws Exception { // 启动一个生产者线程,模拟任务的产生 new Thread(new TaskProducer()).start(); Thread.sleep(15000); //启动一个线程者线程,模拟任务的处理 new Thread(new TaskConsumer()).start(); //主线程休眠 Thread.sleep(Long.MAX_VALUE); } } 运行结果 插入了一个新的任务: 8025c8b8-f81f-4560-a653-3f339cc371a6 插入了一个新的任务: 98dcf980-10d9-4df6-8765-a4873f6b6a74 插入了一个新的任务: d9636112-4cea-4f49-9f70-88e934aa2a66 插入了一个新的任务: 0a8a2799-d672-4444-b53d-74b679559565 插入了一个新的任务: 3948e29e-0217-434a-b7fe-c3be2f0b1073 插入了一个新的任务: f06c3a03-83a1-4278-a7c8-61d88afcbadf 插入了一个新的任务: fbf7ed91-b1f1-4713-8490-325d77f951b0 插入了一个新的任务: 99cbf0e4-d981-45ad-88f4-10db1604171e 插入了一个新的任务: ca7cd3cf-9ae3-41a1-b8e1-c8ac9a729255 插入了一个新的任务: 3c954253-d195-4185-b27d-390a6e441eaa 插入了一个新的任务: 4b7f2b4d-c77b-4813-9a63-2b6975cb44a1 插入了一个新的任务: 662e0d60-7163-444c-9f1a-43451bb442c3 插入了一个新的任务: d9cca9bd-9870-468d-9beb-f2c3e029c58c 插入了一个新的任务: 7af0318f-7771-4996-99aa-7adb26214f6c 插入了一个新的任务: 7deb7d15-9234-44c8-92d6-53e44b578f6b 插入了一个新的任务: 419a4e25-4343-43f6-bd0e-1f02c6aea19f 插入了一个新的任务: b955ac83-6371-461e-b86b-2a12f45809cc 8025c8b8-f81f-4560-a653-3f339cc371a6处理成功,被清除 插入了一个新的任务: 73218c74-dfd6-46c3-84eb-a14df4a3f7f5 98dcf980-10d9-4df6-8765-a4873f6b6a74处理成功,被清除 插入了一个新的任务: f90f9781-6456-474f-8736-93dc3dcc548f d9636112-4cea-4f49-9f70-88e934aa2a66处理成功,被清除 插入了一个新的任务: cc499c95-3153-4392-9341-3e7173cbf685 0a8a2799-d672-4444-b53d-74b679559565处理失败,被弹回任务队列 插入了一个新的任务: 437c33ae-8adb-49fd-8aad-9e7a396aa72b 3948e29e-0217-434a-b7fe-c3be2f0b1073处理失败,被弹回任务队列 插入了一个新的任务: dbd99594-0a82-4dee-a481-117e1541c549 f06c3a03-83a1-4278-a7c8-61d88afcbadf处理成功,被清除 插入了一个新的任务: d9900559-a995-49cd-9300-540375c21ea0 fbf7ed91-b1f1-4713-8490-325d77f951b0处理成功,被清除 插入了一个新的任务: 72dd3c9a-0cf7-4dd4-9a8d-378da4a531a1 本文转自布拉君君 51CTO博客,原文链接:http://blog.51cto.com/5148737/1976868,如需转载请自行联系原作者
Oracle赋权的回收权限是使用grant和revoke语句,但是赋权和回收权限语句执行完成后就会立即生效么?另外Oracle的权限又分为系统权限、角色权限和对象权限,这三种权限的grant和revoke生效时间又是怎样的呢。我们来看官方文档是如何说的: Depending on what is granted or revoked, a grant or revoke takes effect at different times: All grants and revokes of system and object privileges to anything (users, roles, and PUBLIC) take immediate effect. All grants and revokes of roles to anything (users, other roles, PUBLIC) take effect only when a current user session issues a SET ROLE statement to reenable the role after the grant and revoke, or when a new user session is created after the grant or revoke. You can see which roles are currently enabled by examining the SESSION_ROLES data dictionary view. 从上面的描述中我们可以知道,grant和revoke系统权限和对象权限时会立即生效,而grant或revoke角色时对当前会话不会立即生效,除非使用set role语句启用角色或重新连接会话后设置才会生效。 下面以11.2.0.4为例做一个测试,是否与官方文档描述的一致。 一、首先创建一个测试用户,赋予connect角色 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 sys@ORCL>create user zhaoxu identified by zhaoxu; User created. sys@ORCL>grant connect to zhaoxu; Grant succeeded. sys@ORCL>select * from dba_role_privs where grantee='ZHAOXU'; GRANTEE GRANTED_ROLE ADMIN_OPT DEFAULT_R ------------------------------ ------------------------------ --------- --------- ZHAOXU CONNECT NO YES sys@ORCL>select * from dba_sys_privs where grantee='ZHAOXU'; no rows selected sys@ORCL>select * from dba_tab_privs where grantee='ZHAOXU'; no rows selected sys@ORCL>conn zhaoxu/zhaoxu Connected. zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------ CONNECT zhaoxu@ORCL>select * from session_privs; PRIVILEGE ------------------------------------------------------------ CREATE SESSION zhaoxu@ORCL>create table t (id number) segment creation immediate; create table t (id number) * ERROR at line 1: ORA-01031: insufficient privileges 现在的zhaoxu用户只有CONNECT角色,只能连接到数据库,其他基本什么都做不了。 二、测试系统权限和对象权限的grant和revoke 现在打开另一个会话赋予system privilege给zhaoxu用户 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 --session 2 sys@ORCL>grant create table,unlimited tablespace to zhaoxu; Grant succeeded. --session 1 zhaoxu@ORCL>select * from session_privs; PRIVILEGE ------------------------------------------------------------------------------------------------------------------------ CREATE SESSION UNLIMITED TABLESPACE CREATE TABLE zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ CONNECT zhaoxu@ORCL>create table t (id number) segment creation immediate; Table created. --使用segment creation immediate是因为要避免11g的新特性段延迟创建造成影响 在赋予zhaoxu用户create table和unlimited tablespace系统权限全会话1没有做任何操作,权限就会立即生效。 再测试revoke权限的情况 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 --session 2 sys@ORCL>revoke unlimited tablespace from zhaoxu; Revoke succeeded. --session 1 zhaoxu@ORCL>create table t1 (id number) segment creation immediate; create table t1 (id number) segment creation immediate * ERROR at line 1: ORA-01950: no privileges on tablespace 'USERS' zhaoxu@ORCL>select * from session_privs; PRIVILEGE ------------------------------------------------------------------------------------------------------------------------ CREATE SESSION CREATE TABLE 同样可以看到回收操作可以立即生效,现有session无需做任何操作。 测试对象权限的grant和revoke 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 --grant测试 --session 1 zhaoxu@ORCL>select count(*) from zx.t; select count(*) from zx.t * ERROR at line 1: ORA-00942: table or view does not exist --session 2 sys@ORCL>grant select on zx.t to zhaoxu; Grant succeeded. sys@ORCL>select * from dba_tab_privs where grantee='ZHAOXU'; GRANTEE OWNER TABLE_NAME GRANTOR PRIVILEGE GRANTABLE HIERARCHY ------------------------------ ------------------------------ ---------- ---------- ---------- --------- --------- ZHAOXU ZX T ZX SELECT NO NO --session 1 zhaoxu@ORCL>select count(*) from zx.t; COUNT(*) ---------- 99999 zhaoxu@ORCL>select * from session_privs; PRIVILEGE ------------------------------------------------------------------------------------------------------------------------ CREATE SESSION CREATE TABLE --revoke测试 --session 2 sys@ORCL>revoke select on zx.t from zhaoxu; Revoke succeeded. sys@ORCL>select * from dba_tab_privs where grantee='ZHAOXU'; no rows selected --session 1 zhaoxu@ORCL>select count(*) from zx.t; select count(*) from zx.t * ERROR at line 1: ORA-00942: table or view does not exist 对对象权限的grant和revoke操作与系统权限的一致,所有的命令都是立即生效,包括对已经连接的会话。 三、测试角色的grant和revoke 现在的zhaoxu用户仍然只有connect角色,并且已经打开一个会话 1 2 3 4 5 6 7 8 9 10 11 12 --session 2 sys@ORCL>select * from dba_role_privs where grantee='ZHAOXU'; GRANTEE GRANTED_ROLE ADMIN_OPT DEFAULT_R ------------------------------ ------------------------------ --------- --------- ZHAOXU CONNECT NO YES --session 1 zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------ CONNECT 测试grant DBA权限 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 --session 1查看会话中的角色 zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ CONNECT --session 2赋予zhaoxu用户dba角色 sys@ORCL>grant dba to zhaoxu; Grant succeeded. sys@ORCL>select * from dba_role_privs where grantee='ZHAOXU'; GRANTEE GRANTED_ROLE ADMIN_OPT DEFAULT_R ------------------------------ ------------------------------ --------- --------- ZHAOXU DBA NO YES ZHAOXU CONNECT NO YES --session 1再次查看会话中的角色,没有dba角色,也没有查看v$session的权限 zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ CONNECT zhaoxu@ORCL>select count(*) from v$session; select count(*) from v$session * ERROR at line 1: ORA-00942: table or view does not exist --session 1执行set role命令,可以看到DBA及相关的角色已经加载到session1中了,也可以查询v$session zhaoxu@ORCL>set role dba; Role set. zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ DBA SELECT_CATALOG_ROLE HS_ADMIN_SELECT_ROLE ...... 19 rows selected. zhaoxu@ORCL>select count(*) from v$session; COUNT(*) ---------- 29 --使用zhaoxu用户打开session 3,可以看到新会话中默认会加载DBA及相关角色 [oracle@rhel6 ~]$ sqlplus zhaoxu/zhaoxu SQL*Plus: Release 11.2.0.4.0 Production on Sat Jan 21 16:22:01 2017 Copyright (c) 1982, 2013, Oracle. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ CONNECT DBA SELECT_CATALOG_ROLE ...... 20 rows selected. 测试revoke DBA角色 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 51 52 53 54 --session 2回收DBA角色 sys@ORCL>revoke dba from zhaoxu; Revoke succeeded. sys@ORCL>select * from dba_role_privs where grantee='ZHAOXU'; GRANTEE GRANTED_ROLE ADMIN_OPT DEFAULT_R ------------------------------ ------------------------------ --------- --------- ZHAOXU CONNECT NO YES --session 3查看会话的角色,仍然有DBA及相关角色 zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ CONNECT DBA SELECT_CATALOG_ROLE ...... 20 rows selected. --使用zhaoxu用户打开session 4,查看只有CONNECT角色 [oracle@rhel6 ~]$ sqlplus zhaoxu/zhaoxu SQL*Plus: Release 11.2.0.4.0 Production on Sat Jan 21 16:30:19 2017 Copyright (c) 1982, 2013, Oracle. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ CONNECT --session 3执行set role命令 zhaoxu@ORCL>set role dba; set role dba * ERROR at line 1: ORA-01924: role 'DBA' not granted or does not exist zhaoxu@ORCL>set role all; Role set. zhaoxu@ORCL>select * from session_roles; ROLE ------------------------------------------------------------------------------------------ CONNECT 从上面的测试中可以总结出,grant和revoke系统权限和对象权限时会立即生效,而grant或revoke角色时对当前会话不会立即生效,除非使用set role语句启用角色或重新连接会话后设置才会生效。与官方文档的描述一致。 但是有一个问题是如果查看已经连接的其他会话所拥有的role呢? 官方文档:http://docs.oracle.com/cd/E11882_01/network.112/e36292/authorization.htm#DBSEG99974 system privilege:http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9013.htm#BABEFFEE object privilege:http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9013.htm#BGBCIIEG set role:http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_10004.htm#SQLRF01704 本文转自hbxztc 51CTO博客,原文链接:http://blog.51cto.com/hbxztc/1893674,如需转载请自行联系原作者
Linux常用命令的使用方法: 1、cd :cd [-L|-P] [dir] cd DIR: 将工作目录切换至DIR所代表的目录 cd :将工作目录切换至当前登录用户的家目录 cd - :将工作目录切换至上一次工作目录,在两个目录之间来回切换 PWD:显示当前工作目录的名字 CPLDPWD: cd ~USERRNAME:将工作目录切换至指定用户“USERRNAME”的家目录中,仅限于root用户使用 2、pwd :(显示当前工作目录的名字) print the name of the current pwd [-LP] 3、ls :ls [OPTION]... [FILE]... 在Linux文件系统中,所有以“.”开始的文件名,都表示隐藏文件 选项: -a:显示所有文件,包括隐藏文件 -A:显示除了“.”和“..”之外的所有文件,包括隐藏文件 -d:不显示目录的内容,而只显示该目录名 -l,--long:以长格式显示文件的详细属性 drwxr-xr-x. 2 root root 18 12月 23 06:50 account drwxr:文件的权限设置 rwx :文件的属性所具备的权限 r-x :文件的属组所具备的权限 r-x :其他用户对该文件所具备的权限 . :表示文件是否具有特殊属性 2 :表示该文件被硬连接的次数 root:表示文件的属主 root:表示文件的属组 18:表示文件的大小 12月 23 06:50 :文件最后一次被修改的时间 account:文件名 brw-rw----. 1 root disk 8, 0 3月 23 06:50 sda 8:主设备号(majoir),用于标识设备类型,进而确定要加载何种驱动程序 0:次设备号(minor),用于标识同一种设备类型中的不同设备 名字不是属性 设备号使用8位二进制表示,默认的表示范围:0~255 -h:易于人读取的文件大小格式,通常使用1024进制进行单位换算 -r:倒序输出结果 -R: 递归显示目录及子目录中的内容 -Z:显示文件的SELinux的安全上下文(security context) 退出状态码: 0:命令执行成功 1:命令执行过程中有小问题,比如子目录不能访问等 2:命令执行过程中出现了严重问题,比如目标文件或目录不存在等 4、mkdir: mkdir [OPTION]... DIRECTORY... 选项: -p:在创建目录的时候,如果其父母录不存在,则优先创建之 -v:在执行命令时,显示目录的执行过程 5、rmdir:rmdir [OPTION]... DIRECTORY... 注意:rmdir只能删除空目录,不能删除非空目录,也不能删除非目录文件 -p:在删除目录的时候,如果子目录被删除后,父母录为空,则继续删除 -v:在执行命令时,显示目录的执行过程 6、rm:rm [OPTION]... FILE... 选项: -i:与用户进行交互式删除 -f:强制删除,没有任何提示 -r:可以递归删除目录的内容 例如:mkdir -pv /china/{hebei,henan,shandong}/shenghui mkdir -pv /qhdlink/{network/{class17,class18},website/{class1,class2}} 7、touch:touch [OPTION]... FILE... type touch man touch touch改变时间戳 touch修改所有时间戳,改为统一时间 8、stat:stat [OPTION]... FILE... -c FORMAT:以特定格式显示文件的特定属性 # stat -c %a abc # stat -c %A abc 例如:stat -little/bashrc test/newbashrc 9、nano:全屏编辑工具 ^:脱字符,表示Ctrl键 ^+o:保存文档内容 ^+x:退出编辑界面 nano相当于记事本 例如:nano abc 一块(block)是512字符 10、cat:cat [OPTION]... [FILE]... -b:对于非空行内容进行按行编号 -n:对于所有行进行按行编号 -s:合并多行空白行为一行 -E:显示文档中每行末尾的行结束符,用“$”表示 注意:如果没有给出参数,则通过标准输入完成操作,最后使用^+d退出即可 11、tac:cat的逆序输出 12、head:head [OPTION]... [FILE]... -n #:显示文件的前n行内容,也可以缩写为 - # -c #[b|k|m|g] 显示文件的前#多个字符 1b=512Byte 1k=1024Byte 1m=1024*1024Byte …… 如果不加任何选项,则默认显示文件的前10行,如果文件不足10行,则显示所有内容 13、tail:tail [OPTION]...[FILE]... -n #:显示文件的最后n行内容,也可以缩写为 - # -c #[b|k|m|g] 显示文件的最后#多个字符 -f:一直监控文件末尾的变化情况,使用^+c退出 14、more、less:分页显示文件的内容 more只more只能往下翻页不能往前翻页 Less都可以,能往下翻页也能往前翻页 日期的相关命令: 硬件时钟,晶体震荡(更加准确) 系统时钟,系统模拟震荡(所有系统的参考时间) 硬件时钟:hwclock、clock: hwclock [functions] [options] -s:--hctosys hardwaretosystemtime 以硬件时钟为参考设置系统时钟 -w:--systohc 以系统时钟为参考设置硬件时钟 --set --date “TIME”:将硬件时钟设置为”TIME”所表示的时间 例如:# hwclock --set --date “2018/01/01 00:00:00” # clock 系统时钟:date 结构:date [OPTION]... [+FORMAT] ~]# date “052011112017.25” ~]# date -s “2017/10/10 10:10:10” ~]# date -s “2017-11-11 10:10:10” ~]# date +%F %F:完整格式的日期:年-月-日 %T:完整格式的时间:时:分:秒 %Y:年 %m:月 %d:日 %H:时 %M:分 %S:秒 %s:时间戳,从1970年1月1日到当前系统时间所经过的秒数 NTP服务器:Network Time Protocol,网络时间协议 例如:# date +%F 2017-03-12 # date +%T 11:21:11 # date +%Y 2017 # date +%m 03 # date +%d 12 # date +%H 11 # date +%M 21 # date +%S 48 18、cal:(calendar) # calendar # calendar -y 19、关机 halt、poweroff 强制、不保存 shutdown:shutdown [OPTION]... TIME[MESSAGE] 保存(人性化) 选项: -h:关闭系统 -r:重新引导系统 -c:取消一次即将执行的关机作业 TIME: 绝对时间:12:00 相对时间:+#,在#分钟后执行 特例:+0 相当于 now 20、注销:退出登录,进程还在进行 exit :结束当前shell logout: ^+d: 21、cp :cp [OPTION]... SOURCE DEST(单源复制) cp [OPTION]... SOURCE...DERECTORY(多源复制) 单源复制可以改名,多源复制不可以改名 选项: -d:复制的源如果是符号链接文件,则将该符号链接文件直接复制到目标位置,而不是其链接的那个文件 -p:在复制文件时,能保留文件的权限、所有权以及时间戳信息 -r、-R:能够递归的复制目录及目录中的文件 -a:相当于-dpr选项的组合,-a相当于-d -p -r选项的组合 注意: 1、使用cp命令,至少需要两个参数 2、通常情况下,最后一个参数是此次复制的目标 3、如果进行单源复制,目标可以不存在,目标可以为非目录文件 4、如果进行多源复制,目标必须为目录,且复制过程中无法更改文件名 例如:# cp /etc/issue /etc/fstab /etc/inittab /root/abc(错误) # cp /etc/issue /etc/fstab /etc/inittab /tmp(正确) 22、22、mv :mv [OPTION]... SOURCE DEST mv [OPTION]... SOURCE...DERECTORY 选项: -f:强制覆盖目标位置中重名的文件 本文转自little_ding 51CTO博客,原文链接:http://blog.51cto.com/12496428/1906118,如需转载请自行联系原作者
用户的权限管理 用户的权限管理中包含主要的四部分:普通权限、特殊权限、文件的特殊属性、FACL: 一、普通权限: 普通权限下的进程安全上下文包括如下几点: 1、判断进程的所有者是否想要操作所有者的属主,如果是,就按照属主的权限进行授权,如果不是,就转到第二条; 2、判断进程所有者是否想要操作文件属组中的成员,如果是,就按照属组的权限进行授权,如果不是,就转到第三条; 3、按照其他用户的权限进行授权。 权限包括使用权和所有权,具体构成如下: 1、MODE(Permission):使用权 使用权中的权限位为r(readable 可读)、w(writeable 可写)、x(executable 可执行) 目录中权限位的具体用法如下: r:可以使用ls命令获取其中所有目录的文件名列表;ls -l命令来获取命令中文件的详细属性信息,不能使用cd命令进入其中,也不能在路径中引用该目录; w:可以修改此文件的文件名或文件列表,即可以在此命令中创建、修改或删除文件名; x;可以使用ls命令来获取文件中纤细的属性信息,可以自路径中引用该目录,也可以使用cd命令来进入其中。 注意:x权限是目录的基本权限,换言之,任何目录都必须给任何用户开放x权限,如果没有执行权限则不能引用路径。 2、OWNERSHP:所有权 所有权包括三类:属主的、属组的、其他用户的 属主所有权:资源掌控的某些特定用户,用group表示,简写为g; 属组所有权:资源掌控的某个特定用户,用owner(user)表示,简写为u; 其他用户的所有权:未曾掌控资源的那些用户,用other表示,简写为o,为了安全,对于其他用户的写权限可以不给的话就不给; 全部用户可以用all表示,简写为a。 文件(非目录)中权限位的具体用法如下: r:可以查看或获取该文件中存放的数据; w;可以修改文件中存储的数据; x:可以将此文件发起为进程。 其中使用ls -l(ll)命令可以显示文件的详细属性 权限的三种表达方式为:字符权限(如:rw-r--r--);8位二进制权限(如:110100100);十进制权限(如:644) 对于权限rw-r--r--的解释为:rw-(权限属主)、r--(文件属组)、r--(其他用户权限) 权限标识可以用三元组来表示,有权限用1表示,无权限用0表示,对于无权限在字符权限中可以用-来表示,具体例子如下: --- 000 --x 001 -w- 010 -wx 011 r-- 100 r-x 101 rw- 110 rwx 111 注意:只有某个文件的属主才能修改文件的使用权限(root除外,root不受限定) 修改权限位的命令:chmod、chown、chgrp、install、mktemp 1、chmod:change mode chmod修改文件的权限位(change file mode bits) chmod格式为: chmod[OPTION]…MODE[,MODE]…FILE…()注意省略中MODE用逗号分隔 MODE的权限标识所有法为:u、g、o、a(all) +、-、=三个标识的授权方式如下: +:在所有的权限基础上添加新的权限; -:在所有的权限基础上去除某些权限; =:不考虑原有文件,直接将该权限设置为目标文件。 在MODE中,r、w、x表示具体的内容,具体如下所示: 例如:chmod u+w file 改变属主 chmod g+rw file 改变属组 chmod u+x,g-wx,o-x file (注意用逗号隔开) chmod u=rx,g=r,o=r file chmod ug-x file chmod +x file 默认的为a添加执行权限 chmod +w file 默认的只为属主添加写权限 注意:文件的执行权限,对于Linux文件系统来说是一种非常重要的安全网络标识,因为文件一旦具备了执行权限,移位着该文件可以被发起者执行为进程,所以默认情况下,文件都不具备执行权限。 chmod [OPTION]…OCTAL-MODE FILE(八进制数字标识法) 如果使用八进制数字标识法,则每次必须给足所有的权限位,如果给的权限位不完整,文件系统会自动补足,将给定的权限自动放在权限的右侧,左侧用0来补足。、 例如:cmd 640 file chmod [OPTION]…--reference=RFILE FILE… chmod --reference=/PATH/TO/SAMEFILE DES_FILE 例如:chmod --reference=a b chmod中的选项R(recursive):递归,将目标目录中的文件基子目录和子目录中的文件统一设置为指定的权限标识。 2、chown chown 可以修改文件的属主和属组(change file and group) chown的格式为: chown [OPTION]…[OWNER][:[GROUP]] FILE… chown OWNER FILE 改变文件的属主或属组,其中可以存在省略 chown :GROUP FILE 只改变属组 chown OWNER FILE是将目标文件属主改为OWNER,同时将属组改为OWMER的基本组 chown OWNER:GROUP FILE将目标文件的属主和属组改为OWNER和GROUP chown [OPTION]…--reference=RFILE FILE… chown中的选项R(recursive):递归,将目标目录中的文件基子目录和子目录中的文件统一设置为指定的权限标识。 注意:修改OWNERSHIP操作只有超级用户(root)可以执行 3、chgrp chgrp只能修改文件的属组(change group ownership) chgrp [OPTION]…GROUP FILE… chgrp [OPTION]… --reference=RFILE FIKE… 4、install命令 安装、复制文件,为文件赋予执行权限(copy files and set attributes) install的复制包括单源复制和多源复制,如下: 单源复制:install[OPTION]…[-t] SOURCE DEST 多源复制:install[OPTION]…-t DIRECTORY SOURCE… install[OPTION]…SOURCE…DIRECTORY… 创建目录:install [OPTION]… -d DIRECTORY… install常用选项如下: -m,--mode=MODE: 指定目标文件的权限,默认为755 -o,--owner=OWNER: 设定目标文件的属主,只能是root可用 -g,--group=GROUP: 设定目标文件的属组,仅root可用 注意:install命令不仅能复制目录,即其源不能为目录;如果其源为目录,则install经历了会进入目录,依次复制其中所有非目录文件到目录位置 5、mktemp命令 一般来说,临时文件都会创建在/tmp或/var下。在tmp目录中,无需手动删除,系统会定期自动清除这两个目录中的文件 mktemp的选项:-d,--directory:可以创建临时目录 例如:mktemp [-d] /PATH/TO/TMP.XXXXXX(至少3个XXX) 二、特殊权限 特殊权限包括SUID、SGID、STICKY,默认情况下,用户发起执行的一个进程,也就是说,该进程是以其发起者的身份在运行 1、SUID 功能作用:用户发起执行一个进程时,该程序文件如果拥有SUID权限的话,那么此程序发起的进程其属主为该程序文件的属主,而不是其发起者 SUID权限所显示的位置:文件的属主权限中的执行权限位;如果属主本就是执行权限,显示为s;否则,显示为S 管理文件的SUID权限为: chmod u+|-s FILE…… 2、SGID 功能作用:如果某个目录对于一些用户有写权限并且设置了SGID权限时,则所有对此目录有写权限的用户在创建新的文件或目录以后,性文件的属组不在是创建用户的基本组,而是继承了该目录的组 SGID权限显示的位置:文件的属组权限中的执行权限位,如果属组本来及时执行权限,显示为s,否则显示为S 3、STICKY——粘滞位 STICKY的功能作用:如果某个目录中,有超过一个用户可以有写权限,则这多个用户都可以在该目录中随意创建、修改和删除文件名。如果为上述类似的目录设置了STICKY权限,则每个用户仍旧能够创建和修改文件名,但每个用户只能删除那些属主为其自身的文件名 sticky权限的显示位置:在文件权限的其他用户的执行权限位,如果原来就有执行权限,则显示为t,否则为T 管理文件的SYICKY权限:chmod o+|-t FILE…,具体表达格式如下: Suid sgid sticky --- 000 0 --t 001 1 -s- 010 2 -st 011 3 S-- 100 4 S-t 101 5 Ss- 110 6 Sst 111 7 特殊权限还有另一种修改方式:将特殊权限对应的八进制数字放置于普通权限八进制数字的前面即可 例如:想要把某个目录加上粘滞位:chmod 1755 DIRECTORY… 4、umask——权限遮罩码 在创建文件或目录时默认的权限生成标准,root的权限遮罩码为0022,普通用户遮罩码为0002。对于普通用户,不考虑特殊权限位,对于新创建的文件或目录,不遮挡属主的任何权限;遮住了属组的写权限和其他用户的写权限 例如:# mkdir test -->rwxr-xr-x # touch test.txt---->rw-r--r-- 可以理解为,将遮罩码的值变为二进制,凡是有1的位置,其权限在创建文件时,就不设置,默认情况下,文件的遮罩码已经有了一个0111,在此基础之上再次运用umask来遮罩 例如:000011011 -------110100100 644 -------111100100 744 三、文件的特殊属性 1、查看文件的特殊属性 lsattr: list file attributes on a linux second extended file system 格式:lsattr [-RVadv][files…] 2、修改设置文件的特殊属性 chattr: change file attributes on a linux file system 格式:chattr [-Rvf] [-v version] [mode] files… 格式中,mode会使用+、-、=的方式来设置,整个chattr命令最关键最核心的设置就是[mode]部分,[aAcCdDeijsStTu]都是所需要的属性 其中的+、-、=的意义如下: +:在保有属性设定的基础上,添加新属性 -:从原有属性设置中移除指定的属性 =:不考虑原有的属性设置,直接将文件的属性更新为指定的属性内容 chattr的选项如下: a: append,设置这个属性的文件,其内容不能别修改和删除,只能以追加的方式向文件中写数据,多数的服务器日志类文件会设置为此属性 A:atime,文件的访问时间戳,IO瓶颈,设置A属性,可以说的文件在访问时不更改文件的时间戳,、从而可以有效的防止IO瓶颈的发生 c: 设置文件是否压缩后再进行存储 C: 设置文件是否开启“写时复制”属性 d: 设置文件在使用dump进行备份的时候,不会称为备份目标 D: 设置文件在文件系统中的异步写操作(一般不设置) i: 设置文件不能被删除、修改、设定链接关系 s:设置文件的保密性删除,一旦设置s属性的设置被删除,其对应存储设备中的使用空间会被一并收回 u: 跟s属性相反,如果这样的而文件被删除,则其存储于设备中的数据会被留存 chattr中,最常用的属性为i和a ,例如:chattr +i FILE chattr中,常用选项R,递归的设置指定目录中的所有文件和子目录的属性 四、FACL(File Access Control List) FACL为为文件赋予额外的权限机制,文件访问控制列表 文件的额外赋权机制为:在原有的u、g、o权限位之外,让普通用户能够控制权限赋予另外的用户和组的一种赋权机制。一般在CentOS或RHEL7版本以后的发行版中,才逐渐成熟 与FACL有关的命令有getfacl、Setfacl,具体表示如下: getfacl :get file access control lists 格式:Getfacl [-aceEsRLPndvh] file… 其中,MODE一般采用权限符号标识法:有u:USERNAME:MODE、g:GROUPNAME:MODE 为用户赋予额外权限:setfacl -m u:USERNAME:MODE FILE… 为组赋予额外权限: setfacl -m g:GROUPNAME:MODE FILE… 撤销为用户赋予的额外权限:setfacl -x u:USERNAME 撤销为组赋予的额外权限:setfacl -x g:GROUPNAME 注意:如果设置了FACL之后再修改目标文件的使用权限,那么FACL中设置的条目就可能受到影响而导致要求不符,因此,如果真的需要设置FACL,就要在已经确定命令文件的使用权限以后再行设置。 本文转自little_ding 51CTO博客,原文链接:http://blog.51cto.com/12496428/1912809,如需转载请自行联系原作者
下面是交换机、路由器及其相关网络知识 交换机 1、交换机简介 【交换机】是全双工通信,没有冲突。集线器是总线型网络拓扑,所有主机属于一个冲突域;网桥采用半双工方式,减小了冲突域,半双工是单向数据流,发生冲突的可能性高,通过集线器连接。交换机有两个重要的参数,就是背板带宽和PPS(每秒数据包数),对于100Mbps的全双工接口,PPS可达到290万。其中,LAN交换机具有以下特点:较高的端口密集度、大型帧缓冲区、支持各种端口速度混合、快速内部交换模式。快速内部交换模式可分为直通、存储转发、免分片三部分,直通转发就是快速转发,只关注前6位目的地址;免分片,就是每个数据取64字节,不足64字节的直接丢弃。 2、交换机功能 交换机具有【学习、转发、过滤】三个功能,具体解释如下: 学习,就是当交换机接收到一个数据帧时,交换机将源MAC地址与接收数据帧的交换机端口绑定起来存入交换机内部的MAC地址表中,如果接受到的源MAC地址不存在交换机的MAC地址表中,就直接将该条MAC地址存入交换机MAC地址表;如果接收到的MAC地址存在交换机的MAC地址表中,就修改该地址的时间戳;冬天学习的MAC地址能在交换机的MAC地址表中存在300秒。 转发,分为有目的转发和无目的转发两种;有目的转发,就是当交换机接收到数据帧的源MAC地址时,在他自身的MAC地址表中存在该MAC地址条目,就将数据帧经由MAC地址对应的端口转发出去;无目的转发,就是当交换机接收到数据帧的源MAC地址时,在他自身的MAC地址表中没有该MAC地址条目,经过泛洪转发数据帧。 过滤,就是交换机接收到一个目的地址的MAC地址对应的端口和接收数据帧的端口是同一个端口,这样的数据帧不给予转发。 3、交换机中,以太网通信过程 【交换以太网】的数据通信过程如下,和双机互联相比,在主机之间添加了交换机: 1)、确定目的IP地址,通过手动输入或DNS解析获得 2)、应用程序选择传输层所使用的协议,该过程使用UDP协议 3)、UDP进行数据封装,送给下层IP协议进行进一步封装 4)、IP协议根据目的IP和源IP进行进一步数据封装,并试图交给网络访问层 5)、网络访问层求助ARP协议,如果ARP协议没有缓存目的IP地址,UDP数据包暂存内存中,并发送ARP请求,ARP请求从源主机出发,被交换机接收,交换机判断自己的MAC地址表中是否有目的IP地址的MAC地址,在学习了地址之后,根据目的MAC地址进行泛洪或者是单播转发;目的主机接收到ARP请求数据后,缓存源主句的IP地址和MAC地址,并将自己的IP地址和MAC地址响应给源主机,交换机先接收目的主机发来的IP地址和MAC地址,将其缓存至交换机的MAC地址表中,在通过单播转发给源主机;源主机获得目的主机的MAC地址,并将其缓存至ARP缓存中,进行下一步。如果ARP协议已经缓存了目的主机的MAC地址,直接进行下一步。 6)、根据ARP缓存中目的MAC地址封装并发送数据 7)、交换机接收数据后,根据其MAC地址表中的地址进行单播转发。 4、交换机分类 Cisco有两种类型的交换机,【nexus】高端核心交换机和【catalyst】中低端交换机。Cisco的IOS操作系统,是网络的操作系统,主要用在交换机和路由器上,交换机中的IOS只有几兆大小,路由器中的IOS有几十兆大小。 同样的,华为或H3C的操作系统为Comware。两种操作系统都是使用命令行界面。IOS软件能承载所选的网络协议和功能,具有连通性(设备间高速传输)、安全性(控制访问)、可扩展性(接口和容量可变)、可靠性。Catalyst的硬件由7部分组成,分别是CPU、RAM、NVRAM、FLASH、ROM、Interface(Ethernet和console)、back-bone。 以太网交换机,其三种接口类型为:Ethernet(10Mbps)、FastEthernet(100Mbps)、GigabitEthernet(1000Mbps) 5、交换机操作系统 IOS和Comware操作系统组成 IOS是一个【模式化】的操作系统,具有以下模式:(1)、用户模式,提示符为:>;(2)、特权模式(使能模式),提示符为:#;(3、)全局配置模式,提示符为:(config)#;(4)、接口配置模式,提示符为:(config-int)#;(5)、vlan配置模式,提示符为:(vlan)# 或(config-vlan)#;(6)、路由模式,提示符为:(config-router)#。 Comware是【基于视图】的操作系,具有如下视图,(1)、用户视图,提示符为:userview;(2)、系统视图,提示符为:sysview;(3)、接口视图;(4)、vlan视图;(5)、路由视图。 6、交换机层级与安全 Cisco的【查看】命令为 show,【保存】命令为 write。推荐使用 copy running-config startup-config 保存当前的配置到NVRAM。 华为的查看命令为 display,保存命令为 save,保存当前的配置到NVRAM。对于查看display命令,display current-config:用来查看当前正在RAM中运行的配置文件;display saved-config:查看保存MVRAM中的配置文件。 对于交换机的安全,有【三种密码】,分别是用户模式的密码、特权模式的密码、远程连接的密码。用户模式的密码,就是进入模式之前必须输入密码,在console线的配置模式中进行配置。特权模式的密码,就是进入特权模式之前必须输入密码,是在全局模式中配置执行enable命令后所需要的密码,设置密码使用password/secret。远程连接的密码,通过telnet服务远程连接到交换机,并进入特权模式之前输入密码,是在远程客户端上通过telnet远程连接后,进入用户模式所需要的密码。 交换机的【连接层级】,可分为三层:核心层、分布层、接入层。核心层高速传输,进行核心路由器和分布站点之间的传输;分布层提供链路策略,提供多个接入层的交换机;接入层提供多个接口。连接层级架构模式有优点,但也有不足,例如:广播风暴、帧的多重副本、MAC地址表的抖动。为了解决连接架构模式的不足,采用了【生成树协议】,将最小ID的交换机作为生成树的根,建立树形无环拓扑结构,造成端口逻辑阻塞,使交换机不能正常发送和接收数据流量。 7、交换机技术 交换机使用的技术:vlan和ftp 交换机的【vlan技术】中,主要有接入接口和中继接口两种接口,接入接口就是只能传递某个特定的vlan数据,由接入接口连接起来的链路称为接入链路,access链路;中继接口就是可以同时传递多个vlan数据,还可以通过不同的标签来区分不同的valn数据,由中继接口连接起来的链路称为中继链路,trunk链路。除了这两种主流接口外,在华为的交换机上,还有一种Hybrid超级桥接接口,能够传递指定的多个vlan的数据。中继链路的封装协议为IEEE 802.1Q(dot1Q)。 VLAN具有以下三个特点,即分段、灵活性、安全性。VLAN的基本编号为1-1005,扩展编号为1006-4094,同时,VLAN还可以用名称表示。 交换机互联技术分为三部分,即接入层交换机、分布层交换机(2台)、核心层交换机(2台) 【stp生成树协议】是为了避免物理环路而产生的,生成树协议有很多种,如:快速生成树协议(RSTP)、多实例生成树协议MST(MSTP)、每vlan生成树协议(pvst)。生成树协议由四部分组成,【根桥、根端口、指定端口、非指定端口】。经过生成树协议算法的选择,最终每个环路都会选出一个被阻塞的端口,该端口称为非指定端口,处于阻塞状态;在阻塞状态下,该端口只能接收【BPDU数据帧】,不能发送BPDU,也不能收发普通的数据帧。一旦拓扑结构发生变化, 位于变化一端的交换机会生成一个叫做"TC"的BPDU数据帧;该帧会传遍整个网络,也会被处于阻塞状态的端口接收;一旦处于阻塞状态的端口接收到该类数据帧,其会试图自动转换状态至转发状态以用于进行正常数据帧收发;从而可以实现链路的冗余备份;一旦损坏的网段修复,重新计算生成树。 生成树的根桥、根端口、指定端口、非指定端口四部分构成如下: (1)、每个物理环中有一个【根桥】,桥ID最小的即为根桥;桥ID = 桥优先级 + 桥MAC地址 ;其中,桥优先级是第一参考标准,范围为0-65535,默认的桥优先级为32768;桥MAC地址是交换机管理接口的MAC地址,是第二参考标准,通常会认为是vlan1虚拟接口的MAC地址。 (2)、每个非根桥有一个【根端口】,根端口是处于转发状态的端口,可以用于进行正常的数据帧发送和接收。根端口的选择标准有两个,分别是开销值和端ID。对于开销值,从该端口到达根桥的开销值最小,即为根端口;根据带宽计算路径开销为:10000Mbps为2;1000Mbps为4;100Mbps为19;10Mbps为100;对于多条路径,开销值可以进行累加。如果非根桥的两个端口到达根桥的开销值相同,则比较两个端口的端口ID,【端口ID最小】的即为根端口;端口ID:端口优先级 + 端口的MAC地址;端口优先级是第一参考标准,范围为0-255,默认值为128;端口MAC地址是第二参考标准,是物理端口的MAC地址。 (3)、每个网段有一个【指定端口】,指定端口是处于转发状态的端口,可以用于进行正常的数据帧发送和接收。从每个网段中选择指定端口,从该端口到达根桥的开销值最小,即为指定端口,根桥上的端口一定是指定端口(根桥的端口到达根桥的开销值为0);如果某网段上的两个端口到达根桥的开销值相同,则比较端口所在的交换机的桥ID,桥ID小的就是指定端口。 (4)、【非指定端口】,经过生成树协议算法的选择,最终每个环路都会选出一个被阻塞的端口,该端口称为非指定端口,处于阻塞状态;在阻塞状态下,该端口只能接收BPDU数据帧,不能发送BPDU,也不能收发普通的数据帧。 例如,接口为2n,则根桥为1,根桥接口为(n-1),指定端口为n。 Cisco Catalyst交换机支持三种类型的STP分别是:PVST+、PVRST+、MSTP 使用的命令为 Switch(config)# spanning-tree mode {pvst|rapid-pvst} 华为交换机支持三种类型STP为:STP、RSTP、MSTP。 路由器 1、路由器简介 【路由】的4个基本元素为进制、数码、基数、位权。进制即进位计数制;数码即构成路由的数字符号;基数即进制位,10进制为10,2进制为2; 位权即数码加权,整数部分位权为:基数^(位-1),小数部分为:基数^(-位)。例如:2^7=10000000(二进制) ;2^7=128(十进制);2^7=200(八进制) ;2^7=80(十六进制)。二进制转换时,任意三位二进制数字都可以对应一位八进制数字,任意四位二进制数字都可以对应一位十六进制数字。 2、路由转发及路由表的产生 路由器根据【路由表】来转发数据包,路由器根据路由表来进行数据转发,如果路由表中有跟数据包目的IP地址对应的路由条目,则按照相关路由条目转发;如果路由表中没有跟数据包的目的IP地址对应的路由条目,则丢弃数据包。路由器分隔广播域,拥有已分配了IP地址的网络适配器。路由器的4大组件为:CPU、主板、RAM、ROM。路由器可以分为控制台、网络两种类型的接口。 路由表的产生:路由表是一组具有一定标准格式的数据信息,如果是管理员手动的添加到路由表中的信息,这类路由的信息称为【静态路由】;如果是路由器之间通过特定协议相互通告得到的路由信息,称为【动态路由】; 一般来讲,静态路由永久有效,动态路由在特定的时间范围内有效。用路由器连接的多个网络应该具有【不同的广播地址】 。 3、路由格式 【路由格式】:路由条目的来源 目标网络地址 [管理距离/度量值] via 下一跳地址 (1)、路由条目来源:C:直接路由,在路由器的物理接口上配置的IP地址对应的路由条目 S:静态路由 D、R、O、O E1、O E2、D EX、B:动态路由 S*:静态默认路由 D*、O*:动态默认路由 (2)、目标网络地址:网络地址,即主机为全为0的IP地址。利用目标网络地址所标识的子网掩码与数据包中目的IP地址进行逻辑与运算,将得到的结果与"目标网络地址"进行对比,如果完全相同,才算匹配,则转发;否则就匹配下一条路由条目;如果所有的路由条目跟目标IP地址均不匹配,则丢弃数据包; (3)、管理距离:评价路由选择方式的好坏的,是衡量路由信息来源的可靠性的标准;数字越小越好,越大越差。 cisco和华为对路由器管理距离的定义不同,【cisco路由器的管理距离】定义为:直连路由(0)、静态路由(1)、EIGRP(90)、IGRP(100)、OSPF(110)、RIPv2(120)、静态默认路由(254)、不可达路由(255)。【华为路由器的管理距离】定义为:直连路由(0)、OSPF(40)、静态路由(60)、RIP(120)、静态默认路由(254)、不可达路由(255)。 (4)、度量值:度量值是衡量路径的成本的;在同一种选路方式中,度量值越小的路径越好;管理距离和度量值用来评判路径是否优秀的,或者说,这是路由选择的依据 ,越小越好。 RIP为跳数,是经过的路由器的个数,其度量值的最大值为15; OSPF为开销(成本),计算公式为:COST=10^8/带宽,注意,此处带宽的单位是bps,其度量值的最大值为65535; EIGRP为复合度量值,与带宽、延迟、负责量、可靠性、MTU有关,其度量值的最大值:2^32 (5)、下一跳地址(出站接口的编号):如果路由器可以正常将数据包路由出去,则该参数指示此次路由数据的方向; 4、广播域及子网划分 【广播域】即逻辑网段,由路由器分隔,分隔广播域就是分隔逻辑网段,是微分段的方式。交换机用来分隔【冲突域】,分隔冲突域就是分隔逻辑网段,是子网划分的方式。【子网】划分了许多小型网络,易于管理,总流量少,易于使用网络安全策略,子网利用【子网掩码】来进行划分。 子网掩码是32位二进制数字,用子网掩码的1表示网络位,子网掩码的0表示主机位。子网掩码的功能是与IP地址做与运算,然后求出网络位,同一个逻辑网段,网络位必须相同。路由的IP地址分为两类,有类IP地址(默认按类别匹配)和无类IP地址(手动输入),例如无类IP地址的前缀表示法:172.16.1.2/24(24位掩码)。 【子网划分】,实际上就是增加了IP地址中的网络位,减少了IP地址中的主机位,减少了广播域,减少了网段中主机的数量,便于网络管理和安全测略的应用。增加了多少个网络位,就增加了(2^网络位)个子网,主机位全为0叫做网络地址,主机位全为1叫做广播地址,网络位最多为30位,即主机位最少占用2位。 主类网络中,每个网络包含的IP地址数量可能很庞大,而在整个网络中,一旦该主类网络被使用,其他网络即不能使用该主类网络内的所有IP地址;因此,我们可以划分多个子网,把主类网络划分为多个合适的子网。子网划分的实质是增加网络中网络的数量,减少主机的数量。如说不进行子网划分,我们只能使用主类网络。 使用ping命令来检测主机之间的连通性,其返回结果有能连通、不能连通两种,但是如果没有连通时,无法进一步定位故障点。 使用traceroute对路由信息进行跟踪,将路由接口的IP地址信息返回主机。 5、路由技术 路由技术:路由协议和NAT(网络地址转换) 【NAT】为网络地址转换,进行NAT的前提是,IP地址被划分为公有地址和私有地址;公有地址可以直接访问互联网,互联网中的各个路由器为所有的公有地址提供路由;私有地址只能在局域网内使用,互联网中的各个路由器不会为私有地址提供任何路由。NAT会被配置在互联网边界路由器上,在数据发送的过程中,通常会使用全局地址替换本地地址;也就是说,最终封装在数据包上的源和目的IP地址,都是全局地址。 比较常用的NAT有SNAT和DNAT两种,SNAT是使私有IP地址的主机能够访问到互联网资源的方法,将局域网接入互联网;DNAT与SNAT相反,DNAT数据通信的目的地是某个局域网内的主机或服务器,是访问局域网内服务器的方法。 为了实现NAT转换的正常进行,在路由器内部,保存了一个NAT表;对于每台路由器而言,NAT表是实现NAT的依据;生成NAT表的方式,有静态和动态两种,静态即管理员手动的完成,格式为:ip nat inside source static Inside_local Inside_global,动态即由路由器自动执行完成,格式为ip nat inside source Inside_local Inside-global [overload]。 附: R:RIPv2(路由信息协议版本2) D:EIGRP(加强内部网关路由协议) O:OSPF(开放最短路径优先协议) B:BGP(边缘网关协议) 本文转自little_ding 51CTO博客,原文链接:http://blog.51cto.com/12496428/1948240,如需转载请自行联系原作者
##采用Atlas实现MySQL读写分离 一、基础介绍 ========================================================================================== 1、背景描述 目前我们的高可用DB的代理层采用的是360开源的Atlas,从上线以来,已稳定运行2个多月。无论是从性能上,还是稳定性上, 相比其他开源组件(amoeba、cobar、MaxScale、MySQL-Proxy等),还是很出色的。 当初我们之所以选择Atlas,主要看中它有以下优点: (1)、基于mysql-proxy-0.8.2进行修改,代码完全开源; (2)、比较轻量级,部署配置也比较简单; (3)、支持DB读写分离; (4)、支持从DB读负载均衡,并自动剔除故障从DB; (5)、支持平滑上下线DB; (6)、具备较好的安全机制(IP过滤、账号认证); (7)、版本更新、问题跟进、交流圈子都比较活跃。 在测试期间以及线上问题排查过程中,得到了360 Atlas作者朱超的热心解答,在此表示感谢。有关更多Atlas的介绍,我就不一一例举,可以参考以下链接: https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md 3、系统环境 CentOS 7.2 x86_64 网络环境:master 192.168.10.25 slave 192.168.10.26 mysql-atlas-proxy 192.168.10.28 ##安装mysql-server主服务端(192.168.10.25) service firewalld stop chkconfig firewalld off setenforce 0 getenforce sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config yum install -y mariadb mariadb-server service mariadb restart chkconfig mariadb on sed -i '1aserver_id=25' /etc/my.cnf sed -i '2alog-bin=mysql-bin' /etc/my.cnf service mariadb restart mysql -uroot -e "grant all on *.* to admin@'%' identified by '01';flush privileges;" mysql -uroot -e "grant replication slave on *.* to rep@'%' identified by '01';flush privileges;" mysql -uroot -e "select user,host,password from mysql.user;" mysql -uroot -e "reset master;show master status;" ##安装mysql-server主服务端(192.168.10.26) service firewalld stop chkconfig firewalld off setenforce 0 getenforce sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config yum install -y mariadb mariadb-server service mariadb restart chkconfig mariadb on sed -i '1aserver_id=26' /etc/my.cnf sed -i '2alog-bin=mysql-bin' /etc/my.cnf service mariadb restart mysql -uroot -e "grant all on *.* to admin@'%' identified by '01';flush privileges;" mysql -uroot -e "grant replication slave on *.* to rep@'%' identified by '01';flush privileges;" mysql -uroot -e "select user,host,password from mysql.user;" mysql -uroot -e "change master to master_host='192.168.100.11',master_user='rep',master_password='01',master_port=3306,master_log_file='mysql-bin.000001',master_log_pos=245;" sleep 30s mysql -uroot -e "start slave;show slave status\G" ##安装配置atlas读写分离(192.168.10.28) service iptables stop chkconfig iptables off setenforce 0 getenforce sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config grep '^SELINUX=' /etc/selinux/config 安装和配置atlas软件 rpm -ivh Atlas-2.2.1.el6.x86_64.rpm echo "PATH=$PATH:/usr/local/mysql-proxy/bin/" >> /etc/profile source /etc/profile ll /usr/local/mysql-proxy/ ##mysql-proxy文件功能说明: bin目录下放的都是可执行文件 1. “encrypt”是用来生成MySQL密码加密的,在配置的时候会用到 2. “mysql-proxy”是MySQL自己的读写分离代理 3. “mysql-proxyd”是360弄出来的,后面有个“d”,服务的启动、重启、停止。都是用他来执行的 conf目录下放的是配置文件 1. “test.cnf”只有一个文件,用来配置代理的,可以使用vim来编辑 lib目录下放的是一些包,以及Atlas的依赖 log目录下放的是日志,如报错等错误信息的记录 进入bin目录,使用encrypt来对数据库的密码进行加密,我的MySQL数据的用户名是admin,密码是01,我需要对密码进行加密 cd /usr/local/mysql-proxy/bin/ ./encrypt 01 生成加密密码,并复制此密码 cd /usr/local/mysql-proxy/conf/ cp -v test.cnf test.cnf.bak //备份test.cnf配置文件 vi test.conf 修改后的读写分享的完整配置文件内容 [mysql-proxy] admin-username = user admin-password = pwd proxy-backend-addresses = 192.168.100.11:3306 pwds = admin:VFnEp9P4Vu4=, rep:VFnEp9P4Vu4= daemon = true keepalive = true event-threads = 8 log-level = message log-path = /usr/local/mysql-proxy/log proxy-address = 0.0.0.0:3306 admin-address = 0.0.0.0:2345 test.cnf读写分离配置文件功能说明: 1:[mysql-proxy] //读写分离代理配置 6:admin-username = user //管理接口的用户名 9:admin-password = pwd //管理接口的密码 12:proxy-backend-addresses = 192.168.100.11:3306 //主数据库的IP地址和端口号(可读可写) 18:pwds = admin:VFnEp9P4Vu4=, rep:VFnEp9P4Vu4= //后端MYSQL的用户名和encrypt命令生成的加密密码 21:daemon = true //设置为守护进程模式(后台运行) 24:keepalive = true //允许keepalive 27:event-threads = 8 //工作线程数为8 30:log-level = message //日志等级为message消息 33:log-path = /usr/local/mysql-proxy/log //日志文件路径 45:proxy-address = 0.0.0.0:3306 //Atlas监听的管理接口IP和端口 48:admin-address = 0.0.0.0:2345 //Atlas监听的管理接口IP和端口 重启atlas服务:/usr/local/mysql-proxy/bin/mysql-proxyd test start 查状态:./etc/init.d/mysqld status 设置mysql-proxyd开机启动: echo "/usr/local/mysql-proxy/bin/mysql-proxyd test start" >> /etc/profile source /etc/profile 登录测试:mysql -uadmin -p01 -h 192.168.10.28 -P3306 登录到atlas管理端:mysql -uuser -ppwd -h 192.168.10.28 -P2345 本文转自rshare 51CTO博客,原文链接:http://blog.51cto.com/1364952/1952214,如需转载请自行联系原作者
标签:ansible module ansible module ansible模块 Ansible通过模块的方式来完成一些远程的管理工作。可以通过ansible-doc -l查看所有模块,可以使用ansible-doc -s module来查看某个模块的参数,也可以使用ansible-doc help module来查看该模块更详细的信息。下面列出一些常用的模块: 1. setup 可以用来查看远程主机的一些基本信息: ansible -i /etc/ansible/hosts test -m setup 2.ping 可以用来测试远程主机的运行状态: ansible test -m ping 3.file 设置文件的属性 file模块包含如下选项: force:需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no group:定义文件/目录的属组 mode:定义文件/目录的权限 owner:定义文件/目录的属主 path:必选项,定义文件/目录的路径 recurse:递归的设置文件的属性,只对目录有效 src:要被链接的源文件的路径,只应用于state=link的情况 dest:被链接到的路径,只应用于state=link的情况 state: directory:如果目录不存在,创建目录 file:即使文件不存在,也不会被创建 link:创建软链接 hard:创建硬链接 touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间 absent:删除目录、文件或者取消链接文件 示例: ansible test -m file -a "src=/etc/fstab dest=/tmp/fstab state=link" ansible test -m file -a "path=/tmp/fstab state=absent" ansible test -m file -a "path=/tmp/test state=touch" 4.copy 复制文件到远程主机 copy模块包含如下选项: backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no content:用于替代"src",可以直接设定指定文件的值 dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录 directory_mode:递归的设定目录的权限,默认为系统默认权限 force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes others:所有的file模块里的选项都可以在这里使用 src:要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。 validate :The validation command to run before copying into place. The path to the file to validate is passed in via '%s' which must be present as in the visudo example below. 示例: ansible test -m copy -a "src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode=0644" ansible test -m copy -a "src=/mine/ntp.conf dest=/etc/ntp.conf owner=root group=root mode=644 backup=yes" ansible test -m copy -a "src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'" 5.command 在远程主机上执行命令 command模块包含如下选项: creates:一个文件名,当该文件存在,则该命令不执行 free_form:要执行的linux指令 chdir:在执行指令之前,先切换到该指定的目录 removes:一个文件名,当该文件不存在,则该选项不执行 executable:切换shell来执行指令,该执行路径必须是一个绝对路径 示例: ansible test -a "/sbin/reboot" 6.shell 切换到某个shell执行指定的指令,参数与command相同。 示例: ansible test -m shell -a "somescript.sh >> somelog.txt" 7.service 用于管理服务 该模块包含如下选项: arguments:给命令行提供一些选项 enabled:是否开机启动 yes|no name:必选项,服务名称 pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行 runlevel:运行级别 sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟 state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded) 示例: ansible test -m service -a "name=httpd state=started enabled=yes" ansible test -m service -a "name=foo pattern=/usr/bin/foo state=started" ansible test -m service -a "name=network state=restarted args=eth0" 8.cron 用于管理计划任务 包含如下选项: backup:对远程主机上的原任务计划内容修改之前做备份 cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划 day:日(1-31,*,*/2,……) hour:小时(0-23,*,*/2,……) minute:分钟(0-59,*,*/2,……) month:月(1-12,*,*/2,……) weekday:周(0-7,*,……) job:要执行的任务,依赖于state=present name:该任务的描述 special_time:指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly state:确认该任务计划是创建还是删除 user:以哪个用户的身份执行 示例: ansible test -m cron -a 'name="check dirs" hour="5,2" job="ls -alh > /dev/null"' ansible test -m cron -a 'name="a job for reboot" special_time=reboot job="/some/job.sh"' ansible test -m cron -a 'name="yum autoupdate" weekday="2" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=ansible_yum-autoupdate' ansilbe test -m cron -a 'cron_file=ansible_yum-autoupdate state=absent' 9.filesystem 在块设备上创建文件系统 选项: dev:目标块设备 force:在一个已有文件系统的设备上强制创建 fstype:文件系统的类型 opts:传递给mkfs命令的选项 10.yum 使用yum包管理器来管理软件包 选项: config_file:yum的配置文件 disable_gpg_check:关闭gpg_check disablerepo:不启用某个源 enablerepo:启用某个源 list name:要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径 state:状态(present,absent,latest) 示例: ansible test -m yum -a 'name=httpd state=latest' ansible test -m yum -a 'name="@Development tools" state=present' ansible test -m yum -a 'name=http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present' 11.user 管理用户 home: groups: uid password: name: createhome: system: remove: state: shell: 需要特别说明的是,password后面指定的密码不能是明文,后面这一串密码会被直接传送到被管理主机的/etc/shadow文件中,而登陆的时候输入的密码会被hash加密以后再去与/etc/shadow中存放的密码去做对比,会出现不一致的现象。所以需要先将密码字符串进行加密处理:openssl passwd -salt -1 "123456",然后将得到的字符串放到password中即可。 12.group 管理组 13.synchronize 使用rsync同步文件 archive checksum delete dest src dest_port existing_only: skip createing new files on receiver links owner mode:(push, pull) recursive rsync_path times:Preserve modification times 示例: src=some/relative/path dest=/some/absolute/path rsync_path="sudo rsync" src=some/relative/path dest=/some/absolute/path archive=no links=yes src=some/relative/path dest=/some/absolute/path checksum=yes times=no src=/tmp/helloworld dest=/var/www/helloword rsync_opts=--no-motd,--exclude=.git mode=pull 14.mount 配置挂载点 选项: dump fstype:必选项,挂载文件的类型 name:必选项,挂载点 opts:传递给mount命令的参数 passno src:必选项,要挂载的文件 state:必选项 present:只处理fstab中的配置 absent:删除挂载点 mounted:自动创建挂载点并挂载之 umounted:卸载 示例: name=/mnt/dvd src=/dev/sr0 fstype=iso9660 opts=ro state=present name=/srv/disk src='LABEL=SOME_LABEL' state=present name=/home src='UUID=b3e48f45-f933-4c8e-a700-22a159ec9077' opts=noatime state=present ansible test -a 'dd if=/dev/zero of=/disk.img bs=4k count=1024' ansible test -a 'losetup /dev/loop0 /disk.img' ansible test -m filesystem 'fstype=ext4 force=yes opts=-F dev=/dev/loop0' ansible test -m mount 'name=/mnt src=/dev/loop0 fstype=ext4 state=mounted opts=rw' 15.raw 类似command,但可以传递管道 本文转自rshare 51CTO博客,原文链接:http://blog.51cto.com/1364952/1953974,如需转载请自行联系原作者
Git常用命令 转自:http://blog.csdn.net/stven_king/article/details/44856045 查看、添加、提交、删除、找回,重置修改文件 git help # 显示command的help git show # 显示某次提交的内容 git show $id git co – # 抛弃工作区修改 git co . # 抛弃工作区修改 git add # 将工作文件修改提交到本地暂存区 git add . # 将所有修改过的工作文件提交暂存区 git commit -m [提交信息] #将暂存区的文件提交到本地仓库中 git rm # 从版本库中删除文件 git rm –cached # 从版本库中删除文件,但不删除文件 git reset # 从暂存区恢复到工作文件 git reset – . # 从暂存区恢复到工作文件 git reset –hard # 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改 git ci git ci . git ci -a # 将git add, git rm和git ci等操作都合并在一起做* * git ci -am “some comments” git ci –amend # 修改最后一次提交记录 git revert 查看文件diff git diff # 比较当前文件和暂存区文件差异 git diff git diff <id1><id2> # 比较两次提交之间的差异 git diff .. # 在两个分支之间比较 git diff –staged # 比较暂存区和版本库差异 git diff –cached # 比较暂存区和版本库差异 git diff –stat # 仅仅比较统计信息 查看提交记录 git log git log # 查看该文件每次提交记录 git log -p # 查看每次详细修改内容的diff git log -p -2 # 查看最近两次详细修改内容的diff git log –stat #查看提交统计信息 Git 本地分支管理 ===================================================== 查看、切换、创建和删除分支 git br -r # 查看远程分支 git br # 创建新的分支 git br -v # 查看各个分支最后提交信息 git br –merged # 查看已经被合并到当前分支的分支 git br –no-merged # 查看尚未被合并到当前分支的分支 git co # 切换到某个分支 git co -b # 创建新的分支,并且切换过去 git co -b # 基于branch创建新的new_branch git co $id # 把某次历史提交记录checkout出来,但无分支信息,切换到其他分支会自动删除 git co $id -b # 把某次历史提交记录checkout出来,创建成一个分支 git br -d # 删除某个分支 git br -D # 强制删除某个分支 (未被合并的分支被删除的时候需要强制) 分支合并和rebase git merge # 将branch分支合并到当前分支 git merge origin/master –no-ff # 不要Fast-Foward合并,这样可以生成merge提交 git rebase master # 将master rebase到branch,相当于: git co && git rebase master && git co master && git merge Git补丁管理(方便在多台机器上开发同步时用) git diff > ../sync.patch # 生成补丁 git apply ../sync.patch # 打补丁 git apply –check ../sync.patch #测试补丁能否成功 Git暂存管理 git stash # 暂存 git stash list # 列所有stash git stash apply # 恢复暂存的内容 git stash drop # 删除暂存区 Git远程分支管理 git pull # 抓取远程仓库所有分支更新并合并到本地 git pull –no-ff # 抓取远程仓库所有分支更新并合并到本地,不要快进合并 git fetch origin # 抓取远程仓库更新 git merge origin/master # 将远程主分支合并到本地当前分支 git co –track origin/branch # 跟踪某个远程分支创建相应的本地分支 git co -b origin/ # 基于远程分支创建本地分支,功能同上 git push # push所有分支 git push origin master # 将本地主分支推到远程主分支 git push -u origin master # 将本地主分支推到远程(如无远程主分支则创建,用于初始化远程仓库) git push origin # 创建远程分支, origin是远程仓库名 git push origin : # 创建远程分支 git push origin : #先删除本地分支(git br -d ),然后再push删除远程分支 Git远程仓库管理 git remote -v # 查看远程服务器地址和仓库名称 git remote show origin # 查看远程服务器仓库状态 git remote add origin git@ github:robbin/robbin_site.git # 添加远程仓库地址 git remote set-url origin git@ github.com:robbin/robbin_site.git # 设置远程仓库地址(用于修改远程仓库地址) git remote rm # 删除远程仓库 创建远程仓库 git clone –bare robbin_site robbin_site.git # 用带版本的项目创建纯版本仓库 scp -r my_project.git git@ git.csdn.net:~ # 将纯仓库上传到服务器上 mkdir robbin_site.git && cd robbin_site.git && git –bare init # 在服务器创建纯仓库 git remote add origin git@ github.com:robbin/robbin_site.git # 设置远程仓库地址 git push -u origin master # 客户端首次提交 git push -u origin develop # 首次将本地develop分支提交到远程develop分支,并且track git remote set-head origin master # 设置远程仓库的HEAD指向master分支 也可以命令设置跟踪远程库和本地库 git branch –set-upstream master origin/master git branch –set-upstream develop origin/develop 本文转自rshare 51CTO博客,原文链接:http://blog.51cto.com/1364952/1954056,如需转载请自行联系原作者
参考: http://www.ibm.com/developerworks/cn/aix/library/au-cn-pagingspace/AIX操作系统中Paging Space是很重要的设备,当系统中Paging Space使用率过高、系统内存不足时,将影响系统的整体性能,甚至会造成系统的挂起。针对这种情况,通常可以靠增加Paging Space来加以缓解;但是当Paging Space已经相当大,而Paging Space使用率仍旧居高不下时,则需要通过进一步的分析来找出原因并加以解决。文中分析了几种Paging Space使用率持续增长直至过高的常见原因,并给出了相应的解决方案,以确保Paging Space使用率被控制在安全的范围内。1 Paging Space的创建原则AIX中Paging Space大小确定的指导原则如下:系统实际内存小于64MB, paging space= 2 * RAM ; 系统实际内存在 64MB to 256MB 之间, Page Space = RAM size + 16MB ; 系统实际内存大于 256MB , Page Space = 512 + ( RAM - 256 ) * 1.25 ; 当内存超过4GB时,则需要根据实际情况来定,一般可初始3GB, 然后观察paging space的使用情况,如果使用率超过70%, 则需要增加paging space 或把OS中的min_perm%,max_perm%和max_client%参数调小一点。 此外在创建Paging Space时还应遵循以下原则以提高性能:创建的数量应尽可能的多; 每个Paging Space的大小应该相同; 每个Paging Space应尽可能的分配在不同的硬盘上。 AIX中可以通过命令lsps -s查看Paging Space的使用情况。列Total Paging Space给出的是系统总的Paging Space空间大小,Percent Used则表示已被占用的Paging Space的百分比。eg:# lsps -sTotal Paging Space Percent Used 16384MB 1% 命令lsps -a可以用来查看Paging Space的分布情况# lsps -aPage Space Physical Volume Volume Group Size %Used Active Auto Typehd6 hdisk0 rootvg 16384MB 1 yes yes lv 2 文件型内存对Paging Space使用率的影响 在AIX系统中,内存可以简单的分为两类:计算型内存和文件型内存。类似大量文件类操作,如压缩、数据库的dump/load等操作会大量占用文件型内存。如果按照系统缺省的配置,文件型内存最多会占用到内存总量的80%,由于文件型内存占用并不主动释放,从而可能造成内存资源的短缺及Paging Space使用率过高。命令topas可以用来查看文件型内存占用内存情况,在MEMORY一栏中的%Noncomp显示的是文件型内存的占用百分比。Topas Monitor for host: hostname EVENTS/QUEUES FILE/TTYFri Jul 31 13:15:39 2009 Interval: 2 Cswitch 1489 Readch 2896.8K Syscall 7341 Writech 17338Kernel 1.2 |# | Reads 327 Rawin 0User 18.0 |###### | Writes 13 Ttyout 373Wait 13.4 |#### | Forks 0 Igets 0Idle 67.5 |#################### | Execs 0 Namei 33 Runqueue 1.5 Dirblk 0Network KBPS I-Pack O-Pack KB-In KB-Out Waitqueue 0.0en2 2.5 8.0 4.0 1.3 1.2en0 1.1 2.0 2.0 0.4 0.7 PAGING MEMORYlo0 0.0 0.0 0.0 0.0 0.0 Faults 174 Real,MB 7808 Steals 0 % Comp 83.3Disk Busy% KBPS TPS KB-Read KB-Writ PgspIn 0 % Noncomp 2.5hdisk3 27.5 2924.0 322.0 2910.0 14.0 PgspOut 0 % Client 3.2hdisk0 1.0 4.0 1.0 2.0 2.0 PageIn 1hdisk1 0.5 2.0 0.5 0.0 2.0 PageOut 1 PAGING SPACEdac0 0.0 0.0 0.0 0.0 0.0 Sios 2 Size,MB 16384dac0-utm 0.0 0.0 0.0 0.0 0.0 % Used 0.6dac5 0.0 2924.0 322.0 2910.0 14.0 NFS (calls/sec) % Free 99.3dac5-utm 0.0 0.0 0.0 0.0 0.0 ServerV2 0dac2 0.0 0.0 0.0 0.0 0.0 ClientV2 0 Press:dac4 0.0 0.0 0.0 0.0 0.0 ServerV3 0 "h" for helpcd0 0.0 0.0 0.0 0.0 0.0 ClientV3 0 "q" to quitdac4-utm 0.0 0.0 0.0 0.0 0.0hdisk2 0.0 0.0 0.0 0.0 0.0dac2-utm 0.0 0.0 0.0 0.0 0.0Name PID CPU% PgSp Owneroracle 438598 22.1 7.2 oracleoracle 741490 3.6 5.5 oracletopas 975296 0.3 2.1 rootoracle 897480 0.0 4.2 oraclehats_nim 225330 0.0 1.8 root aioserve 242162 0.0 0.1 root oracle 901544 0.0 4.2 oraclegil 28972 0.0 0.1 rootaioserve 315456 0.0 0.1 root aioserve 118860 0.0 0.1 root aioserve 381290 0.0 0.1 rootaioserve 323656 0.0 0.1 root hatsd 151846 0.0 8.2 root oracle 188724 0.0 7.1 oracle如果文件型内存所占比例很高,而Paging Space使用率居高不下时,可以通过降低minperm、maxperm的参数值来进行调优,减少文件型内存可占用的份额。在进行调整前,首先通过命令vmo -a/vmtune -a来查看目前的参数值;minperm及maxperm的缺省值分别是30%和80%。# vmo -acpu_scale_memp = 8data_stagger_interval = 161defps = 1force_relalias_lite = 0framesets = 2htabscale = n/akernel_heap_psize = 4096large_page_heap_size = 0lgpg_regions = 0lgpg_size = 0low_ps_handling = 1lru_file_repage = 1lru_poll_interval = 10lrubucket = 131072maxclient% = 10maxfree = 1088maxperm = 192213maxperm% = 10maxpin = 1613727maxpin% = 80mbuf_heap_psize = 4096memory_affinity = 1memory_frames = 1998848memplace_data = 2memplace_mapped_file = 2memplace_shm_anonymous = 2memplace_shm_named = 2memplace_stack = 2memplace_text = 2memplace_unmapped_file = 2mempools = 0minfree = 960minperm = 96106minperm% = 5nokilluid = 0npskill = 32768npsrpgmax = 262144npsrpgmin = 196608npsscrubmax = 262144npsscrubmin = 196608npswarn = 131072num_spec_dataseg = 0numpsblks = 4194304page_steal_method = 0pagecoloring = n/apinnable_frames = 637301pta_balance_threshold = n/arelalias_percentage = 0rpgclean = 0rpgcontrol = 2scrub = 0scrubclean = 0soft_min_lgpgs_vmpool = 0spec_dataseg_int = 512strict_maxclient = 1strict_maxperm = 0v_pinshm = 1vm_modlist_threshold = -1vmm_fork_policy = 1#说明:(1) minperm%如果由文件页面占有的实际内存的百分比低于这个级别,则页面替换算法既替换文件页面也替换计算页面,而不管repage rate。 # vmo -a |grep minperm%minperm% = 20(2) maxperm%如果由文件页面占有的实际内存的百分比高于这个级别,则页面替换算法仅替换文件页面。 # vmo -a |grep maxperm%maxperm% = 80(3) maxclient%如果由文件页面占有的实际内存的百分比高于这个级别,则页面替换算法仅替换客户机页面。# vmo -a |grep maxclient%maxclient% = 80这三个参数,可以根据内存总量大小,进行适度调节。计算型内存与文件型内存,在实际的应用中,需要遵循以下一些原则(这些原则是自己归纳的): 1.使用的文件型内存百分比 + 使用的计算型内存百分比 < 100% 2.计算型内存中的pinned memory设置要合理,即sga大小要设置合理,要留一部份给OS,OS也需要pinned memory.当系统资源紧张时,OS的pinned memory具有最高的优先级. 3.保证系统非pinned 计算型 memory有一个合理的成长空间,这部份主要是给ORACLE PGA使用,当连接数增长过 快时,此内存的使用增长也相当的明显,而此增长很有可能会导致操作系统的交换。当系统的使用的文件型内存百分比 + 使用的计算型内存百分比 >= 100%,系统便开始产生交换,系统的PAGING SPACE会持续的增长,影响到产品库的安全。 恰当的设置OS内存参数,控制操作系统的交换,可以减少很多系统不稳定的情况发生。比如说操作系统执行重启命令都执行不了: shutdown -Fr当由文件页面占有的实际内存的百分比处于 minperm 和 maxperm 之间时,VMM通常只替换文件页面,但是如果文件页面的重新调页(repaging)率高于计算页面的重新调页率的话,计算页面也被替换。页面替换算法的主要意图是确保计算页面得到合理的待遇。例如,对于可能会很快再次使用的程序文本页,顺序读取长的数据文件到内存中应该不会使它们丢失。对阈值和重新调页率使用页面替换算法可确保合理地对待这两种类型的页面,但仍稍微偏向有利于计算页面的一方。通过vmstat -v可以看到当前persistent或者client page的数目和百分比,可以作为系统调优的依据.# vmstat -v4079616 memory pages3870685 lruable pages601736 free pages2 memory pools535883 pinned pages80.0 maxpin percentage20.0 minperm percentage80.0 maxperm percentage66.2 numperm percentage2565739 file pages0.0 compressed percentage0 compressed pages66.7 numclient percentage80.0 maxclient percentage2583086 client pages0 remote pageouts scheduled28222 pending disk I/Os blocked with no pbuf0 paging space I/Os blocked with no psbuf2740 filesystem I/Os blocked with no fsbuf0 client filesystem I/Os blocked with no fsbuf106338 external pager filesystem I/Os blocked with no fsbufList-based LRU (page_steal_method)在AIX 5.3, LRU算法可以用lists或者page frame table,在AIX 5.3之前,只有page frametable的算法, The list-based algorithm provides a list of pages to scan foreach type of segment. 下面是段类型的列表:Working Persistent Client Compressed # vmo -a |grep page_steal_methodpage_steal_method = 0如果page_steal_method = 1, 将采用list-based LRU算法, 如果page_steal_methodparameter 为 0, 将采用physical-address-based scanning的方式.page_steal_method参数值只有在bosboot and reboot后生效.# vmo -L page_steal_methodNAME CUR DEF BOOT MIN MAX UNIT TYPEDEPENDENCIES-------------------------------------------------------------------------------page_steal_method 0 0 0 0 1 boolean B-------------------------------------------------------------------------------strict_maxperm 缺省为0. 当strict_maxperm 设置成 1, places a hard limit on how much memoryis used for a persistent file cache by making the maxperm value be theupper limit for this file cache. 当达到上线的时候least recently used(LRU)将执行在persistent pages上.# vmo -a |grep strict_maxpermstrict_maxperm = 0Enhanced JFS file system cache 相关的参数: maxclient, strict_maxclient和lru_file_repageEnhanced JFS file system cache使用client page来作为buffercache,通过maxclient%来控制page stealing. 如果strict_maxlient设置为0,maxclient%将用来作为一个soft limit. 也就是说clientpages可以超过maxclient参数,如果超过这个值,只有client file page被stolen.当lru_file_repage设置为1的时候,如果client pages的数目介于minperm和maxclient之间,LRU算法将参考repage的计数. 最近没有被referenced的page将被stolen. If the value of thefile repage counter is higher than the value of the computationalrepage counter, computational pages, which are the working storage, areselected for replacement. If the value of the computational repagecounter exceeds the value of the file repage counter, file pages areselected for replacement.当lru_file_repage设置为0的时候, 如果client pages的数目大于minperm,将选择file pages被替换.如果小于minperm,任何没有被referenced的page将被替换.注意:maxclient同样影响NFS client和compressed pages.# vmo -a |grep lru_file_repagelru_file_repage = 1# vmo -a |grep strict_maxclientstrict_maxclient = 1工程经验内存调优主要集中在几个关键参数中,往往这几个关键参数就能很大地提高系统的内存使用性能. 这几个参数是minperm%, maxperm%, maxclient%和lru_file_repage. 原则:首先了解你的应用类型,是文件读写型还是数据库类型. 尽量保证你的应用运行所需要的数据充分地利用物理内存. 具体的工程Tips例子请参见内存调优的工程经验篇 3 应用程序内存泄露对Paging Space使用率的影响应用程序的内存泄露也是造成Paging Space使用率不断增长的另一常见原因,此类情况的解决方法主要是找出内存泄露的应用,然后进行修正或安装补丁。以下方法可用来找出发生内存泄露的应用: 该命令每m秒钟按降序列出前n个最耗内存进程。为了便于分析,可以将结果输出到文件中,然后对内容进行分析,从而找出内存泄露的应用。下例中命令svmon -P -t 10 -i 5的结果被输出到文件svmonresult.txt中,该命令每5秒种输出一次最耗内存的前10个进程。 svmon -P -t 10 -i 5 > svmonresult.txt找出发生内存泄露的应用后可自行进行修正或查找相关的补丁进行安装。4 数据库参数配置对Paging Space使用率的影响在装有数据库的系统环境中,数据库相关参数的设置不当也容易造成Paging Space的占用率过高 本文转自glying 51CTO博客,原文链接:http://blog.51cto.com/liying/968600,如需转载请自行联系原作者
常有Linux用户询问,为什么利用du和df查看磁盘容量的结果不一致,是否是有bug或者有磁盘碎块,或该以哪个结果为准。而实际上两个命令得出的值是不一致的由于du与df命令实施上的不同,而非故障。 [root@www ~]# du -sh /home 4.7G /home [root@www ~]# df -h /home Filesystem Size Used Avail Use% Mounted on /dev/sda5 15G 4.9G 8.9G 36% /home [root@www ~]# 从上图能够看出,/home 分区的容量,使用df查看是4.9GB,而使用du查看是4.7GB。 du -s 命令通过将指定文件系统中所有的目录、符号链接和文件使用的块数累加得到该文件系统使用的总块数。 df 命令通过查看文件系统磁盘块分配图得出总块数与剩余块数。文件系统分配其中的一些磁盘块用来记录它自身的一些数据,如i节点,磁盘分布图,间接块,超级块等。这些数据对大多数用户级的程序来说是不可见的,通常称为Meta Data。 du 命令是用户级的程序,它不考虑Meta Data,而df命令则查看文件系统的磁盘分配图并考虑Meta Data。df命令获得真正的文件系统数据,而du命令只查看文件系统的部分情况。 本文转自glying 51CTO博客,原文链接:http://blog.51cto.com/liying/967715,如需转载请自行联系原作者
系统的时间和真实时间相差12小时,网上百度都是关于8小时设置的,so,采用如下方法: 使用CRT的多窗口交互模式批量执行: 先设置日期:date -s 20151015 再设置时间:date -s 11:27:00 硬件时间同步:hwclock -w 可悲,重启后时间依然是原先的,可能是BIOS的时间有问题,重启的时候会读BIOS的时间 http://www.2cto.com/os/201306/220722.html 本文转自Tenderrain 51CTO博客,原文链接:http://blog.51cto.com/tenderrain/1703106,如需转载请自行联系原作者
如何导出cer证书的Base64编码信息 1、将证书双击,安装到IE中,如果是个人证书会安装到:在IE的 工具 -> internet选项 -> 内容 -> 证书 -> 个人2、打开IE,在在IE的 工具 -> internet选项 -> 内容 -> 证书 -> 个人 中,找到这张证书,选中它3、点击“导出”按钮4、点击“下一步”,再点击“下一步”5、选择“Base64编码X.509(.cer)”6、点击“下一步”,一直到保存完毕OK,cer证书的Base64编码格式已经生成完毕。 证书链的生成: 需导出如下两个证书: 方法: internet选项 -> 内容 -> 证书 -> 个人2、打开IE,在在IE的 工具 -> internet选项 -> 内容 -> 证书 -> 个人 中,找到这张证书,选中它3、点击“导出”按钮4、点击“下一步”,再点击“下一步”5、选择“Base64编码X.509(.cer)”6、点击“下一步”,一直到保存完毕OK,cer证书的Base64编码格式已经生成完毕。 生成证书链: 根证书:cat 11111111.cer > maoyan.com.chain.crt 中间证书:cat 22222.cer >> maoyan.com.chain.crt 域证书:cat maoyan.com.crt >> maoyan.com.chain.crt maoyan.com.chain.crt 就是链证书 参考:https://help.aliyun.com/knowledge_detail/13094677.html?pos=2 本文转自Tenderrain 51CTO博客,原文链接:http://blog.51cto.com/tenderrain/1782652,如需转载请自行联系原作者
1,安装依赖的库和包,否则编译会报错 apt-get install gcc libpcre3 libpcre3-dev openssl libssl-dev make 2,下载附件中的nginx-1.8.1.tar.gz 及nginx-sticky-module-1.1.tar.gz 备注: nginx-sticky-module-1.1模块在附件中,下载附件后,重命名 mv aa.txt nginx-sticky-module-1.1.tar.gz mv nginx-1.8.1.txt nginx-1.8.1.tar.gz tar xf nginx-1.8.1.tar.gz mkdir /usr/local/nginx-sticky-module-1.1/ tar xf nginx-sticky-module-1.1.tar.gz -C /usr/local/nginx-sticky-module-1.1/ cd nginx-1.8.1/ 3,编译安装nginx ./configure --prefix=/usr/local/nginx-1.8.1 --with-http_stub_status_module --with-http_ssl_module --with-http_realip_module --add-module=/usr/local/nginx-sticky-module-1.1/nginx-sticky-module-1.1 会报错,根据错误提示修改文件(参考http://tenderrain.blog.51cto.com/9202912/1880880) vim /usr/local/nginx-sticky-module-1.1/nginx-sticky-module-1.1/ngx_http_sticky_misc.c +281 make make install 4,配置nginx.conf cd /usr/local/nginx-1.8.1/conf cat nginx.conf 内容如下: worker_processes 5; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; sendfile on; keepalive_timeout 65; map $cookie_jsessionid $route_cookie { ~.+\.(?P<route>\w+)$ $route; } map $request_uri $route_uri { ~jsessionid=.+\.(?P<route>\w+)$ $route; } upstream jiracluster { server 10.32.115.91:8090; server 10.32.115.92:8090; sticky; } server { listen 80; server_name 10.32.116.28; location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://jiracluster; } error_log /tmp/error.log; access_log /tmp/access.log; } } 5,检测语法,启动nginx /usr/local/nginx-1.8.1/sbin/nginx -t /usr/local/nginx-1.8.1/sbin/nginx /usr/local/nginx-1.8.1/sbin/nginx -t /usr/local/nginx-1.8.1/sbin/nginx -s reload 其实session持久化就nginx本身而言是有三种方式的 cookie route learn http://nginx.org/en/docs/http/ngx_http_upstream_module.html http://blog.csdn.net/agangdi/article/details/41087921 附件:http://down.51cto.com/data/2368461 本文转自Tenderrain 51CTO博客,原文链接:http://blog.51cto.com/tenderrain/1881186,如需转载请自行联系原作者
四、提交与历史 了解了文件的状态,我们对文件进行了必要的修改后,就要把我们所做的修改放入版本库了,这样以后我们就可以在需要的时候恢复到现在的版本,而要恢复到某一版,一般需要查看版本的历史。 提交 提交很简单,直接执行"git commit"。执行git commit后会调用默认的或我们设置的编译器要我们填写提示说明,但是提交说明最好按GIT要求填写:第一行填简单说明,隔一行填写详细说明。因为第一行在一些情况下会被提取使用,比如查看简短提交历史或向别人提交补丁,所以字符数不应太多,40为好。下面看一下查看提交历史。 查看提交历史 查看提交历史使用如下图的命令 如图所示,显示了作者,作者邮箱,提交说明与提交时间,"git log"可以使用放多参数,比如: 仅显示最新的1个log,用"-n"表示。 显示简单的SHA-1值与简单提交说明,oneline仅显示提交说明的第一行,所以第一行说明最好简单点方便在一行显示。 "git log --graph"以图形化的方式显示提交历史的关系,这就可以方便地查看提交历史的分支信息,当然是控制台用字符画出来的图形。 "git log"的更多参数可以查看命令帮助。 不经过暂存的提交 如果我们想跳过暂存区直接提交修改的文件,可以使用"-a"参数,但要慎重,别一不小心提交了不想提交的文件 git commit -a 如果需要快捷地填写提交说明可使用"-m"参数 git commit -m 'commit message' 修订提交 如果我们提交过后发现有个文件改错了,或者只是想修改提交说明,这时可以对相应文件做出修改,将修改过的文件通过"git add"添加到暂存区,然后执行以下命令: git commit --amend 然后修改提交说明覆盖上次提交,但只能重写最后一次提交。 重排提交 通过衍合(rebase)可以修改多个提交的说明,并可以重排提交历史,拆分、合并提交,关于rebase在讲到分支时再说,这里先看一下重排提交。 假设我们的提交历史是这样的: 如果我们想重排最后两个提交的提交历史,可以借助交互式rebase命令: git rebase -i HEAD~2 或 git rebase -i 3366e1123010e7d67620ff86040a061ae76de0c8 HEAD~2表示倒数第三个提交,这条命令要指定要重排的最旧的提交的父提交,此处要重排Second commit与Third commit,所以要指定Initial commit的Commit ID。如图所示: 注释部分详细说明了每个选项的作用,如果我们想交互这两个提交,只需把开头的这两行交换下位置就OK了,交换位置后保存,然后看下提交历史: 可以看到提交历史已经变了,而且最新的两个提交的Commit ID变了,如果这些提交已经push到了远程服务器,就不要用这个命令了。 删除提交与修改提交说明 如果要删除某个提交,只需要删除相应的行就可以了,而要修改某个提交的提交说明的话,只需要把相应行的pick改为reward。 合并提交-squashing 合并提交也很简单,从注释中的说明看,只需要把相应的行的pick改为squash就可以把这个提交全并到它上一行的提交中。 拆分提交 至于拆分提交,由于Git不可能知道你要做哪里把某一提交拆分开,把以我们就需要让Git在需要拆分的提交处停下来,由我们手动修改提交,这时要把pick改为edit,这样Git在处理到这个提交时会停下来,此时我们就可以进行相应的修改并多次提交来拆分提交。 撤销提交 前面说了删除提交的方法,但是如果是多人合作的话,如果某个提交已经Push到远程仓库,是不可以用那种方法删除提交的,这时就要撤销提交 git revert <commit-id> 这条命令会把指定的提交的所有修改回滚,并同时生成一个新的提交。 Reset git reset会修改HEAD到指定的状态,用法为 git reset [options] <commit> 这条命令会使HEAD提向指定的Commit,一般会用到3个参数,这3个参数会影响到工作区与暂存区中的修改: --soft: 只改变HEAD的State,不更改工作区与暂存区的内容 --mixed(默认): 撤销暂存区的修改,暂存区的修改会转移到工作区 --hard: 撤销工作区与暂存区的修改 cherry-pick 当与别人和作开发时,会向别人贡献代码或者接收别人贡献的代码,有时候可能不想完全Merge别人贡献的代码,只想要其中的某一个提交,这时就可以使用cherry-pick了。就一个命令 git cherry-pick <commit-id> filter-branch 这条命令可以修改整个历史,如从所有历史中删除某个文件相关的信息,全局性地更换电子邮件地址。 本文转自Tenderrain 51CTO博客,原文链接:http://blog.51cto.com/tenderrain/1881969,如需转载请自行联系原作者
1.使用NAT模型的TCP协议类型的lvs服务负载均衡一个php应用,如Discuz!论坛或者phpMyAdmin; 2.使用DR模型的FWM类型的lvs服务负载均衡一个php应用,如Discuz!论坛或者phpMyAdmin; 注意:以上两个集群需要考虑两个问题: 1) 是否需要会话保持; 2) 是否需要共享存储; 1.使用NAT模型负载均衡wordpress 环境部署: serverA :调度器 外网:172.16.1.2 内网:192.168.100.7 serverB :rs1 内网:192.168.100.8 serverC :rs2 内网:192.168.100.9 serverD :nfs服务器 内网:192.168.100.6 大致拓扑图: 80050122e29f033afaee58e09baafdf1.png 注意: (1)配置之前把所有主机的防火墙和SElinux关闭,方便实验 ~]# iptables -F && setenforce 0 && systemctl stop firewalld.service (2)同步时间 时间同步是最重要的环节,Director和后台的RealServer的时间必须同步,并且时间差小于1秒钟。 本次我们使用Director服务器作为时间服务器,全部都向它来同步时间。 ~]# service ntpd restart # 重启ntp服务器 Shutting down ntpd: [ OK ] Starting ntpd: [ OK ] ~]# ntpdate 192.168.100.7 # 客户端同步三台都要同步这里我们就不多说了 rs1配置 安装服务 yum -y install httpd php php-mysql 设置网关 route add default gw 192.168.100.7 配置主页信息 echo "rs1.zrs.com" > /var/www/html/index.html 启动服务 systemctl start httpd.service 查看一下 ~]# curl http://localhost rs1.zrs.com rs2配置 安装服务 yum -y install httpd php php-mysql 设置网关 route add default gw 192.168.100.7 配置主页信息 echo "rs2.zrs.com" > /var/www/html/index.html 启动服务 systemctl start httpd.service 查看一下 ~]# curl http://localhost rs2.zrs.com 调度器配置 测试rs1和rs2主机能否正常通信: ping 192.168.100.8 ping 192.168.100.9 curl http://192.168.10.8 curl http://192.168.10.9 安装lvs软件包 yum -y install ipvsadm 开启核心转发功能 ~]# echo 1 > /proc/sys/net/ipv4/ip_forward 创建集群 ~]# ipvsadm -A -t 172.16.1.2:80 -s rr ~]# ipvsadm -a -t 172.16.1.2:80 -r 192.168.100.8 -m ~]# ipvsadm -a -t 172.16.1.2:80 -r 192.168.100.9 -m 查看集群 ~]# ipvsadm -l -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.16.1.2:80 rr -> 192.168.100.8:80 Masq 1 0 0 -> 192.168.100.9:80 Masq 1 0 0 由于这个集群使用的是rr(轮询)算法,所以rs1和rs2交替被访问 客户端测试 ee91477c9e9ba7822b24da77a5e687e9.png d6703d65b968673b1389966f383a8191.png 循环测试 ~]# for i in {1..10};do curl http://172.16.1.2 ;done rs1.zrs.com rs2.zrs.com rs1.zrs.com rs2.zrs.com rs1.zrs.com rs2.zrs.com rs1.zrs.com rs2.zrs.com rs1.zrs.com rs2.zrs.com 可以保存一下规则,重启后可继续适用 ipvsadm -S > /etc/sysconfig/ipvsadm.web 重载规则 ipvsadm -R < /etc/sysconfig/ipvsadm.web nfs服务器配置 1.安装所需软件包 yum -y install nfs-utils 2.准备用户apache(访问NFS服务时映射为的用户) useradd -u 48 apache 3.准备需要导出的目录,且其属主、属组为apahce install -o apache -g apache -d /data/application/web 4.下载wordpress程序包并解压至/data/application/web目录下,并将其属主、属组改为apache,wordpress目录下的wp-content目录的权限改为777(上传图片时需要写权限) unzip wordpress-4.3.1.-zh_CN.zip mv wordpress /data/application/web cd /data/application/web chown -R apache.apache wordpress chmod 777 wordpress/wp-content 5.在wordpress目录下,修改配置文件 : mv wp-config-sample.php wp-config.php vim wp-config.php /* WordPress数据库的名称/ define('DB_NAME', 'wpdb'); /** MySQL数据库用户名 */ define('DB_USER', 'wpuser'); /** MySQL数据库密码 */ define('DB_PASSWORD', '123456'); /** MySQL主机 */ define('DB_HOST', '192.168.100.6'); 6.编辑nfs配置文件,将/data/application/web目录导出,允许192.168.10.0/24网段连接,导出属性为rw,async,用户映射为apache。 vim /etc/exports /data/application/web 192.168.10.0/24(rw,async,anonuid=48,anongid=48) 7.启动mysql服务,创建数据库wpdb和dzdb,并分别授权用户wpuser对wpdb数据库下的所有表拥有所有权限,dzuser对dzdb数据库下的所有表拥有所有权限; yum -y install mariadb-server php-mysql systemctl start mariadb.service MariaDB [(none)]> CREATE DATABASE wpdb; MariaDB [(none)]> grant all on wpdb.* to 'wpuser'@'192.168.%.%' identified by '123456'; MariaDB [(none)]> FLUSH PRIVILEGES; rs1和rs2 创建session目录,存放会话,更改属组属主为apache ~]# ll -d /var/lib/php/session/ drwxr-xr-x. 2 apache apache 4096 10月 21 10:28 /var/lib/php/session/ 将D主机nfs服务器上导出的目录挂载至/var/www/html目录下 mount.nfs 192.168.100.6:/data/application/web /var/www/html 客户端测试 e776401c92b9a325d6d22d4387c17e99.png 2.使用DR模型的FWM类型的lvs服务负载均衡wordpress 环境部署: serverA :调度器 VIP:172.16.1.2 DIP:172.16.1.100 serverB :rs1 RIP1:172.16.1.3 serverC :rs2 RIP2:172.16.1.4 serverD :nfs服务器 nfs:172.16.1.5 大致拓扑图: 76d35b0d9baf59af63ae2677524a0a89.png 注意: 和上面的nat模型一样需要注意时间同步和防火墙及SElinux的设置,在这里就不再赘述。 调度器主机: 安装一个仅主机的网卡地址为172.16.1.100,此ip地址为DIP VIP配置在接口的别名上,如下配置 [root@zj02 ~]# ifconfig eno16777736:0 172.16.1.2 netmask 255.255.255.255 broadcast 172.16.1.2 up c9a43c689079fd6b2b0f72d040a3523a.png 安装lvs软件包 yum -y install ipvsadm 集群配置 设置FWH规则: [root@zj02 ~]# iptables -t mangle -A PREROUTING -p tcp --dport 80 -d 172.16.1.2 -j MARK --set-mark 6 [root@zj02 ~]# ipvsadm -A -f 6 -s rr [root@zj02 ~]# ipvsadm -a -f 6 -r 172.16.1.3:80 -g [root@zj02 ~]# ipvsadm -a -f 6 -r 172.16.1.4:80 -g [root@zj02 ~]# ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn FWM 6 rr -> 172.16.1.3:80 Route 1 0 0 -> 172.16.1.4:80 Route 1 0 0 开启核心转发功能 ~]# echo 1 > /proc/sys/net/ipv4/ip_forward rs1&rs2配置 安装服务 yum -y install httpd php php-mysql 配置主页信息 echo "<h1>rs1.zrs.com</h1>" > /var/www/html/index.html echo "<h1>rs2.zrs.com</h1>" > /var/www/html/index.html 启动服务 systemctl start httpd.service 在DR模型中,各个主机均需要配置VIP;为了解决地址冲突可以修改对应的内核参数,来限制ARP的通告和应答的级别 arp_ignore: 0:默认值,对于从任何网络接口接收到对本机任意IP地址的ARP查询请求均予以回应; 1:只应答目标IP地址是入站接口上配置的IP地址所在网段的IP地址的ARP请求; 2:只应答目标IP地址是入站接口上配置的IP地址所在网段的IP地址的ARP请求,且来访IP地址也必须与该接口的IP地址在同一子网中; 3:不响应该网络接口的ARP请求,而只对设置为全局的IP地址做应答; 4-7:保留; 8:不应答所有的ARP请求; arp_announce: 0:默认值,将本机所有接口的信息向所有接口所连接的网络中通告; 1:尽量避免向与本接口不同网络中的其他接口通告; 2:绝对避免向非本网络的主机通告; 可以用脚本实现 ~]# vim arp_para.sh #!/bin/bash # VIP=172.16.1.2 MASK=255.255.255.255 case $1 in start) echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce ifconfig lo:0 $VIP netmask $MASK broadcast $VIP up route add -host $VIP dev lo:0 ;; stop) ifconfig lo:0 down echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce ;; *) echo "Usage: $(basename $0) { start | stop }" ;; esac ~]# chmod +x arp_para.sh ///赋予执行权限 ~]# ./arp_para.sh start ///运行脚本环境即可配置成功 客户端测试 49f74c96f395815a30a32890c37fd181.png 87cd8bacb5534ed936a14057153a0763.png nfs共享存储服务器配置 和上面的nat模型基本一样,在这里就不再赘述,需要注意的是更改/etc/exports此文件中的网段为本次dr模型实验的网段。 最后同样将共享目录分别挂载到rs1和rs2中,可以用mount命令查看挂载信息: ebfc50bc9d8838b0039e197ed5d243e5.png 客户端测试 3aaa0b2ac6eb190d311ca03eafe76985.png 本文转自Vincent一马 51CTO博客,原文链接:http://blog.51cto.com/mazhenbo/2044985,如需转载请自行联系原作者
分别基于mysqldump、lvm2、xtrabackup三种方式实现MySQL备份恢复 一、利用mysqldump实施逻辑备份操作 1.在/etc/my.cnf中添加如下,开启二进制日志 innodb-file-per-table = ON skip-name-resolve=ON log_bin=/var/log/maradb/binlog 2.备份数据,锁表,二进制日志做滚动,CHANGE MASTER TO设置为2让语句被注释 [root@zj07 ~]# mysqldump -uroot -hlocalhost zrs --lock-tables --flush-logs --master-data=2 > /tmp/zrs.1.sql 查看日志存放位置,出现2,即日志发生滚动 [root@zj07 ~]# ls /var/log/mariadb binlog.000001 binlog.000002 binlog.index mariadb.log 添加数据库结构,即显示数据库的创建和使用 --databases [root@zj07 ~]# mysqldump -uroot -hlocalhost --databases zrs --lock-tables --flush-logs --master-data=2 > /tmp/zrs.2.sql 备份整个服务器的数据库 --all-databases [root@zj07 ~]# mysqldump -uroot -hlocalhost --all-databases --lock-tables --flush-logs --master-data=2 > /tmp/myserver.1.sql 3.模拟故障 进程崩溃 [root@zj07 ~]# killall mysqld mysqld_safe 所有的库文件丢失 [root@zj07 ~]# rm -rf /var/lib/mysql/* 4.恢复备份 先启动服务 [root@zj07 ~]# systemctl start mariadb 查看已经生成修复的库文件 [root@zj07 ~]# ls /var/lib/mysql/ aria_log.00000001 ibdata1 ib_logfile1 mysql.sock test aria_log_control ib_logfile0 mysql performance_schema 因为恢复的过程,也会产生命令记录,导致数据改变,所以强制不让其记录到二进制 [root@zj07 ~]# mysql 仅设置当前会话即可 MariaDB [(none)]> set @@session.sql_log_bin=OFF; 恢复数据 MariaDB [(none)]> source /tmp/myserver.1.sql 再开启二进制记录 MariaDB [zrs]> set @@session.sql_log_bin=ON; 5.当恢复数据后,需要删除备份,再重新备份,备份数据仅使用一次。 二、利用lvm2实现物理备份操作 温备份(几乎热备) 1.先创建一个分区 [root@zj07 ~]# fdisk /dev/sda 命令(输入 m 获取帮助):n Partition type: p primary (2 primary, 0 extended, 2 free) e extended Select (default p): Using default response p 分区号 (3,4,默认 3): 起始 扇区 (109684736-167772159,默认为 109684736): 将使用默认值 109684736 Last 扇区, +扇区 or +size{K,M,G} (109684736-167772159,默认为 167772159):+20G 分区 3 已设置为 Linux 类型,大小设为 20 GiB 命令(输入 m 获取帮助):t 分区号 (1-3,默认 3):3 Hex 代码(输入 L 列出所有代码):8e 已将分区“Linux”的类型更改为“Linux LVM” 命令(输入 m 获取帮助):w partprobe一下 [root@zj07 ~]# partprobe /dev/sda 查看刚才创建的分区是否存在 [root@zj07 ~]# cat /proc/partitions 做物理卷 [root@zj07 ~]# pvcreate /dev/sda3 Physical volume "/dev/sda3" successfully created. 做卷组 [root@zj07 ~]# vgcreate datavg /dev/sda3 Volume group "datavg" successfully created 创建逻辑卷,指定名字 [root@zj07 ~]# lvcreate -L 8G -n mydata datavg Logical volume "mydata" created. 查看 [root@zj07 ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert root centos -wi-ao---- 50.00g swap centos -wi-ao---- 2.00g mydata datavg -wi-a----- 8.00g [root@zj07 ~]# ls /dev/mapper/ centos-root centos-swap control datavg-mydata [root@zj07 ~]# ls /dev/datavg/ mydata 格式化 [root@zj07 ~]# mke2fs -b 2048 -t ext4 /dev/datavg/mydata [root@zj07 ~]# blkid /dev/datavg/mydata /dev/datavg/mydata: UUID="95e9edc9-257a-49c6-b44b-235f18af371d" TYPE="ext4" 创建目录 [root@zj07 ~]# mkdir -pv /data/mydata 挂载这个lvm到创建的目录下,在配置文件中,添加如下 [root@zj07 ~]# vim /etc/fstab UUID="95e9edc9-257a-49c6-b44b-235f18af371d" /data/mydata ext4 defaults,acl 0 0 查看 [root@zj07 ~]# mount -a [root@zj07 ~]# df 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/mapper/centos-root 52403200 4552636 47850564 9% / ... ... ... /dev/mapper/datavg-mydata 8190760 12308 7750830 1% /data/mydata 更改该目录的属主属组 [root@zj07 ~]# chown -R mysql.mysql /data/* 修改配置文件 [root@zj07 ~]# vim /etc/my.cnf [mysqld] datadir=/data/mydata socket=/data/mydata/mysql.sock 2.模拟故障 进程崩溃 [root@zj07 ~]# killall mysqld mysqld_safe 所有的库文件丢失 [root@zj07 ~]# rm -rf /var/lib/mysql/* 3.恢复备份 先启动服务 [root@zj07 ~]# systemctl start mariadb 当更改sock文件后,进入mysql会提示错误,可以如下设置配置文件,即可。 [root@zj07 ~]# mysql ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) [root@zj07 ~]# vim .my.cnf [client] socket='/data/mydata/mysql.sock' 关闭二进制日志记录,恢复备份,再开启二进制日志记录。 MariaDB [(none)]> set @@session.sql_log_bin=OFF; MariaDB [(none)]> source /tmp/myserver.1.sql; MariaDB [zrs]> set @@session.sql_log_bin=ON; 为了测试,先创建一个表,插入数据 MariaDB [zrs]> create table if not exists tbl5 (UID tinyint unsigned not null auto_increment primary key,Username varchar(100),Age tinyint unsigned); MariaDB [zrs]> insert into tbl5 (Username,Age) values ('Zhang san',30),('Li si',27); 给表加一个读锁 MariaDB [zrs]> flush tables with read lock; 创建快照卷 [root@zj07 ~]# lvcreate -L 5G -s -p r -n data_backup /dev/datavg/mydata Using default stripesize 64.00 KiB. Logical volume "data_backup" created. 立马释放锁 MariaDB [zrs]> unlock tables; 创建目录 [root@zj07 ~]# mkdir -pv /mnt/backup 挂载 [root@zj07 ~]# mount /dev/datavg/data_backup /mnt/backup 查看 [root@zj07 ~]# ls /mnt/backup/ aria_log.00000001 ibdata1 ib_logfile1 mysql.sock test aria_log_control ib_logfile0 mysql performance_schema zrs 创建备份目录 [root@zj07 ~]# mkdir /tmp/backup 将文件全部备份到该目录 [root@zj07 ~]# cd /mnt/backup [root@zj07 backup]# cp -a * /tmp/backup/ 删除不需要的文件 [root@zj07 backup]# rm -f /tmp/backup/mysql.sock 记录下面的二进制数值,以备之后恢复数据 MariaDB [zrs]> show master status; +---------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +---------------+----------+--------------+------------------+ | binlog.000012 | 759 | | | +---------------+----------+--------------+------------------+ 4.模拟故障 [root@zj07 ~]# killall mysqld mysqld_safe 挂载并删除快照卷 [root@zj07 ~]# umount /mnt/backup/ [root@zj07 ~]# lvremove /data/datavg/data_backup 删除目录下的文件 [root@zj07 ~]# rm -rf /data/mydata/* 5.下面开始进行物理备份还原 [root@zj07 ~]# cd /tmp/backup/ [root@zj07 backup]# cp -a * /data/mydata/ 启动服务 [root@zj07 backup]# systemctl start mariadb [root@zj07 backup]# mysql MariaDB [(none)]> use zrs; MariaDB [zrs]> select * from tbl5; +-----+-----------+------+ | UID | Username | Age | +-----+-----------+------+ | 1 | Zhang san| 30 | | 2 | Li si | 27 | +-----+-----------+------+ 发现刚才新建的数据并没有恢复 利用二进制日志恢复 [root@zj07 ~]# mysqlbinlog --start-position=759 /var/log/mariadb/binlog.000012 > /tmp/lvm.sql 关闭二进制记录功能 MariaDB [zrs]> set @@session.sql_log_bin=OFF; 利用二进制日志恢复数据 MariaDB [zrs]> . /tmp/lvm.sql 开启二进制记录功能 MariaDB [zrs]> set @@session.sql_log_bin=ON; 三、利用xtrabackup实现物理备份操作 1.安装软件 yum install percona-xtrabackup 2. 创建备份目录 [root@zj07 ~]# mkdir /data/backup 更改属组属主 [root@zj07 ~]# chown mysql. /data/backup/ 完全备份 [root@zj07 ~]# innobackupex --user=root --host=localhost --socket=/data/mydata/mysql.sock /data/backup/ 查看,以时间命名创建目录 [root@zj07 ~]# ls /data/backup/ 2018-01-15_16-48-43 为了做增量备份,先修改表内容,如下 MariaDB [zrs]> insert into tbl5 (username,age) values ('Qi qi',55); MariaDB [zrs]> delete from tbl5 where UID between 1 and 2; 做增量备份,指明基于哪一次完全备份 [root@zj07 ~]# innobackupex --user=root --socket=/data/mydata/mysql.sock --incremental /data/backup/ --incremental-basedir=/data/backup/2018-01-15_16-48-43 查看,已经生成增量备份 [root@zj07 ~]# ls /data/backup/ 2018-01-15_16-48-43 2018-01-15_17-10-47 如何区分呢,查看该配置文件 [root@zj07 ~]# cat /data/backup/2018-01-15_16-48-43/xtrabackup_checkpoints backup_type = full-backuped from_lsn = 0 to_lsn = 1611662 last_lsn = 1611662 compact = 0 recover_binlog_info = 0 [root@zj07 ~]# cat /data/backup/2018-01-15_17-10-47/xtrabackup_checkpoints backup_type = incremental from_lsn = 1611662 to_lsn = 1613212 last_lsn = 1613212 compact = 0 recover_binlog_info = 0 为了再次做增量备份,再次修改表内容,如下 MariaDB [zrs]> create table if not exists tbl7 (UID tinyint unsigned not null auto_increment primary key,Username varchar(100),Age tinyint unsigned); MariaDB [zrs]> insert into tbl7 (Username,Age) values ('name11',98),('name22',99); 基于第二次增量备份,再次做增量 [root@zj07 ~]# innobackupex --user=root --socket=/data/mydata/mysql.sock --incremental /data/backup/ --incremental-basedir=/data/backup/2018-01-15_17-10-47 [root@zj07 ~]# ls /data/backup/ 2018-01-15_16-48-43 2018-01-15_17-10-47 2018-01-15_17-38-09 删除数据 MariaDB [zrs]> delete from tbl7 where UID between 1 and 2; 注意:如果在最后一个备份结果集之后,还有其他的数据修改操作,还需要依靠在最后一次备份操作之后的二进制日志的内容来实现数据的完整恢复。 3.模拟故障 [root@zj07 ~]# killall mysqld mysqld_safe [root@zj07 ~]# cd /data [root@zj07 data]# rm -rf mydata/* 4.恢复数据 准备工作 [root@zj07 ~]# innobackupex --apply-log --redo-only /data/backup/2018-01-15_16-48-43/ [root@zj07 ~]# innobackupex --apply-log --redo-only /data/backup/2018-01-15_16-48-43/ --incremental-dir=/data/backup/2018-01-15_17-10-47 [root@zj07 ~]# innobackupex --apply-log /data/backup/2018-01-15_16-48-43/ --incremental-dir=/data/backup/2018-01-15_17-38-09 恢复工作 [root@zj07 ~]# innobackupex --copy-back /data/backup/2018-01-15_16-48-43/ 查看 [root@zj07 ~]# ls /data/mydata/ ibdata1 performance_schema xtrabackup_binlog_pos_innodb zrs mysql test xtrabackup_info 因为在第二次增量备份后,又删除了两个数据,所以需要借助binlog恢复 [root@zj07 ~]# cat /data/backup/2018-01-15_17-38-09/xtrabackup_binlog_info binlog.000013 1123 保存 [root@zj07 ~]# mysqlbinlog --start-position=1123 /var/log/mariadb/binlog.000013 > /tmp/last.sql 修改权限 [root@zj07 ~]# chown mysql. -R /data/mydata/* 重启服务 [root@zj07 data]# systemctl start mariadb 查看,该表的内容还在 MariaDB [zrs]> select * from tbl7; +-----+----------+------+ | UID | Username | Age | +-----+----------+------+ | 1 | name11 | 98 | | 2 | name22 | 99 | +-----+----------+------+ 关闭二进制日志记录功能 MariaDB [zrs]> set @@session.sql_log_bin=OFF; 恢复 MariaDB [zrs]> . /tmp/last.sql 开启二进制日志记录功能 MariaDB [zrs]> set @@session.sql_log_bin=ON; 查看,该表的内容已经没有了 MariaDB [zrs]> select * from tbl7; Empty set (0.01 sec) 总结: MySQL的备份和恢复: mysqldump:逻辑备份 + 温备|热备 + binlog lvm2:物理备份 + 温备(几乎热备) + binlog Xtrabackup:物理备份 + 温备|热备 + (完全+增量) + binlog 本文转自Vincent一马 51CTO博客,原文链接:http://blog.51cto.com/mazhenbo/2084356,如需转载请自行联系原作者
项目: 1.自动发现nginx调度器及后端apache构建的web服务集群; 2.使用自定义参数监控调度器上nginx服务的相关统计数据及速率数据; 3.使用自定义参数监控后端apache服务的相关统计数据及速率数据;(选做) 4.制定出nginx调度器及后端apache服务的监控模板,在模板中定义出:items, trigger, graph;(选做) 项目规划: zabbix-server端:172.16.1.2 zabbix-agent端/nginx调度器:172.16.1.99 zabbix-agent端/后端RS1:172.16.1.3 zabbix-agent端/后端RS2:172.16.1.10 把nginx调度器的ip地址设置的大一些,是为了设置zabbix Discovery的时候,自动区分发现nginx调度器及后端apache构建的web服务集群,所以下面可以设置两个zabbix Discovery,分别发现不同作用的主机。 1. zabbix-server端: 安装以下应用 yum install zabbix-server-mysql zabbix-web-mysql zabbix-web zabbix-agent zabbix-get -y 详细的server端配置请参照:http://blog.51cto.com/12667170/2044254 三个zabbix-agent端: 安装以下应用 yum install -y zabbix-agent zabbix-sender 详细的agent端配置请参照:http://blog.51cto.com/12667170/2044254 2.创建nginx调度器 在nginx.conf配置文件中的http段内添加upstream内容,将后端两台RS加入到该upstream中 upstream zrs { server 172.16.1.3; server 172.16.1.10; } server { listen 80; location / { proxy_pass http://zrs; proxy_set_header X-Real-IP $remote_addr; } } 两个后端rs各配置一个index.html方便测试,并开启httpd服务 测试可以看到使用了RoundRobin模式对后端rs访问。 [root@zrs2 ~]# for i in {1..10}; do curl http://172.16.1.99; done <h1>172.16.1.3</h1> <h1>172.16.1.10</h1> <h1>172.16.1.3</h1> <h1>172.16.1.10</h1> <h1>172.16.1.3</h1> <h1>172.16.1.10</h1> <h1>172.16.1.3</h1> <h1>172.16.1.10</h1> <h1>172.16.1.3</h1> <h1>172.16.1.10</h1> 3.自动发现nginx调度器及后端apache构建的web服务集群 创建nginx discovery 1.png 创建web discovery 2.png 分别打开nginx调度器端和后端rs主机上的zabbix-agent服务 查看Hosts,已经添加进了这三台主机 4.使用自定义参数监控调度器上nginx服务的相关统计数据及速率数据 为了监控nginx状态,在nginx的主配置文件的server中添加location监控nginx的状态值。 [root@zrs2 ~]# vim /etc/nginx/nginx.conf location /status { stub_status on; } [root@zrs2 ~]# systemctl restart nginx.service [root@zrs2 ~]# curl 172.16.1.99/status Active connections: 1 server accepts handled requests 1 1 1 Reading: 0 Writing: 1 Waiting: 0 监控nginx的状态,需要item的key,默认的没有,需要自定义参数UserParameters 5.自定义参数(UserParameters) nginx自定义参数 vim /etc/zabbix/zabbix_agentd.d/userparameter_nginx.conf UserParameter=nginx.active,curl -s http://172.16.1.99/status | awk '/^Active/{print $NF}' UserParameter=nginx.accepts,curl -s http://172.16.1.99/status | awk '/^[[:space:]]+[0-9]/{print $1}' UserParameter=nginx.handled,curl -s http://172.16.1.99/status | awk '/^[[:space:]]+[0-9]/{print $2}' UserParameter=nginx.requests,curl -s http://172.16.1.99/status | awk '/^[[:space:]]+[0-9]/{print $3}' 保存退出,重启服务 [root@zrs2 zabbix_agentd.d]# systemctl restart zabbix-agent.service 在server端查看,可以不用eno查看状态,直接用第二种方法就能获取值,都成功了 [root@zrs1 ~]# zabbix_get -s 172.16.1.99 -k net.if.in[eno16777736,bytes] 285905110 [root@zrs1 ~]# zabbix_get -s 172.16.1.99 -k nginx.active 1 [root@zrs1 ~]# zabbix_get -s 172.16.1.99 -k nginx.accepts 9 [root@zrs1 ~]# zabbix_get -s 172.16.1.99 -k nginx.handled 10 [root@zrs1 ~]# zabbix_get -s 172.16.1.99 -k nginx.requests 11 接下来可以根据上面自定义的参数UserParameters,创建新的item项,可以输入刚才自定义的key。 在Hosts的172.16.1.99主机后面点击Items,然后Create item 如下创建4个监控项,也就是刚才设置的,注意的是preprocessing中改为Change per second 3.png 4.png 5.png 6.png 可以给这些监控创建一个graph 7.png 经过一段时间后,查看这个graph有了数值,表示自定义参数监控设置成功。 8.png 6.nginx调度器创建监控模板,在模板中定义出:items, trigger, graph。 创建nginx template 9.png 在这个模版上创建item,监控入站流量,注意的是preprocessing中改为Change per second 10.png 创建trigger 11.png 为了触发器被触发需要定义动作actions 12.png 13.png 这时需要定义Administration中users下面的media 14.png 再定义media types中的email中的media type 15.png 创建graph 16.png 7.后端apache服务配置监控模板,在模板中定义出:items, trigger, graph。 创建web template 17.png 在这个模版上创建item,监控出站流量,注意的是preprocessing中改为Change per second 18.png 创建trigger为了跟上面的trigger区分,这里Severity改为High 19.png 创建graph 20.png 8.链接应用模版 如下图,在172.16.1.99的host旁边,选择templates 21.png 链接nginx template 22.png 同样的步骤为两个后端rs链接模版 9.查看Hosts,刚才自定义配置监控都成功了。 23.png 本文转自Vincent一马 51CTO博客,原文链接:http://blog.51cto.com/mazhenbo/2084365,如需转载请自行联系原作者
************jquery 中设置属性************ $("#uploadButton").attr("disabled", true); ************js获取name相同的元素************ $("div[id]") 选择所有含有id属性的div元素 $("input[name='keleyicom']") 选择所有的name属性等于'keleyicom'的input元素 $("input[name!='keleyicom']") 选择所有的name属性不等于'keleyicom'的input元素 $("input[name^='keleyi']") 选择所有的name属性以'keleyi'开头的input元素 $("input[name$='keleyi']") 选择所有的name属性以'keleyi'结尾的input元素 $("input[name*='keleyi']") 选择所有的name属性包含'keleyi'的input元素 $("input[id][name$='keleyi']") 可以使用多个属性进行联合选择,该选择器是得到所有的含有id属性并且那么属性以keleyi结尾的元素 CheckBox选中事件 var userIds = ""; $('input:checkbox[name=userId]:checked').each(function(i){ if(0==i){ userIds = $(this).val(); }else{ userIds += (","+$(this).val()); } }); $("#notify_userIds").val(userIds); 延时执行 setTimeout("alert('对不起, 三秒钟已到')", 3000 ) //注意这里的调用方式,使用引号包围 setTimeout("changeState()",1000 ); 本文转自建波李 51CTO博客,原文链接:http://blog.51cto.com/jianboli/2045379,如需转载请自行联系原作者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #!/bin/bash hit_164=`redis-cli -h 192.168.1.164 -p 6379 info Stats|grep keyspace_hits|awk -F ':' '{print $2}'|sed -r 's/\r//'` mis_164=`redis-cli -h 192.168.1.164 -p 6379 info Stats|grep keyspace_misses|awk -F ':' '{print $2}'|sed -r 's/\r//'` exr_164=`redis-cli -h 192.168.1.164 -p 6379 info Stats|grep expired_keys|awk -F ':' '{print $2}'|sed -r 's/\r//'` let num_164=hit_164+mis_164-exr_164 let percent_164=(100*hit_164)/num_164 if [ $percent_164 -lt 70 ] && [ $percent_164 -ge 60 ] then echo "Warning!redis hit succeed percents is less than 70%.Now it's $percent_164%." exit 1 elif [ $percent_164 -lt 60 ] then echo "CRITICAL!redis hit succeed percents is less than 60%.Now it's $percent_164%." exit 2 else echo "OK!Now redis hit succeed percents is $percent_164%." exit 0 fi 主要思路:通过redis-cli的info命令匹配hits/misses/expired_keys三个字段参数进行百分比计算。 本文转自YU文武貝 51CTO博客,原文链接:http://blog.51cto.com/linuxerxy/1933062,如需转载请自行联系原作者
linux复制指定目录下的全部文件到另一个目录中 复制指定目录下的全部文件到另一个目录中 文件及目录的复制是经常要用到的。linux下进行复制的命令为cp。 假设复制源目录 为 dir1 ,目标目录为dir2。怎样才能将dir1下所有文件复制到dir2下了 如果dir2目录不存在,则可以直接使用 cp -r dir1 dir2 即可。 如果dir2目录已存在,则需要使用 cp -r dir1/. dir2 如果这时使用cp -r dir1 dir2,则也会将dir1目录复制到dir2中,明显不符合要求。 ps:dir1、dir2改成对应的目录路径即可。 cp -r /home/www/xxx/statics/. /home/www/statics 如果存在文件需要先删除 rm -rf /home/www/statics/* 否则会一个个文件提示你确认,使用cp -rf 也一样提示 -------------------------------------- copy命令的功能是将给出的文件或目录拷贝到另一文件或目录中,同MSDOS下的copy命令一样,功能十分强大。 语法: cp [选项] 源文件或目录 目标文件或目录 说明:该命令把指定的源文件复制到目标文件或把多个源文件复制到目标目录中。 该命令的各选项含义如下: - a 该选项通常在拷贝目录时使用。它保留链接、文件属性,并递归地拷贝目录,其作用等于dpR选项的组合。 - d 拷贝时保留链接。 - f 删除已经存在的目标文件而不提示。 - i 和f选项相反,在覆盖目标文件之前将给出提示要求用户确认。回答y时目标文件将被覆盖,是交互式拷贝。 - p 此时cp除复制源文件的内容外,还将把其修改时间和访问权限也复制到新文件中。 - r 若给出的源文件是一目录文件,此时cp将递归复制该目录下所有的子目录和文件。此时目标文件必须为一个目录名。 - l 不作拷贝,只是链接文件。 需要说明的是,为防止用户在不经意的情况下用cp命令破坏另一个文件,如用户指定的目标文件名已存在,用cp命令拷贝文件后,这个文件就会被新源文件覆盖,因此,建议用户在使用cp命令拷贝文件时,最好使用i选项。 例1 复制指定目录下的全部文件到另一个目录中 文件及目录的复制是经常要用到的。linux下进行复制的命令为cp。 假设复制源目录 为 dir1 ,目标目录为dir2。怎样才能将dir1下所有文件复制到dir2下了 如果dir2目录不存在,则可以直接使用 cp -r dir1 dir2 即可。 如果dir2目录已存在,则需要使用 cp -r dir1/. dir2 如果这时使用cp -r dir1 dir2,则也会将dir1目录复制到dir2中,明显不符合要求。 ps:dir1、dir2改成对应的目录路径即可。 例2 复制指定文件到指定文件夹 首先建立一个用于测试的目录,用'tree'命令查看 可见,目录中主要包含用于测试的*.txt文件和用于充当炮灰的*。tes文件 目标是保持当前的目录结构,只把txt文件复制出来 方法一:当不需要的文件类型较为单一时,可以通过完全复制然后删除指定类型的文件完成 Step1 使用命令 cp -r test/ test2 将测试目录test下所有内容完全复制到test2 Step2 组合使用find及xargs,将*.tes文件删除 xargs是给命令传递参数的一个过滤器,可以将前一个命令产生的输出作为后一个命令的参数 命令find test2/ -name '*.tes' |xargs rm -rf, 即将find产生的输出(test2目录下的所有tes文件),作为rm的参数,从而完全删除 适用场景举例:把项目文件备份,要去除其中的.svn文件,可以采用这种方式 方法二:需要的文件为单一类型,带目录结构复制 这种情况下可以使用tar命令将指定类型的文件打包,然后解包,同样需要组合使用find和xargs Step1 建立目录test3 mkdir test3 Step2 将指定类型文件带目录结构打包 find test/ -name '*.txt' |xargs tar czf test3.tgz Step3 解包到目录test3 tar zxvf test3.tgz -C test3 适用场景:较为普遍,例如可以复制某个Web项目的所有html/jsp/php文件;或复制其他项目中特定类型的源文件 本文转自yzy121403725 51CTO博客,原文链接:http://blog.51cto.com/lookingdream/1896382,如需转载请自行联系原作者
1、通用方法 dijit/form/TextBox :一个基本的文本框 dijit/form/SimpleTextarea :大量文字输入,一个基本的textarea dijit/form/Textarea :一个扩展dijit/form/SimpleTextarea动态增加或减少其高度 dijit/form/NumberTextBox或dijit/form/NumberSpinner:输入是数字,确保输入一个文本框,dijit/form/NumberSpinner提供扩展dijit/form/NumberTextBox逐步改变值的按钮 dijit/form/DateTextBox :输入是日期,一个文本框,其中包括一个弹出日历 dijit/form/TimeTextBox :输入是时间,一个文本框,其中包括一个弹出时间选择器 dijit/form/CurrencyTextBox :输入是货币,一个扩展dijit/form/NumberTextBox本地化货币 dijit/form/ValidationTextBox:一个基本的验证能力,可以进一步定制 如果你要使用dijit/form/DateTextBox或dijit/form/TimeTextBox ,你将需要有主题的CSS引入并设置body元素的css样式。 --申明方式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <!DOCTYPE html> <html > <head> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script>dojoConfig = {parseOnLoad: true}</script> <script src='dojo/dojo.js'></script> <script> require(["dojo/parser", "dijit/form/TextBox","dojo/domReady!"]); </script> <title>TextBox</title> </head> <body
、dijit/Tooltip 提示条(Tooltip)是为页面上的空间提供辅助信息的常用手段,其样式定义在单独的样式文件中,开发人员可以自己修改。同时也提供了一些强大的功能,比如可以显示图片、图表和从服务器请求得到的数据等,可以控制显示的时间和出现持续的时间。 dijit/Tooltip 的属性 属性 属性类别 描述 connectId String 要挂载 Tooltip 的控件的 Id,可以为用逗号分隔的多个 Id label String 要显示的提示信息 showDelay Integer 400 Tooltip 显示之前等待的时间,毫秒级 position String[] 显示提示条的位置,字符串数组,可取值before,after,above,below --声明方式样例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Tooltip</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dojo/parser", "dijit/Tooltip", "dijit/form/Button"]); </script> </head> <body class="claro"> <button id="button1" data-dojo-type="dijit/form/Button">Tooltip above</button> <button id="button2" data-dojo-type="dijit/form/Button">Tooltip below</button> <div data-dojo-type="dijit/Tooltip" data-dojo-props="connectId:'button1',position:['above']"> 在按钮上方显示提示信息 </div> <div data-dojo-type="dijit/Tooltip" data-dojo-props="connectId:'button2',position:['below']"> 在按钮下方显示提示信息 </div> </body> </html> --编程方式样例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Tooltip</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dijit/Tooltip", "dojo/domReady!"], function(Tooltip){ new Tooltip({ connectId: ["exampleNode"], label: "提示条显示内容", position:["above","below"] }); }); </script> </head> <body class="claro"> <span id="exampleNode">测试提示条</span> </body> </html> --使用selector和getContent()绑定多个节点: 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Tooltip</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dijit/Tooltip", "dojo/query!css2", "dojo/domReady!"], function(Tooltip){ new Tooltip({ connectId: "myTable", selector: "tr", getContent: function(matchedNode){ return matchedNode.getAttribute("tooltipText"); } }); }); </script> </head> <body class="claro"> <table id="myTable"> <tr tooltipText="tooltip for row 1"><td>row 1</td></tr> <tr tooltipText="tooltip for row 2"><td>row 2</td></tr> <tr tooltipText="tooltip for row 3"><td>row 3</td></tr> </table> </body> </html> 2、dijit/Dialog Extends: dijit/layout/ContentPane, dijit/_TemplatedMixin, dijit/form/_FormMixin, dijit/_DialogMixin, dijit/_CssStateMixin。 Dialog非常适合临时阻止用户对页面控件的操作,或者强制用户确认或对告警给出响应。对话框包括两种,一种是普通的对话框,一种是提示窗口的对话框。Dialog中可以包含任何DOM内容,无论是简单的HTML片段,还是复杂的布局部件,甚至自定义部件。 --普通对话框: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dijit/Dialog", "dojo/domReady!"], function(Dialog){ myDialog = new Dialog({ title: "My Dialog", content: "Test content.", style: "width: 300px" }); }); </script> </head> <body class="claro"> <button onclick="myDialog.show();">show</button> </body> </html> 输出: --利用dijitDialogPaneContentArea和dijitDialogPaneActionBar自定义对话框: 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dijit/Dialog", "dijit/form/TextBox", "dijit/form/Button"]); </script> </head> <body class="claro"> <div data-dojo-type="dijit/Dialog" data-dojo-id="myDialog" title="Name and Address"> <table class="dijitDialogPaneContentArea"> <tr> <td><label for="name">Name:</label></td> <td><input data-dojo-type="dijit/form/TextBox" name="name" id="name"></td> </tr> <tr> <td><label for="address">Address:</label></td> <td><input data-dojo-type="dijit/form/TextBox" name="address" id="address"></td> </tr> </table> <div class="dijitDialogPaneActionBar"> <button data-dojo-type="dijit/form/Button" type="submit" id="ok">OK</button> <button data-dojo-type="dijit/form/Button" type="button" data-dojo-props="onClick:function(){myDialog.hide();}" id="cancel">Cancel</button> </div> </div> <button data-dojo-type="dijit/form/Button" type="button" onClick="myDialog.show();"> Show me! </button> </body> </html> 输出: --动态设置对话框中的内容: 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dijit/Dialog", "dijit/form/Button", "dojo/domReady!"], function(Dialog, Button){ var myDialog = new Dialog({ title: "Programmatic Dialog Creation", style: "width: 300px" }); var myButton = new Button({ label: "Show me!", onClick: function(){ myDialog.set("content", "Hey, I wasn't there before, I was added at " + new Date() + "!"); myDialog.show(); } }, "progbutton"); }); </script> </head> <body class="claro"> <p>注意:时间在变化。</p> <button id="progbutton" type="button">Show me!</button> </body> </html> 输出: --更改衬底颜色: 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <style type="text/css"> #dialogColor_underlay { background-color:green; } </style> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dojo/parser", "dijit/Dialog", "dijit/form/Button"]); </script> </head> <body class="claro"> <div id="dialogColor" title="Colorful" data-dojo-type="dijit/Dialog"> My background color is Green </div> <button id="button4" data-dojo-type="dijit/form/Button" type="button">Show me! <script type="dojo/method" data-dojo-event="onClick" data-dojo-args="evt"> require(["dijit/registry"], function(registry){ registry.byId("dialogColor").show(); }); </script> </button> </body> </html> 输出: 备注:衬底颜色是通过样式表ID属性来确定,若dijit/Dialog属性的ID为dialogColor,则衬底样式表为:#dialogColor_underlay。即Dialog+_underlay。 --具有表单对话框: 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 51 52 53 54 55 56 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dojo/parser", "dijit/Dialog", "dijit/form/Button", "dijit/form/TextBox", "dijit/form/DateTextBox", "dijit/form/TimeTextBox"]); </script> </head> <body class="claro"> <div data-dojo-type="dijit/Dialog" data-dojo-id="myFormDialog" title="Form Dialog" execute="alert('submitted args:\n' + dojo.toJson(arguments[0], true));"> <div class="dijitDialogPaneContentArea"> <table> <tr> <td><label for="name">Name: </label></td> <td><input data-dojo-type="dijit/form/TextBox" type="text" name="name" id="name"></td> </tr> <tr> <td><label for="loc">Location: </label></td> <td><input data-dojo-type="dijit/form/TextBox" type="text" name="loc" id="loc"></td> </tr> <tr> <td><label for="sdate">Start date: </label></td> <td><input data-dojo-type="dijit/form/DateTextBox" data-dojo-id="myStartDate" onChange="myEndDate.constraints.min = arguments[0];" type="text" name="sdate" id="sdate"></td> </tr> <tr> <td><label for="edate">End date: </label></td> <td><input data-dojo-type="dijit/form/DateTextBox" data-dojo-id="myEndDate" onChange="myStartDate.constraints.max = arguments[0];" type="text" name="edate" id="edate"></td> </tr> <tr> <td><label for="time">Time: </label></td> <td><input data-dojo-type="dijit/form/TimeTextBox" type="text" name="time" id="time"></td> </tr> <tr> <td><label for="desc">Description: </label></td> <td><input data-dojo-type="dijit/form/TextBox" type="text" name="desc" id="desc"></td> </tr> </table> </div> <div class="dijitDialogPaneActionBar"> <button data-dojo-type="dijit/form/Button" type="submit" onClick="return myFormDialog.isValid();"> OK </button> <button data-dojo-type="dijit/form/Button" type="button" onClick="myFormDialog.hide()"> Cancel </button> </div> </div> <button id="buttonThree" data-dojo-type="dijit/form/Button" type="button" onClick="myFormDialog.show();"> Show me! </button> </body> </html> 输出: 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dojo/parser", "dijit/Dialog", "dijit/form/Form", "dijit/form/Button", "dijit/form/ValidationTextBox"]); </script> </head> <body class="claro"> <div data-dojo-type="dijit/Dialog" data-dojo-id="myFormDialog" title="Form Dialog" style="display: none"> <form data-dojo-type="dijit/form/Form" data-dojo-id="myForm"> <script type="dojo/on" data-dojo-event="submit" data-dojo-args="e"> e.preventDefault(); // prevent the default submit if(!myForm.isValid()){ alert('Please fix fields'); return; } window.alert("Would submit here via dojo/xhr"); // xhr.post( { // url: 'foo.com/handler', // content: { field: 'go here' }, // handleAs: 'json' // load: function(data){ .. }, // error: function(data){ .. } // }); </script> <div class="dijitDialogPaneContentArea"> <label>Foo:</label><div data-dojo-type="dijit/form/ValidationTextBox" data-dojo-props="required:true"></div> </div> <div class="dijitDialogPaneActionBar"> <button data-dojo-type="dijit/form/Button" type="submit">OK</button> <button data-dojo-type="dijit/form/Button" type="button" data-dojo-props="onClick:function(){myFormDialog.hide();}">Cancel</button> </div> </form> </div> <button id="buttonThree" data-dojo-type="dijit/form/Button" type="button">Show me! <script type="dojo/method" data-dojo-event="onClick" data-dojo-args="evt"> myFormDialog.show(); </script> </button> </body> </html> 输出: --条款和条件对话框: 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 51 52 53 54 55 56 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dijit/Dialog", "dijit/form/Button", "dijit/form/RadioButton", "dojo/dom", "dojo/dom-style"], function(Dialog, Button, RadioButton, dom, domStyle){ accept = function(){ dom.byId("decision").innerHTML = "接受条款和条件!"; domStyle.set("decision", "color", "#00CC00"); myFormDialog.hide(); }; decline = function(){ dom.byId("decision").innerHTML = "不接受条款和条件!"; domStyle.set("decision", "color", "#FF0000"); myFormDialog.hide(); } }); </script> </head> <body class="claro"> <div data-dojo-type="dijit/Dialog" data-dojo-id="myFormDialog" title="接受或拒绝条款"> <h1>条款</h1> <div style="width:400px; border:1px solid #b7b7b7; background:#fff; padding:8px; margin:0 auto; height:150px; overflow:auto;"> 这里是条款内容...... </div> <br /> <table> <input type="radio" data-dojo-type="dijit/form/RadioButton" name="agreement" id="radioOne" value="accept" data-dojo-props="onClick:accept" /> <label for="radioOne"> 接受条款 </label> </td> </tr> <tr> <td> <input type="radio" data-dojo-type="dijit/form/RadioButton" name="agreement" id="radioTwo" value="decline" data-dojo-props="onClick:decline" /> <label for="radioTwo"> 拒绝条款 </label> </td> </tr> </table> </div> </div> <label id="decision" style="color:#FF0000;"> 接受或拒绝条款结果展示 </label> <button id="termsButton" data-dojo-type="dijit/form/Button" type="button" onClick="myFormDialog.show();"> View terms and conditions to accept </button> </body> </html> 输出结果: --HREF调用和设置.dijitDialogPaneContent属性修改对话框尺寸 : 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <style type="text/css"> .dijitDialogPaneContent { width: 600px !important; height: auto !important; } </style> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dojo/parser", "dijit/form/Button", "dijit/Dialog"]); </script> </head> <body class="claro"> <div data-dojo-id="myExternalDialog" data-dojo-type="dijit/Dialog" title="My external dialog" href="dojo/resources/LICENSE"> </div> <p>XHR调用</p> <button data-dojo-type="dijit/form/Button" onClick="myExternalDialog.show();" type="button">Show me!</button> </body> </html> 输出: 3、dijit/TooltipDialog Extends: dijit/layout/ContentPane, dijit/_TemplatedMixin, dijit/form/_FormMixin, dijit/_DialogMixin。 TooltipDialog类似Dialog,但当鼠标点击屏幕任何位置时,TooltipDialog都可以关闭。 --声明方式创建: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require(["dojo/parser", "dijit/TooltipDialog", "dijit/form/DropDownButton", "dijit/form/TextBox", "dijit/form/Button"]); </script> </head> <body class="claro"> <div data-dojo-type="dijit/form/DropDownButton"> <span>Register</span> <div data-dojo-type="dijit/TooltipDialog"> <label for="name2">Name:</label> <input data-dojo-type="dijit/form/TextBox" id="name2" name="name2" /><br /> <label for="hobby2">Hobby:</label> <input data-dojo-type="dijit/form/TextBox" id="hobby2" name="hobby2" /><br /> <button data-dojo-type="dijit/form/Button" type="submit">Save</button> </div> </div> </body> </html> --编程方式创建: 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require([ "dijit/TooltipDialog", "dijit/form/TextBox", "dijit/form/Button", "dijit/form/DropDownButton", "dojo/dom", "dojo/domReady!" ], function (TooltipDialog, TextBox, Button, DropDownButton, dom) { var myDialog = new TooltipDialog({ content: '<label for="name">Name:</label> <input data-dojo-type="dijit/form/TextBox" id="name" name="name"><br>' + '<label for="hobby">Hobby:</label> <input data-dojo-type="dijit/form/TextBox" id="hobby" name="hobby"><br>' + '<button data-dojo-type="dijit/form/Button" type="submit">Save</button>' }); var myButton = new DropDownButton({ label: "show tooltip dialog", dropDown: myDialog }); dom.byId("dropDownButtonContainer").appendChild(myButton.domNode); }); </script> </head> <body class="claro"> <div id="dropDownButtonContainer"></div> </body> </html> --鼠标移动样例 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 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo: Dialog</title> <link rel="stylesheet" href="dijit/themes/claro/claro.css"> <script src="dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script> <script> require([ "dijit/TooltipDialog", "dijit/popup", "dojo/on", "dojo/dom", "dojo/domReady!" ], function(TooltipDialog, popup, on, dom){ var myTooltipDialog = new TooltipDialog({ id: 'myTooltipDialog', style: "width: 300px;", content: "<p>I have a mouse leave event handler that will close the dialog.", onMouseLeave: function(){ popup.close(myTooltipDialog); } }); var node = dom.byId('mouseovernode'); console.log(on, node); on(node, 'mouseover', function(evt){ popup.open({ popup: myTooltipDialog, around: node }); }); }); </script> </head> <body class="claro"> <div id="mouseovernode">Move the mouse over me to pop up the dialog.</div> </body> </html> 本文转自stock0991 51CTO博客,原文链接:http://blog.51cto.com/qing0991/1571820,如需转载请自行联系原作者
2 单主机Docker容器VLAN划分pipework不仅可以使用Linux bridge连接Docker容器,还可以与OpenVswitch结合,实现Docker容器的VLAN划分。下面,就来简单演示一下,在单机环境下,如何实现Docker容器间的二层隔离。为了演示隔离效果,我们将4个容器放在了同一个IP网段中。但实际他们是二层隔离的两个网络,有不同的广播域。 安装openvswitch 安装基础环境 1 2 3 yum install gcc make python-devel openssl-devel kernel-devel graphviz \ kernel-debug-devel autoconf automake rpm-build redhat-rpm-config \ libtool 下载openvswitch的包 wgethttp://openvswitch.org/releases/openvswitch-2.3.1.tar.gz 解压与打包 1 2 3 4 5 [root@localhost src]# tar zxf openvswitch-2.3.1.tar.gz [root@localhost src]# cd /root/ [root@localhost ~]# mkdir -p ~/rpmbuild/SOURCES [root@localhost src]# cp openvswitch-2.3.1.tar.gz ~/rpmbuild/SOURCES/ [root@localhost src]# sed 's/openvswitch-kmod, //g' openvswitch-2.3.1/rhel/openvswitch.spec > openvswitch-2.3.1/rhel/openvswitch_no_kmod.spec 之后会在~/rpmbuild/RPMS/x86_64/里有2个文件 1 2 [root@localhost src]# ls ~/rpmbuild/RPMS/x86_64/ openvswitch-2.3.1-1.x86_64.rpm openvswitch-debuginfo-2.3.1-1.x86_64.rpm 安装第一个就行 1 [root@localhostsrc]#yum localinstall ~/rpmbuild/RPMS/x86_64/openvswitch-2.3.1-1.x86_64.rpm 或 systemctl start openvswitch 启动 1 2 3 4 root@localhost src]# /sbin/chkconfig openvswitch on [root@localhost src]# /sbin/service openvswitch start Starting openvswitch (via systemctl): [ OK ] 查看状态 1 2 3 [root@localhost src]# /sbin/service openvswitch status ovsdb-server is not running ovs-vswitchd is not running 或 [root@localhost src]# systemctl status openvswitch 安装pipework过程略,参考前面的操作 创建交换机,把物理网卡加入ovs1 1 2 3 4 [root@localhost ~]# ovs-vsctl add-br ovs1 [root@localhost ~]# ovs-vsctl add-port ovs1 eno16777736 [root@localhost ~]# ip link set ovs1 up [root@localhost ~]# ifconfig eno16777736 Ifconfig 查看 在主机A上创建4个Docker容器,test1、test2、test3、test4 1 2 3 4 5 6 7 8 [root@localhost ~]# docker run -itd --name test1 centos7:http /bin/bash 0ef176613e34b045112f84f860643a071b903c10d23ffc1b1a233ff1367bc312 [root@localhost ~]# docker run -itd --name test2 centos7:http /bin/bash cf99eb3b2558d87226f5624f2cb3144e5e34425b73f3da15a1ea5b86027dbb5d [root@localhost ~]# docker run -itd --name test3 centos7:http /bin/bash 3abd9472a1075241d900c9d2e4ed6b6860e2e140efb104036ae7cfbbd27fd570 [root@localhost ~]# docker run -itd --name test4 centos7:http /bin/bash 09a73f1a6284e4380c1b4e271756a422caa10f384fd6a532d8522e7e9de5ca37 将test1,test2划分到一个vlan中,vlan在mac地址后加@指定,此处mac地址省略。 [root@localhost ~]# pipework ovs1 test1 192.168.1.1/24@100 [root@localhost ~]# pipework ovs1 test2 192.168.1.2/24@100 [root@localhost ~]# pipework ovs1 test3 192.168.1.3/24@200 [root@localhost ~]# pipework ovs1 test4 192.168.1.4/24@200 [root@0ef176613e34 /]# ping 192.168.1.3 测试ping 测试ping PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data. 64 bytes from 192.168.1.3: icmp_seq=1 ttl=64 time=0.564 ms 64 bytes from 192.168.1.3: icmp_seq=2 ttl=64 time=0.053 ms 完成上述操作后,使用docker attach连到容器中,然后用ping命令测试连通性,发现test1和test2可以相互通信,但与test3和test4隔离。这样,一个简单的VLAN隔离容器网络就已经完成。由于OpenVswitch本身支持VLAN功能,所以这里pipework所做的工作和之前介绍的基本一样,只不过将Linux bridge替换成了OpenVswitch,在将veth pair的一端加入ovs0网桥时,指定了tag。底层操作如下:ovs-vsctl add-port ovs0 veth* tag=100 本文转自柴鑫旺 51CTO博客,原文链接:http://blog.51cto.com/chaixinwang/1959620,如需转载请自行联系原作者
Cinder安装 块存储服务cinder提供了块存储给instance使用,这种存储的提供和消耗的方法是由块存储驱动确定的,支持多种可用驱动:NAS/SAN, NFS, iSCSI, Ceph和更多。 块存储API和调度程序服务通常在控制器节点上运行。根据所使用的驱动程序,卷服务可以在控制器节点、计算节点或独立存储节点上运行。 本节描述如何为块存储服务安装和配置存储节点。为简单起见,此配置操作一个带有空的本地块存储设备的存储节点,使用/dev/sdb。在设备上使用LVM驱动提供一个逻辑卷并通过iSCSI提供。 安装和配置存储节点 安装和配置控制节点: 前期准备: 1、创建数据库并授权: 1 2 3 4 5 6 7 MariaDB [(none)]> CREATE DATABASE cinder; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'localhost' \ -> IDENTIFIED BY '123456'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'%' IDENTIFIED BY '123456'; Query OK, 0 rows affected (0.00 sec) 1、执行admin凭证以访问命令行 1 [root@controller /]# source admin-openrc 创建cinder用户 openstack user create --domain default --password-prompt cinder 为cinder用户赋予admin角色,没有任何输出 1 [root@controller /]# openstack role add --project service --user cinder admin 创建cinderv2和cinderv3服务项:块存储服务要求2个服务项 openstack service create --name cinderv2 --description "OpenStack Block Storage" volumev2 openstack service create --name cinderv3 --description "OpenStack Block Storage" volumev3 创建块存储服务API的endpoints: openstack endpoint create --region RegionOne \ volumev2 public http://controller:8776/v2/%\(project_id\)s openstack endpoint create --region RegionOne \ volumev2 internal http://controller:8776/v2/%\(project_id\)s openstack endpoint create --region RegionOne \ volumev2 admin http://controller:8776/v2/%\(project_id\)s openstack endpoint create --region RegionOne \ volumev3 admin http://controller:8776/v3/%\(project_id\)s 配置和安装组件: 1、安装包: 2、编辑/etc/cinder/cinder.conf文件完成以下设置: 在[database]部分,配置到数据库的连接 [database] connection = mysql+pymysql://cinder:123456@controller/cinder 在[DEFAULT]部分,配置到RabbitMQ消息队列的访问: transport_url = rabbit://openstack:123456@controller 在[DEFAULT]和[keystone_authtoken]部分,配置身份验证服务: [DEFAULT] auth_strategy = keystone [keystone_authtoken] auth_uri = http://controller:5000 auth_url = http://controller:35357 memcached_servers = controller:11211 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = cinder password = 123456 在[DEFAULT]部分配置my_ip选项: [DEFAULT] my_ip = 10.0.0.11 添加 1、在[oslo_concurrency]部分配置锁定路径 [oslo_concurrency]. lock_path = /var/lib/cinder/tmp 1、初始生成存储数据库 1 [root@controller /]# su -s /bin/sh -c "cinder-manage db sync" cinder 1、配置计算使用块存储: 编辑/etc/nova/nova.conf文件 [cinder] os_region_name = RegionOne 完成安装: 1、重启nova计算服务 2、启动块服务并设置开机启动 1 root@controller /]# systemctl enable openstack-cinder-api.service openstack-cinder-scheduler.service 1 [root@controller /]# systemctl start openstack-cinder-api.service openstack-cinder-scheduler.service 存储节点配置安装 环境准备:在存储节点block1上操作 1、安装规划配置IP地址 2、主机名配置和/etc/hosts文件配置,要确定可以解析 3、配置NTP服务,安装chrony,并配置controller作为NTP服务器 4、配置基本的openstack包环境: um install centos-release-openstack-pike 安装pike源 yum upgrade 更新,如果升级过程包含一个新内核,请重启主机以激活它。 yum install python-openstackclient 安装openstack客户端 yum install openstack-selinux 为openstack服务自动管理Selinux中的安全策略 准备存储设备: 1、安装支持单元包: 安装LVM包 Yum -y install lvm 1 2 [root@block1 /]# systemctl enable lvm2-lvmetad.service [root@block1 /]# systemctl start lvm2-lvmetad.service 1、创建LVM物理卷/dev/sdb 1 2 [root@block1 ~]# pvcreate /dev/sdb Physical volume "/dev/sdb" successfully created 1、创建LVM卷组cinder-volumes 1 2 [root@block1 ~]# vgcreate cinder-volumes /dev/sdb Volume group "cinder-volumes" successfully created 1、只有实例才能访问块存储卷,然而,底层操作系统管理关于卷的管理设备,默认LVM卷扫描工具会为块存储扫描 /dev目录。如果租户使用LVM,扫描工具会检测这些卷和缓存他们,这会造成各种各样的问题,必须重新配置LVM仅扫描包含cinder-volumes卷组的设备,配置/etc/lvm/lvm.conf文件完成以下设置: 在devices部分,添加过滤器接受/dev/sdb设备,拒绝其它设备: 每个过滤器组中的元素都以“a”开头,即为 accept,或以”b”开头,即为reject,并且包括一个设备名称的正则表达式规则。过滤器组必须以 r/.*/ 结束,过滤所有其它剩余设备。可以通过vgs -vvv命令来测试过滤器。 注意: 如果你的存储节点的操作系统也使用LVM,你必须要添加相关设备到过滤器中,例如,如果/dev/sda包含操作系统: filter = [ "a/sda/", "a/sdb/", "r/.*/"] 类似,如果你的计算节点的操作系统也使用LVM,你也必须在所有的这些计算节点上配置/etc/lvm/lvm.conf文件设置过滤器,只包含操作系统磁盘。例如,如果/dev/sda包含操作系统: vim /etc/lvm/lvm.conf filter = [ "a/sda/", "r/.*/"] 安装和配置组件: 1、安装数据包: 2、配置/etc/cinder/cinder.conf文件完成以下设置: 在[database]部分,配置到数据库的连接 [database] connection = mysql+pymysql://cinder:123456@controller/cinder 在[DEFAULT]部分,配置到RabbitMQ消息队列的访问: [DEFAULT] transport_url = rabbit://openstack:123456@controller 在[DEFAULT]和[keystone_authtoken]部分,配置身份验证服务: [DEFAULT] auth_strategy = keystone [keystone_authtoken] auth_uri = http://controller:5000 auth_url = http://controller:35357 memcached_servers = controller:11211 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = cinder password = 123456 在[DEFAULT]部分配置my_ip选项: [DEFAULT] .my_ip = 10.0.0.41 在[lvm]部分,配置LVM后端LVM驱动,卷组cinder-volumes,iSCSI协议和正确的iSCSI服务,如果[lvm]不存在就创建它。 [lvm] volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver volume_group = cinder-volumes iscsi_protocol = iscsi iscsi_helper = lioadm 在[DEFAULT]部分,激活LVM后端。 [DEFAULT] enabled_backends = lvm 后端名称是任意的。作为一个例子,这个向导使用驱动程序的名称作为后端的名称。 在[DEFAULT]部分,配置本地镜像服务的API [DEFAULT] glance_api_servers = http://controller:9292 在[oslo_concurrency]部分配置锁定路径: [oslo_concurrency] lock_path = /var/lib/cinder/tmp 1、完成安装 启动并设置开机启动: 1 2 [root@controller /]# systemctl enable openstack-cinder-volume.service target.service [root@controller /]# systemctl start openstack-cinder-volume.service target.service 检查存储服务: 在控制节点controller上执行以下命令: openstack volume service list 本文转自柴鑫旺 51CTO博客,原文链接:http://blog.51cto.com/chaixinwang/1970324,如需转载请自行联系原作者