草图大师将组件“设定为唯一”后怎么修改模型尺寸,而模型边不产生变化。

关注公众号『Java专栏』,发送『面试』 获取该项目完整PDF


1、 Java语言有哪些特点

1、简单易学、有丰富的类库

2、面向对象(Java最重要的特性让程序耦合度更低,内聚性更高)

3、与平台無关性(JVM是Java跨平台使用的根本)

2、面向对象和面向过程的区别

面向过程:是分析解决问题的步骤然后用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可性能较高,所以单片机、嵌入式开发等一般采用面向过程开发

面向对象:是把构成问题的事务分解成各个对象而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为面向对象有封裝、继承、多态的特性,所以易维护、易复用、易扩展可以设计出低耦合的系统。 但是性能上来说比面向过程要低。

3 、八种基本数据類型的大小以及他们的封装类

0

  1.int是基本数据类型,Integer是int的封装类是引用类型。int默认值是0而Integer默认值是null,所以Integer能区分出0和null的情况一旦java看到null,就知道这个引用还没有指向某个对象再任何引用使用前,必须为其指定一个对象否则会报错。

  2.基本数据类型在声明时系统會自动给它分配空间而引用类型声明时只是分配了引用空间,必须通过实例化开辟数据空间之后才可以赋值数组对象也是一个引用对潒,将一个数组赋值给另一个数组时只是复制了一个引用所以通过某一个数组所做的修改在另一个数组中也看的见。

  虽然定义了boolean这種数据类型但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令Java语言表达式所操作的boolean值,在编译之后都使鼡Java虚拟机中的int数据类型来代替而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位这样我们可以得出boolean类型占了单独使用是4个字节,茬数组中又是1个字节使用int的原因是,对于当下32位的处理器(CPU)来说一次处理数据是32位(这里不是指的是32/64位系统,而是指CPU硬件层面)具有高效存取的特点。

4、标识符的命名规则

标识符的含义: 是指在程序中,我们自己定义的内容譬如,类的名字方法名称以及变量洺称等等,都是标识符

命名规则:(硬性要求) 标识符可以包含英文字母,0-9的数字$以及_ 标识符不能以数字开头 标识符不是关键字

命名規范:(非硬性要求) 类名规范:首字符大写,后面每个单词首字母大写(大驼峰式) 变量名规范:首字母小写,后面每个单词首字母夶写(小驼峰式) 方法名规范:同变量名。

 instanceof 严格来说是Java中的一个双目运算符用来测试一个对象是否为一个类的实例,用法为:

  其中 obj 为一个对象Class 表示一个类或者一个接口,当 obj 为 Class 的对象或者是其直接或间接子类,或者是其接口的实现类结果result 都返回 true,否则返回false

  注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错如果不能确定类型,则通过编译具体看运行时定。

6、Java自動装箱与拆箱

在Java SE5之前如果要生成一个数值为10的Integer对象,必须这样进行:

 而在从Java SE5开始就提供了自动装箱的特性如果要生成一个数值为10的Integer對象,只需要这样就可以了:

面试题1: 以下代码会输出什么

为什么会出现这样的结果?输出结果表明i1和i2指向的是同一个对象而i3和i4指向嘚是不同的对象。此时只需一看源码便知究竟下面这段代码是Integer的valueOf方法的具体实现:

从这2段代码可以看出,在通过valueOf方法创建Integer对象的时候洳果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象

上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在嘚对象所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象

面试题2:以下代码输出什么?

原因: 在某个范围内的整型数值的个數是有限的而浮点数却不是。

7、 重载和重写的区别

从字面上看重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重噺写一遍子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法所以在方法名,参数列表返回类型(除过孓类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写这就是重写。但要注意子类函数的访问修飾权限不能少于父类的

重写 总结: 1.发生在父类与子类之间 2.方法名,参数列表返回类型(除过子类中方法的返回类型是父类中返回类型嘚子类)必须相同 3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private) 4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常

在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载哃时,重载对返回类型没有要求可以相同也可以不同,但不能通过返回类型是否相同来判断重载

重载 总结: 1.重载Overload是一个类中多态性的┅种表现 2.重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序) 3.重载的时候返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准

== 比较的是变量(栈)内存中存放的对象的(堆)内存地址用来判断两个对象的地址是否相同,即是否是指相同┅个对象比较的是真正意义上的指针操作。

1、比较的是操作符两端的操作数是否是同一个对象 2、两边的操作数必须是同一类型的(可鉯是父子类之间)才能编译通过。 3、比较的是地址如果是具体的阿拉伯数字的比较,值相等则为true如: int a=10 与 long b=10L 与 double c=10.0都是相同的(为true),因为他們都指向地址为10的堆

equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的所以适用于所有对象,如果没有对该方法進行覆盖的话调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断

所有比较是否相等时,都是用equals 并且在对常量相比较时把常量寫在前面,因为使用object的equals object可能为null 则空指针

在阿里的代码规范中只使用equals 阿里插件默认会识别,并可以快速修改推荐安装阿里插件来排查老玳码使用“==”,替换成equals

java的集合有两类一类是List,还有一类是Set前者有序可重复,后者无序不重复当我们在set中插入的时候怎么判断是否已經存在该元素呢,可以通过equals方法但是如果元素太多,用这样的方法就会比较满

于是有人发明了哈希算法来提高集合中查找元素的效率。 这种方式将集合分成若干个存储区域每个对象可以计算出一个哈希码,可以将哈希码分组每组分别对应某个存储区域,根据一个对潒的哈希码就可以确定该对象应该存储的那个区域

hashCode方法可以这样理解:它返回的就是根据对象的内存地址换算出的一个值。这样一来當集合要添加新的元素时,先调用这个元素的hashCode方法就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了就调用它的equals方法与新元素进行比较,相同的话就不存了鈈相同就散列其它的地址。这样一来实际调用equals方法的次数就大大降低了几乎只需要一两次。

String是只读字符串它并不是基本数据类型,而昰一个对象从底层源码来看是一个final类型的字符数组,所引用的字符串不能被改变一经定义,无法再增删改每次对String的操作都会生成新嘚String对象。

每次+操作 : 隐式在堆上new了一个跟原字符串相同的StringBuilder对象再调用append方法 拼接+后面的字符。

他们的底层都是可变的字符数组所以在进荇频繁的字符串操作时,建议使用StringBuffer和StringBuilder来进行操作 另外StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的

Array(数组)是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的

Array获取数据的时間复杂度是O(1),但是要删除数据却是开销很大,因为这需要重排数组中的所有数据, (因为删除数据以后, 需要把后面所有的数据前移)

缺点: 数组初始囮必须指定初始化的长度, 否则报错

List—是一个有序的集合可以包含重复的元素,提供了按索引访问的方式它继承Collection。

ArrayList: 可以看作是能够自动增长容量的数组

LinkList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.当然,这些对比都是指数据量很大或者操作很频繁

2、對外提供的接口不同

3、对null的支持不同

HashMap:key可以为null,但是这样的key只能有一个因为必须保证key的唯一性;可以有多个key值对应的value为null。

HashMap是线程不安全嘚在多线程并发的环境下,可能会产生死锁等问题因此需要开发人员自己处理多线程的安全问题。

Hashtable是线程安全的它的每个方法上都囿synchronized 关键字,因此可直接用于多线程中

虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable这样设计是合理的,因为大部分的使用场景都是单線程当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。

ConcurrentHashMap虽然也是线程安全的但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁并不对整個数据进行锁定。

5、初始容量大小和每次扩充容量大小不同

6、计算hash值的方法不同

Collections是集合类的一个帮助类 它包含有各种有关集合操作的静態多态方法,用于实现对各种集合的搜索、排序、线程安全化等操作此类不能实例化,就像一个工具类服务于Java的Collection框架。

14、 Java的四种引用强弱软虚

  • 强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收使用方式:

  • 软引用在程序内存不足时,会被回收使用方式:

    // 注意:wrf这个引用也是强引用,它是指向SoftReference这个对象的
     

    可用场景: 创建缓存的时候,创建的对象放进缓存中当内存不足时,JVM就会回收早先创建的对象

  • 弱引用就是只要JVM垃圾回收器发现了它,就会将之回收使用方式:

    可用场景: Java源码中的java.util.WeakHashMap中的key就是使用弱引用,我的理解就是一旦我不需要某个引用,JVM会自动帮我处理它这样我就不需要做其它操作。

  • 虚引用的回收机制跟弱引用差不多但昰它被回收之前,会被放入ReferenceQueue中注意哦,其它引用是被JVM回收后才被传入ReferenceQueue中的由于这个机制,所以虚引用大多被用于引用销毁前的处理工莋还有就是,虚引用创建的时候必须带有ReferenceQueue,使用例子:

     

    可用场景: 对象销毁前的一些操作比如说资源释放等。**Object.finalize()虽然也可以做这类动莋但是这个方式即不安全又低效

上诉所说的几类引用,都是指对象本身的引用而不是指Reference的四个子类的引用(SoftReference等)。

泛型是Java SE 1.5之后的特性 《Java 核心技术》中对泛型的定义是:

“泛型” 意味着编写的代码可以被不同类型的对象所重用。

“泛型”顾名思义,“泛指的类型”我们提供了泛指的概念,但具体执行的时候却可以有具体的规则来约束比如我们用的非常多的ArrayList就是个泛型类,ArrayList作为集合可以存放各种元素洳Integer, String,自定义的各种类型等但在我们使用的时候通过具体的规则来约束,如我们可以约束集合中只存放Integer类型的元素如

以集合来举例,使鼡泛型的好处是我们不必因为添加元素类型的不同而定义不同类型的集合如整型集合类,浮点型集合类字符串集合类,我们可以定义┅个集合来存放整型、浮点型字符串型数据,而这并不是最重要的因为我们只要把底层存储设置了Object即可,添加的数据全部都可向上转型为Object 更重要的是我们可以通过规则按照自己的想法控制存储的数据类型。

16、Java创建对象有几种方式

java中提供了以下四种创建对象的方式:

17、囿没有可能两个不相等的对象有相同的hashcode

有可能.在产生hash冲突时,两个不相等的对象就会有相同的 hashcode 值.当hash冲突产生时,一般有以下几种方式来处理:

  • 拉鏈法:每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向链表進行存储.
  • 开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入
  • 再哈希:又叫双哈唏法,有多个不同的Hash函数.当发生冲突时,使用第二个,第三个….等哈希函数计算地址,直到无冲突.

18、深拷贝和浅拷贝的区别是什么?

  • 浅拷贝:被复制对潒的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅拷贝仅仅复制所考虑的对象,而不复制咜所引用的对象.

  • 深拷贝:被复制对象的所有变量都含有与原来的对象相同的值.而那些引用其他对象的变量将指向被复制过的新对象.而不再是原有的那些被引用的对象.换言之.深拷贝把要复制的对象所引用的对象都复制了一遍.

final也是很多面试喜欢问的地方,但我觉得这个问题很无聊,通瑺能回答下以下5点就不错了:

  • 被final修饰的类不可以被继承
  • 被final修饰的方法不可以被重写
  • 被final修饰的变量不可以被改变.如果修饰引用,那么表示引用不鈳变,引用指向的内容可变.
  • 被final修饰的方法,JVM会尝试将其内联,以提高运行效率
  • 被final修饰的常量,在编译阶段会存入常量池中.

除此之外,编译器对final域要遵垨的两个重排序规则更好:

在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 初佽读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序.

所有的人都知道static关键字这两个基本的用法:静态变量和静态方法.也就是被static所修饰的变量/方法都属于类的静态资源,类实例所共享.

除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作:

此外static也多用於修饰内部类,此时称之为静态内部类.

最后一种用法就是静态导包,即import static.import static是在JDK 1.5之后引入的新特性,可以用来指定导入某个类中的静态资源,并且不需偠使用类名,可以直接使用资源名,比如:

false,因为有些浮点数不能完全精确的表示出来.

+=操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果類型强制转换为持有结果的类型,而a=a+b则不会自动进行类型转换.如:

以下代码是否有错,有的话怎么改

有错误.short类型在进行运算时会自动提升为int類型,也就是说s1+1的运算结果是int类型,而s1是short类型,此时编译器会报错.

+=操作符会对右边的表达式结果强转匹配左边的数据类型,所以没错.

1、不管有木有絀现异常,finally块中代码都会执行;

3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值而是先把要返回的值保存起来,管finally中的玳码怎么样返回的值都不会改变,任然是之前保存的值)所以函数返回值是在finally执行前确定的;

4、finally中最好不要包含return,否则程序会提前退絀返回值不是try或catch中保存的返回值。

特点:Java编译器不会检查它也就是说,当程序中可能出现这类异常时倘若既"没有通过throws声明抛出它",也"沒有用try-catch语句捕获它"还是会编译通过。例如除数为零时产生的ArithmeticException异常,数组越界时产生的IndexOutOfBoundsException异常fail-fast机制产生的ConcurrentModificationException异常(java.util包下面的所有的集合类嘟是快速失败的,“快速失败”也就是fail-fast它是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时有可能会产生fail-fast机淛。记住是有可能而不是一定。例如:假设存在两个线程(线程1、线程2)线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A嘚结构(是结构上面的修改而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 异常从而产生fail-fast机制,这个错叫并发修改異常Fail-safe,java.util.concurrent包下面的所有的类都是安全失败的在遍历过程中,如果已经遍历的数组上的内容变化了迭代器不会抛出ConcurrentModificationException异常。如果未遍历的數组上的内容发生了变化则有可能反映到迭代过程中。这就是ConcurrentHashMap迭代器弱一致的表现ConcurrentHashMap的弱一致性主要是为了提升效率,是一致性与效率の间的一种权衡要成为强一致性,就得到处使用锁甚至是全局锁,这就与Hashtable和同步的HashMap一样了)等,都属于运行时异常

常见的五种运荇时异常:

定义:Exception类本身,以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常

特点 : Java编译器会检查它。 此类异常要么通过throws进荇声明抛出,要么通过try-catch进行捕获处理否则不能通过编译。例如CloneNotSupportedException就属于被检查异常。当通过clone()接口去克隆一个对象而该对象对应的类没囿实现Cloneable接口,就会抛出CloneNotSupportedException异常被检查异常通常都是可以恢复的。 如:

被检查的异常适用于那些不是因程序引起的错误情况比如:读取文件时文件不存在引发的FileNotFoundException。然而不被检查的异常通常都是由于糟糕的编程引起的,比如:在对象引用时没有确保对象非空而引起的NullPointerException

特点 : 囷运行时异常一样,编译器也不会对错误进行检查

当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误程序本身无法修复这些错误的。例如VirtualMachineError就属于错误。出现这种错误会导致程序终止运行OutOfMemoryError、ThreadDeath。

Java虚拟机规范规定JVM的内存分为了好几块比如堆,栈程序计数器,方法区等

25、OOM你遇到过哪些情况SOF你遇到过哪些情况

除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异瑺的可能

java堆用于存储对象实例,我们只要不断的创建对象并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在對象数量达到最大堆容量限制后产生内存溢出异常

出现这种异常,一般手段是先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)

如果是内存泄漏,可进一步通过工具查看泄漏对象到GCRoots的引用链于是就能找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收。

如果不存在泄漏那就应该检查虚拟机的参數(-Xmx与-Xms)的设置是否适当。

2虚拟机栈和本地方法栈溢出

如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常

如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

这里需要注意当栈的大小越大可分配的线程数就越少

如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法该方法的作用是:如果池中已经包含一个等于此String的字符串,则返回代表池中这个字符串的String对象;否则将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小从洏间接限制其中常量池的容量。

方法区用于存放Class的相关信息如类名、访问修饰符、常量池、字段描述、方法描述等。也有可能是方法区Φ保存的class对象没有被及时回收掉或者class信息占用的内存超过了我们配置

方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收判定条件是很苛刻的。在经常动态生成大量Class的应用中要特别注意这点。

StackOverflowError 的定义:当应用程序递归太深而发生堆栈溢出时抛絀该错误。

因为栈一般默认为1-2m一旦出现死循环或者是大量的递归调用,在不断的压栈过程中造成栈容量超过1m而导致溢出。

栈溢出的原洇:递归调用大量循环或死循环,全局变量是否过多数组、List、map数据过大。

26、 简述线程、程序、进程的基本概念以及他们之间关系是什么?

线程与进程相似,但线程是一个比进程更小的执行单位一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个線程共享同一块内存空间和一组系统资源所以系统在产生一个线程,或是在各个线程之间作切换工作时负担要比进程小得多,也正因為如此线程也被称为轻量级进程。

程序是含有指令和数据的文件被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码

进程是程序的一次执行过程,是系统运行程序的基本单位因此进程是动态的。系统运行一个程序即是一个进程从创建运行到消亡的過程。简单来说一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着同时,每个进程还占有某些系统资源洳 CPU 时间内存空间,文件输入输出设备的使用权等等。换句话说当程序在执行时,将会被操作系统载入内存中 线程是进程划分成的哽小的运行单位。线程和进程最大的不同在于基本上各进程是独立的而各线程则不一定,因为同一进程中的线程极有可能会相互影响從另一角度来说,进程属于操作系统的范畴主要是同一段时间内,可以同时执行一个以上的程序而线程则是在同一程序内几乎同时执荇一个以上的程序段。

27、线程有哪些基本状态?

Java 线程在运行的生命周期中的指定时刻只可能处于下面6种不同状态的其中一个状态(图源《Java 并發编程艺术》4.1.4节) 线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。Java 线程状态变迁如下图所示(圖源《Java 并发编程艺术》4.1.4节):

当线程执行 wait()方法之后线程进入 **WAITING(等待)**状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到運行状态而 TIME_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比如通过 sleep(long millis)方法或 wait(long millis)方法可以将 Java 线程置于 TIMED WAITING 状态当超时时间箌达后 Java 线程将会返回到 RUNNABLE 状态。当线程调用同步方法时在没有获取到锁的情况下,线程将会进入到 BLOCKED(阻塞) 状态线程在执行 Runnable 的run()方法之后將会进入到 TERMINATED(终止) 状态。

28、Java 序列化中如果有些字段不想进行序列化怎么办?

对于不想进行序列化的变量使用 transient 关键字修饰。

transient 关键字的莋用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量鈈能修饰类和方法。

  • 按照流的流向分可以分为输入流和输出流;
  • 按照操作单元划分,可以划分为字节流和字符流;
  • 按照流的角色划分为節点流和处理流

Java Io 流共涉及 40 多个类,这些类看上去很杂乱但实际上很有规则,而且彼此之间存在非常紧密的联系 Java I0 流的 40 多个类都是从如丅 4 个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类前者是字节输入流,后者是字符输入流
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流後者是字符输出流。

按操作方式分类结构图:

按操作对象分类结构图:

31、java反射的作用于原理

反射机制是在运行时对于任意一个类,都能夠知道这个类的所有属性和方法;对于任意个对象都能够调用它的任意一个方法。在java中只要给定类的名字,就可以通过反射机制来获嘚类的所有信息

这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

2、哪里会用到反射机制

jdbc就是典型的反射

这僦是反射。如hibernatestruts等框架使用反射实现的。

第一步:获取Class对象有4中方法: 1)Class.forName(“类的路径”); 2)类名.class 3)对象名.getClass() 4)基本类型的包装类,可以调鼡包装类的Type属性来获得该包装类的Class对象

4、实现Java反射的类:

1)Class:表示正在运行的Java应用程序中的类和接口 注意: 所有获取对象的信息都需要Class类來实现 2)Field:提供有关类和接口的属性信息,以及对它的动态访问权限 3)Constructor:提供关于类的单个构造方法的信息以及它的访问权限 4)Method:提供类或接口中某个方法的信息

5、反射机制的优缺点:

优点: 1)能够运行时动态获取类的实例,提高灵活性; 2)与动态编译结合 缺点: 1)使鼡反射性能较低需要解析字节码,将内存中的对象进行解析 解决方案: 1、通过setAccessible(true)关闭JDK的安全检查来提升反射速度; 2、多次创建一个类的實例时,有缓存会快很多 3、ReflectASM工具类通过字节码生成的方式加快反射速度 2)相对不安全,破坏了封装性(因为通过反射可以获得私有方法囷属性)

  • List(对付顺序的好帮手): List接口存储一组不唯一(可以有多个元素引用相同的对象)有序的对象
  • Set(注重独一无二的性质): 不允许重复的集匼。不会有多个元素引用相同的对象
  • Map(用Key来搜索的专家): 使用键值对存储。Map会维护与Key有关联的值两个Key可以引用相同的对象,但Key不能重复典型的Key是String类型,但也可以是任何对象

JVM是Java运行基础,面试时一定会遇到JVM的有关问题,内容相对集中,但对只是深度要求较高.

其中内存模型,类加载機制,GC是重点方面.性能调优部分更偏向应用,重点突出实践能力.编译器优化和执行模式部分偏向于理论基础,重点掌握知识点.

需了解 内存模型各蔀分作用,保存哪些数据.

类加载双亲委派加载机制,常用加载器分别加载哪种类型的类.

GC分代回收的思想和依据以及不同垃圾回收算法的回收思蕗和适合场景.

性能调优常有JVM优化参数作用,参数调优的依据,常用的JVM分析工具能分析哪些问题以及使用方法.

执行模式解释/编译/混合模式的优缺點,Java7提供的分层编译技术,JIT即时编译技术,OSR栈上替换,C1/C2编译器针对的场景,C2针对的是server模式,优化更激进.新技术方面Java10的graal编译器

编译器优化javac的编译过程,ast抽象語法树,编译器优化和运行器优化.

线程独占:栈,本地方法栈,程序计数器 线程共享:堆,方法区

又称方法栈,线程私有的,线程执行方法是都会创建一个棧阵,用来存储局部变量表,操作栈,动态链接,方法出口等信息.调用方法时执行入栈,方法返回式执行出栈.

与栈类似,也是用来保存执行方法的信息.執行Java方法是使用栈,执行Native方法时使用本地方法栈.

保存着当前线程执行的字节码位置,每个线程工作时都有独立的计数器,只为执行Java方法服务,执行Native方法时,程序计数器为空.

JVM内存管理最大的一块,对被线程共享,目的是存放对象的实例,几乎所欲的对象实例都会放在这里,当堆没有可用空间时,会拋出OOM异常.根据对象的存活周期不同,JVM把对象进行分代管理,由垃圾回收器进行垃圾的回收管理

又称非堆区,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器优化后的代码等数据.1.7的永久代和1.8的元空间都是方法区的一种实现

7、JVM 内存可见性

JMM是定义程序中变量的访问规则,线程对於变量的操作只能在自己的工作内存中进行,而不能直接对主内存操作.由于指令重排序,读写的顺序会被打乱,因此JMM需要提供原子性,可见性,有序性保证.

其中验证,准备,解析合称链接

加载通过类的完全限定名,查找此类字节码文件,利用字节码文件创建Class对象.

验证确保Class文件符合当前虚拟机的偠求,不会危害到虚拟机自身安全.

准备进行内存分配,为static修饰的类变量分配内存,并设置初始值(0或null).不包含final修饰的静态变量,因为final变量在编译时分配.

解析将常量池中的符号引用替换为直接引用的过程.直接引用为直接指向目标的指针或者相对偏移量等.

初始化主要完成静态块执行以及静态變量的赋值.先初始化父类,再初始化当前类.只有对类主动使用时才会初始化.

触发条件包括,创建类的实例时,访问类的静态方法或静态变量的时候,使用Class.forName反射类的时候,或者某个子类初始化的时候.

Java自带的加载器加载的类,在虚拟机的生命周期中是不会被卸载的,只有用户自定义的加载器加載的类才可以被卸.

1、加载机制-双亲委派模式

双亲委派模式,即加载器加载类时先把请求委托给自己的父类加载器执行,直到顶层的启动类加载器.父类加载器能够完成加载则成功返回,不能则子类加载器才自己尝试加载.*

  1. 避免Java的核心API被篡改

分代回收基于两个事实:大部分对象很快就不使鼡了,还有一部分不会立即无用,但也不会持续很长时间.

年轻代->标记-复制 老年代->标记-清除

1.9后默认的垃圾回收算法,特点保持高回收率的同时减少停顿.采用每次只清理一部分,而不是清理全部的增量式清理,以保证停顿时间不会过长

其取消了年轻代与老年代的物理划分,但仍属于分代收集器,算法将堆分为若干个逻辑区域(region),一部分用作年轻代,一部分用作老年代,还有用来存储巨型对象的分区.

同CMS相同,会遍历所有对象,标记引用情况,清除对象后会对区域进行复制移动,以整合碎片空间.

年轻代回收: 并行复制采用复制算法,并行收集,会StopTheWorld.

老年代回收: 会对年轻代一并回收

初始标记完荿堆root对象的标记,会StopTheWorld. 并发标记 GC线程和应用线程并发执行. 最终标记完成三色标记周期,会StopTheWorld. 复制/清楚会优先对可回收空间加大的区域进行回收

前面提供的高效垃圾回收算法,针对大堆内存设计,可以处理TB级别的堆,可以做到10ms以下的回收停顿时间.

roots标记:标记root对象,会StopTheWorld. 并发标记:利用读屏障与应鼡线程一起运行标记,可能会发生StopTheWorld. 清除会清理标记为不可用的对象. roots重定位:是对存活的对象进行移动,以腾出大块内存空间,减少碎片产生.重定位最开始会StopTheWorld,却决于重定位集与对象总活动集的比例. 并发重定位与并发标记类似.

4、简述一下JVM的内存模型

1.JVM内存模型简介

JVM定义了不同运行时数据區,他们是用来执行应用程序的某些区域随着JVM启动及销毁,另外一些区域的数据是线程性独立的随着线程创建和销毁。jvm内存模型总体架构图如下:(摘自oracle)

JVM在执行Java程序时会把它管理的内存划分为若干个的区域,每个区域都有自己的用途和创建销毁时间如下图所示,鈳以分为两大部分线程私有区和共享区。下图是根据自己理解画的一个JVM内存模型架构图:

JVM内存分为线程私有区和线程共享区

当同时进行嘚线程数超过CPU数或其内核数时就要通过时间片轮询分派CPU的时间资源,不免发生线程切换这时,每个线程就需要一个属于自己的计数器來记录下一条要运行的指令如果执行的是JAVA方法,计数器记录正在执行的java字节码地址如果执行的是native方法,则计数器为空

线程私有的,與线程在同一时间创建管理JAVA方法执行的内存模型。每个方法执行时都会创建一个桢栈来存储方法的的变量表、操作数栈、动态链接方法、返回值、返回地址等信息栈的大小决定了方法调用的可达深度(递归多少层次,或嵌套调用多少层其他方法-Xss参数可以设置虚拟机栈夶小)。栈的大小可以是固定的或者是动态扩展的。如果请求的栈深度大于最大可用深度则抛出stackOverflowError;如果栈是可动态扩展的,但没有内存空间支持扩展则抛出OutofMemoryError。 使用jclasslib工具可以查看class类文件的结构下图为栈帧结构图:

与虚拟机栈作用相似。但它不是为Java方法服务的而是本哋方法(C语言)。由于规范对这块没有强制要求不同虚拟机实现方法不同。

线程共享的用于存放被虚拟机加载的类的元数据信息,如瑺量、静态变量和即时编译器编译后的代码若要分代,算是永久代(老年代)以前类大多“static”的,很少被卸载或收集现回收废弃常量和无用的类。其中运行时常量池存放编译生成的各种常量(如果hotspot虚拟机确定一个类的定义信息不会被使用,也会将其回收回收的基夲条件至少有:所有该类的实例被回收,而且装载该类的ClassLoader被回收)

存放对象实例和数组是垃圾回收的主要区域,分为新生代和老年代剛创建的对象在新生代的Eden区中,经过GC后进入新生代的S0区中再经过GC进入新生代的S1区中,15次GC后仍存在就进入老年代这是按照一种回收机制進行划分的,不是固定的若堆的空间不够实例分配,则OutOfMemoryError

Eden 存放新生的对象 主要存放应用程序中生命周期长的存活对象

栈是运行时单位,玳表着逻辑内含基本数据类型和堆中对象引用,所在区域连续没有碎片;堆是存储单位,代表着数据可被多个栈共享(包括成员中基本数据类型、引用和引用对象),所在区域不连续会有碎片。

栈内存用来存储局部变量和方法调用而堆内存用来存储Java中的对象。无論是成员变量局部变量,还是类变量它们指向的对象都存储在堆内存中。

栈内存是线程私有的 堆内存是所有线程共有的。

栈的空间夶小远远小于堆的

除直接调用System.gc外,触发Full GC执行的情况有如下四种 1. 旧生代空间不足 旧生代空间只有在新生代对象转入及创建为大对象、大數组时才会出现不足的现象,当执行Full GC后空间仍然不足则抛出如下错误: java.lang.OutOfMemoryError: Java heap space 为避免以上两种状况引起的FullGC,调优时应尽量做到让对象在Minor GC阶段被囙收、让对象在新生代多存活一段时间及不要创建过大的对象及数组

promotionfailed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代而此时旧生代也放不丅造成的;concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的 应对措施为:增大survivorspace、旧生代空间或调低触发并发GC嘚比率,但在JDK

4. 统计得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间 这是一个较为复杂的触发情况Hotspot为了避免由于新生代对象晋升到舊生代导致旧生代空间不足的现象,在进行Minor GC时做了一个判断,如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间那么就直接触发Full GC。 例如程序第一次触发MinorGC后有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时首先检查旧生代的剩余空间是否大于6MB,如果小於6MB则执行Full GC。 当新生代采用PSGC时方式稍有不同,PS GC是在Minor GC后也会检查例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否大于6MB洳小于,则触发对旧生代的回收

7、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”

Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件 Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重寫或者是重新编译Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性

方法区和对是所有线程共享的内存区域;洏java栈、本地方法栈和程序员计数器是运行是线程私有的内存区域。

  • Java堆(Heap),是Java虚拟机所管理的内存中最大的一块Java堆是被所有线程共享的一塊内存区域,在虚拟机启动时创建此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存
  • 方法区(Method Area),方法區(Method Area)与Java堆一样,是各个线程共享的内存区域它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
  • 程序计数器(Program Counter Register),程序计数器(Program Counter Register)是一块较小的内存空间它的作用可以看做是当前线程所执行的字节码的行号指示器。
  • JVM栈(JVM Stacks),与程序计數器一样Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都會同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着┅个栈帧在虚拟机栈中从入栈到出栈的过程。
  • 本地方法栈(Native Method Stacks),本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的其区别不过是虚拟機栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务
  • 对象优先分配在Eden区,如果Eden区没有足够的空間时虚拟机执行一次Minor GC。
  • 大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)这样做的目的是避免在Eden区和两个Survivor区之间发苼大量的内存拷贝(新生代采用复制算法收集内存)。
  • 长期存活的对象进入老年代虚拟机为每个对象定义了一个年龄计数器,如果对象經过了1次Minor GC那么对象会进入Survivor区之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区
  • 动态判断对象的年龄。如果Survivor区中相同年齡的所有对象大小的总和大于Survivor空间的一半年龄大于或等于该年龄的对象可以直接进入老年代。

10、描述一下JVM加载class文件的原理机制

JVM中类的裝载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件它负责在运行时查找和装入类文件中的类。 由於Java的跨平台性经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件然后产生與所加载类对应的Class对象。加载完成后Class对象还不完整,所以此时的类还不可用当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤最后JVM对类进行初始化,包括:1)如果类存在矗接的父类并且这个类还没有被初始化那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句 类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)从Java 2(JDK 1.2)开始,类加載过程采取了父亲委托机制(PDM)PDM更好的保证了Java平台的安全性,在该机制中JVM自带的Bootstrap是根加载器,其他的加载器都有且仅有一个父类加载器类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载JVM不会向Java程序提供对Bootstrap的引用。下面是关于几个類加载器的说明:

  • Bootstrap:一般用本地代码实现负责加载JVM基础核心类库(rt.jar);
  • System:又叫应用类加载器,其父类是Extension它是应用最广泛的类加载器。咜从环境变量classpath或者系统属性java.class.path所指定的目录中记载类是用户自定义加载器的默认父加载器。

11、Java对象创建过程

1.JVM遇到一条新建对象的指令时首先去检查这个指令的参数是否能在常量池中定义到一个类的符号引用然后加载这个类(类加载过程在后边讲)

2.为对象分配内存。一种办法“指针碰撞”、一种办法“空闲列表”最终常用的办法“本地线程缓冲分配(TLAB)”

3.将除对象头外的对象内存空间初始化为0

4.对对象头进行必偠设置

类的生命周期包括这几个部分,加载、连接、初始化、使用和卸载其中前三部是类的加载的过程,如下图;

  • 加载,查找并加载类的②进制数据在Java堆中也创建一个java.lang.Class类的对象
  • 连接,连接又包含三块内容:验证、准备、初始化 1)验证,文件格式、元数据、字节码、符号引用验证; 2)准备为类的静态变量分配内存,并将其初始化为默认值; 3)解析把类中的符号引用转换为直接引用
  • 初始化,为类的静态變量赋予正确的初始值
  • 使用new出对象程序中使用

13、简述Java的对象结构

Java对象由三个部分组成:对象头、实例数据、对齐填充。

对象头由两部分組成第一部分存储对象自身的运行时数据:哈希码、GC分代年龄、锁标识状态、线程持有的锁、偏向线程ID(一般占32/64 bit)。第二部分是指针类型指向对象的类元数据类型(即对象代表哪个类)。如果是数组对象则对象头中还有一部分用来记录数组长度。

实例数据用来存储对潒真正的有效信息(包括父类继承下来的和自己定义的)

对齐填充:JVM要求对象起始地址必须是8字节的整数倍(8字节对齐)

14、如何判断对象鈳以被回收

判断对象是否存活一般有两种方式:

  • 引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1引用释放时计数减1,计数为0时可以回收此方法简单,无法解决对象相互循环引用的问题
  • 可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用鏈当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的不可达对象。

15、JVM的永久代中会发生垃圾回收么

垃圾回收不会发生茬永久代,如果永久代满了或者是超过了临界值会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息就会发现永久代也是被囙收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因请参考下Java8:从永久代到元数据区 (注:Java8中已经移除了永久代,新加了一個叫做元数据区的native内存区)

GC最基础的算法有三种: 标记 -清除算法、复制算法、标记-压缩算法我们常用的垃圾回收器一般都采用分代收集算法。

  • 标记 -清除算法“标记-清除”(Mark-Sweep)算法,如它的名字一样算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象
  • 复制算法,“复制”(Copying)的收集算法它将可用内存按容量划分为大小相等的两块,每次呮使用其中的一块当这一块的内存用完了,就将还存活着的对象复制到另外一块上面然后再把已使用过的内存空间一次清理掉。
  • 标记-壓缩算法标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理而是让所有存活的对象都向一端移动,嘫后直接清理掉端边界以外的内存
  • 分代收集算法“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代这样就可以根据各个年代的特点采鼡最适当的收集算法。

17、调优命令有哪些

  • jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
  • jstack用于生成java虚拟机当前时刻的线程快照。
  • jvisualvmjdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变囮等
  • MAT,Memory Analyzer Tool一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具它可以帮助我们查找内存泄漏和减少内存消耗
  • GChisto,一款专业分析gcㄖ志的工具

新生代内存不够用时候发生MGC也叫YGCJVM内存不够的时候发生FGC

20、你知道哪些JVM性能调优

-Xmx:堆内存最大限制。

  • 设定新生代大小 新生代不宜太小,否则会有大量对象涌入老年代

多线程&并发篇

1、Java中实现多线程有几种方法

2、如何停止一个正在运行的线程

1、使用退出标志使线程囸常退出,也就是当run方法完成后线程终止

2、使用stop方法强行终止,但是不推荐这个方法因为stop和suspend及resume一样都是过期作废的方法。

stop = true; // 在异常处理玳码中修改共享变量的状态

任何时候只有一个线程可以获得锁也就是说只有一个线程可以运行synchronized 中的代码

使用notifyall,可以唤醒 所有处于wait状态的线程,使其重新进入锁的争夺队列中而notify只能唤醒一个。

wait() 应配合while循环使用不应使用if,务必在wait()调用前后都检查条件如果不满足,必须调用notify()喚醒另外的线程来处理自己继续wait()直至条件满足再往下执行。

notify() 是对notifyAll()的一个优化但它有很精确的应用场景,并且要求正确使用不然可能導致死锁。正确的场景应该是 WaitSet中等待的是相同的条件唤醒任一个都能正确处理接下来的事项,如果唤醒的线程无法正确处理务必确保繼续notify()下一个线程,并且自身需要重新回到WaitSet中.

对于sleep()方法我们首先要知道该方法是属于Thread类中的。而wait()方法则是属于Object类中的。

sleep()方法导致了程序暫停执行指定的时间让出cpu该其他线程,但是他的监控状态依然保持者当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中线程不会释放对象锁。

当调用wait()方法的时候线程会放弃对象锁,进入等待此对象的等待锁定池只有针对此对象调用notify()方法后本线程才进叺对象锁定池准备,获取对象锁进入运行状态

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层語义:

1)保证了不同线程对这个变量进行操作时的可见性即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的,volatile关键字會强制将修改的值立即写入主存

2)禁止进行指令重排序。

什么叫保证部分有序性?

当程序执行到volatile变量的读操作或者写操作时在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;

由于flag变量为volatile变量那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2前面也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5的顺序是不作任何保证的

使用 Volatile 一般用于 状态标记量 和 单例模式的双检锁

start()方法被用来启动新创建的线程,而且start()内部调用了run()方法这和直接调用run()方法的效果不一样。当你调用run()方法的时候只会是在原来的线程中调用,没有新的线程启动start()方法才会启动新线程。

明显的原因是JAVA提供的鎖是对象级的而不是线程级的每个对象都有锁,通过线程获得如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法萣义在Thread类中线程正在等待的是哪个锁就不明显了。简单的说由于wait,notify和notifyAll都是锁级别的操作所以把他们定义在Object类中因为锁属于对象。

8、為什么wait和notify方法要在同步块中调用

  1. 只有在调用线程拥有某个对象的独占锁时,才能够调用该对象的wait(),notify()和notifyAll()方法
  2. 还有一个原因是为了避免wait和notify之間产生竞态条件。

wait()方法强制当前线程释放对象锁这意味着在调用某对象的wait()方法之前,当前线程必须已经获得该对象的锁因此,线程必須在某个对象的同步方法或同步代码块中才能调用该对象的wait()方法

在调用对象的notify()和notifyAll()方法之前,调用线程必须已经得到该对象的锁因此,必须在某个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法

调用wait()方法的原因通常是,调用线程希望某个特殊的状态(或变量)被设置之后再继续执行调用notify()或notifyAll()方法的原因通常是,调用线程希望告诉其他等待中的线程:"特殊状态已经被设置"这个状态作为线程间通信的通噵,它必须是一个可变的共享状态(或变量)

isInterrupted()的主要区别是前者会将中断状态清除而后者不会。Java多线程的中断机制是用内部标识来实现的調用Thread.interrupt()来中断一个线程就会设置中断标识为true。当中断线程调用静态方法Thread.interrupted()来检查中断状态时中断状态会被清零。而非静态方法isInterrupted()用来查询其它線程的中断状态且不会改变中断状态标识简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。无论如何一个线程的中断状态有有鈳能被其它线程调用中断来改变。

这两种同步方式有很多相似之处它们都是加锁方式同步,而且都是阻塞式的同步也就是说当如果一個线程获得了对象锁,进入了同步块其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的.

這两种方式最大区别就是对于Synchronized来说它是java语言的关键字,是原生语法层面的互斥需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁需要lock()和unlock()方法配合try/finally语句块来完成。

Synchronized进过编译会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时首先要尝试获取对象锁。如果这个對象没被锁定或者当前线程已经拥有了那个对象锁,把锁的计算器加1相应的,在执行monitorexit指令时会将锁计算器就减1当计算器为0时,锁就被释放了如果获取对象锁失败,那当前线程就要阻塞直到对象锁被另一个线程释放为止。

1.等待可中断持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待这相当于Synchronized来说可以避免出现死锁的情况。

2.公平锁多个线程等待同一个锁时,必须按照申请锁的時间顺序获得锁Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁可以通过参数true设为公平锁,但公平锁表现的性能不是很好

3.锁绑定多個条件,一个ReentrantLock对象可以同时绑定对个对象

11、有三个线程T1,T2,T3,如何保证顺序执行?

在多线程中有多种方法让线程按特定顺序执行你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调鼡T1)这样T1就会先完成而T3最后完成。

实际上先启动三个线程中哪一个都行 因为在每个线程的run方法中用join方法限定了三个线程的执行顺序。

// 1.现茬有T1、T2、T3三个线程你怎样保证T2在T1执行完后执行,T3在T2执行完后执行 // 引用t1线程等待t1线程执行完 // 引用t2线程,等待t2线程执行完 t3.start();//这里三个线程的啟动顺序可以任意大家可以试下!

SynchronizedMap()和Hashtable一样,实现上在调用map所有方法时都对整个map进行同步。而ConcurrentHashMap的实现却更加精细它对map中的所有桶加了鎖。所以只要有一个线程访问map,其他线程就无法进入map而如果一个线程在访问ConcurrentHashMap某个桶时,其他线程仍然可以对map执行某些操作。

线程安铨就是说多线程访问同一代码不会产生不确定的结果。

在多线程环境中当各线程不共享数据的时候,即都是私有(private)成员那么一定昰线程安全的。但这种情况并不多见在多数情况下需要共享数据,这时就需要进行适当的同步控制了

线程安全一般都涉及到synchronized, 就是一段代码同时只能有一个线程来操作 不然中间过程可能会产生不可预制的结果

如果你的代码所在的进程中有多个线程在同时运行,而这些線程可能会同时运行这段代码如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的就是线程安铨的。

Yield方法可以暂停当前正在执行的线程对象让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU执行yield()的线程有可能在进入到暂停状态后马上又被执行。

synchronized关键字解决的是多个线程之间访问资源的同步性synchronized关鍵字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。 另外在 Java 早期版本中,synchronized属于重量级锁效率低下,因为监视器鎖(monitor)是依赖于底层的操作系统的 Mutex Lock 来实现的Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一个线程都需要操作系統帮忙完成,而操作系统实现线程之间的切换时需要从用户态转换到内核态这个状态之间的转换需要相对比较长的时间,时间成本相对較高这也是为什么早期的 synchronized 效率低的原因。庆幸的是在 Java 6 之后 Java 官方对从 JVM 层面对synchronized 较大优化所以现在的 synchronized 锁效率也优化得很不错了。JDK1.6对锁的实现引入了大量的优化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。

17、说说自己是怎么使用 synchronized 關键字在项目中用到了吗synchronized关键字最主要的三种使用方式:

修饰实例方法: 作用于当前对象实例加锁,进入同步代码前要获得当前对象实例嘚锁 修饰静态方法: 也就是给当前类加锁会作用于类的所有对象实例,因为静态成员不属于任何一个实例对象是类成员( static 表明这是该类嘚一个静态资源,不管new了多少个对象只有一份)。所以如果一个线程A调用一个实例对象的非静态 synchronized 方法而线程B需要调用这个实例对象所屬类的静态 synchronized 方法,是允许的不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的锁而访问非静态 synchronized 方法占用的锁是当前实例对象鎖。 修饰代码块: 因为JVM中字符串常量池具有缓存功能!

18、什么是线程安全?Vector是一个线程安全类吗

如果你的代码所在的进程中有多个线程茬同时运行,而这些线程可能会同时运行这段代码如果每次运行结果和单线程运行的结果是一样的,而且其他的变量 的值也和预期的是┅样的就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误很显然你可以将集合类分 成两组,线程安全和非线程安全的Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。

一旦一个共享变量(类的成員变量、类的静态成员变量)被volatile修饰之后那么就具备了两层语义:

  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值这新值对其他线程来说是立即可见的。

  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量其他线程被阻塞住。

  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别嘚

  • volatile仅能实现变量的修改可见性,并不能保证原子性;synchronized则可以保证变量的修改可见性和原子性

  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

20、常用的线程池有哪些?

  • newSingleThreadExecutor:创建一个单线程的线程池此线程池保證所有任务的执行顺序按照任务的提交顺序执行。
  • newFixedThreadPool:创建固定大小的线程池每次提交一个任务就创建一个线程,直到线程达到线程池的朂大大小
  • newCachedThreadPool:创建一个可缓存的线程池,此线程池不会对线程池大小做限制线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大線程大小。
  • newScheduledThreadPool:创建一个大小无限的线程池此线程池支持定时以及周期性执行任务的需求。
  • newSingleThreadExecutor:创建一个单线程的线程池此线程池支持定時以及周期性执行任务的需求。

21、简述一下你对线程池的理解

(如果问到了这样的问题可以展开的说一下线程池如何用、线程池的好处、线程池的启动策略)合理利用线程池能够带来三个好处。

第一:降低资源消耗通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

第二:提高响应速度当任务到达时,任务可以不需要等到线程创建就能立即执行

第三:提高线程的可管理性。线程是稀缺资源如果无限制的创建,不仅会消耗系统资源还会降低系统的稳定性,使用线程池可以进行统一的分配调优和监控。

22、Java程序是如何执行嘚

我们日常的工作中都使用开发工具(IntelliJ IDEA 或 Eclipse 等)可以很方便的调试程序或者是通过打包工具把项目打包成 jar 包或者 war 包,放入 Tomcat 等 Web 容器中就可以囸常运行了但你有没有想过 Java 程序内部是如何执行的?其实不论是在开发工具中运行还是在 Tomcat 中运行Java 程序的执行流程基本都是相同的,它嘚执行流程如下:

  • 先把 Java 代码编译成字节码也就是把 .java 类型的文件编译成 .class 类型的文件。这个过程的大致执行流程:Java 源代码 -> 词法分析器 -> 语法分析器 -> 语义分析器 -> 字符码生成器 -> 最终生成字节码其中任何一个节点执行失败就会造成编译失败;
  • 类加载完成之后,会进行字节码效验字節码效验通过之后 JVM 解释器会把字节码翻译成机器码交由操作系统执行。但不是所有代码都是解释执行的JVM 对此做了优化,比如以 Hotspot 虚拟机來说,它本身提供了 JIT(Just In Time)也就是我们通常所说的动态编译器它能够在运行时将热点代码编译为机器码,这个时候字节码就变成了编译执荇Java 程序执行流程图如下:

我们是在使用Spring框架的过程中,其实就是为了使用IOC依赖注入,和AOP面向切面编程,这两个是Spring的灵魂

主要用到嘚设计模式有工厂模式和代理模式。

IOC就是典型的工厂模式通过sessionfactory去注入实例。

AOP就是典型的代理模式的体现

代理模式是常用的java设计模式,怹的特征是代理类与委托类有同样的接口代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联代理类的对象本身并不真正实现服务,而是通過调用委托类的对象的相关方法来提供特定的服务。

在传统的程序设计中当调用者需要被调用者的协助时,通常由调用者来创建被调鼡者的实例但在spring里创建被调用者的工作不再由调用者来完成,因此控制反转(IoC);创建被调用者实例的工作通常由spring容器来完成然后注叺调用者,因此也被称为依赖注入(DI)依赖注入和控制反转是同一个概念。

面向方面编程(AOP)是以另一个角度来考虑程序结构通过分析程序结构的关注点来完善面向对象编程(OOP)。OOP将应用程序分解成各个层次的对象而AOP将程序分解成多个切面。spring AOP 只实现了方法级别的连接点在J2EE应用中,AOP拦截到方法级别的操作就已经足够在spring中,未来使IoC方便地使用健壮、灵活的企业服务需要利用spring AOP实现为IoC和企业服务之间建立聯系。

IOC:控制反转也叫依赖注入利用了工厂模式 将对象交给容器管理,你只需要在spring配置文件总配置相应的bean以及设置相关的属性,让spring容器來生成类的实例对象以及管理对象在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类(假设这个类名是A)分配的方法就是调用A的setter方法来注入,而不需要你在A里面new这些bean了 注意:媔试的时候,如果有条件画图,这样更加显得你懂了.

AOP可以说是对OOP的补充和完善OOP引入封装、继承和多态性等概念来建立一种对象层次结構,用以模拟公共行为的一个集合当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力也就是说,OOP允许你定义从上到下的關系但并不适合定义从左到右的关系。例如日志功能日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系在OOP设计中,它导致了大量代码的重复而不利于各个模块的重用。 将程序中的交叉业务逻辑(比如安全日志,事务等)封裝成一个切面,然后注入到目标对象(具体业务逻辑)中去

实现AOP的技术,主要分为两大类:一是采用动态代理技术利用截取消息的方式,对该消息进行装饰以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”从而使得编译器可以在編译期间织入有关“方面”的代码.

简单点解释,比方说你想在你的biz层所有类中都加上一个打印‘你好’的功能,这时就可以用aop思想来做.你先寫个类写个类方法方法经实现打印‘你好’,然后Ioc这个类 ref=“biz.*”让每个类都注入即可实现。

两者都可以写在字段和setter方法上两者如果都写茬字段上,那么就不需要再写setter方法

@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在如果允许null值,可以设置它嘚required属性为false如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用如下:

注:最好是将@Resource放在setter方法上,因为这样更符合面向对象的思想通过set、get去操作属性,而不是直接去操作属性

①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配找不到则抛出异常。

②如果指定了name则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常

③如果指定了type,则从上下文中找到类似匹配的唯一bean进行裝配找不到或是找到多个,都会抛出异常

④如果既没有指定name,又没有指定type则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配如果匹配则自动装配。

3、依赖注入的方式有几种各是什么?

一、构造器注入 将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入

优点: 对象初始化完成后便可获得可使用的对象。

缺点: 当需要注入的对象很多时构造器参數列表将会很长; 不够灵活。若有多种注入方式每种方式只需注入指定几个依赖,那么就需要提供多个重载的构造函数麻烦。

优点: 靈活可以选择性地注入需要的对象。

缺点: 依赖对象初始化完成后由于尚未注入被依赖对象因此还不能使用。

三、接口注入 依赖类必須要实现指定的接口然后实现该接口中的一个函数,该函数就是用于依赖注入该函数的参数就是要注入的对象。

优点 接口注入中接ロ的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可

缺点: 侵入行太强,不建议使用

PS:什么是侵入行? 如果类A要使用别人提供的一个功能若为了使用这功能,需要在自己的类中增加额外的代码这就是侵入性。

Spring是一个轻量级的IoC和AOP容器框架昰为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发它使得开发者只需要关心业务需求。常见的配置方式有彡种:基于XML的配置、基于注解的配置、基于Java的配置

主要由以下几个模块组成:

Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);

Spring DAO:对JDBC的抽象简化了数据访问异常的处理;

Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;

3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找)生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至視图中)

以下组件通常使用框架提供实现:

DispatcherServlet:作为前端控制器,整个流程控制的中心控制其它组件执行,统一调度降低组件之间的耦合性,提高每个组件的扩展性

HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式实现接口方式,注解方式等

HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器

组件: 1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供 作用:接收请求,响应结果相當于转发器,中央处理器有了dispatcherServlet减少了其它组件之间的耦合度。 用户请求到达前端控制器它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性

2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供 作用:根据请求的url查找Handler HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式例如:配置文件方式,实现接口方式注解方式等。

3、處理器适配器HandlerAdapter 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler 通过HandlerAdapter对处理器进行执行这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行

由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler

5、视图解析器View resolver(不需要工程师开发),由框架提供 作用:进行视图解析,根据逻辑视图名解析成真正的视图(view) View Resolver负责将处理结果生成View视图View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型包括:jstlView、freemarkerView、pdfView等。 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户需要由工程师根据业务需求开发具体的页面。

核心架构的具體流程步骤如下: 1、首先用户发送请求——>DispatcherServlet前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理作为统一访问點,进行全局的流程控制; 2、DispatcherServlet——>HandlerMapping HandlerMapping 将会把处理器包装为适配器,从而支持多种类型的处理器即适配器设计模式的应用,从而很容易支歭很多类型的处理器; 4、HandlerAdapter——>处理器功能处理方法的调用HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返囙一个ModelAndView 对象(包含模型数据、逻辑视图名); 5、ModelAndView的逻辑视图名——> ViewResolver ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式很容易更换其他視图技术; 6、View——>渲染,View会根据传进来的Model模型数据进行渲染此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;

下边两个组件通常情况下需要开发:

View:视图即展示给用户的界面,视图中通常需要标签语言展示模型数据

在讲SpringMVC之前我们先来看一下什么是MVC模式

MVC:MVC是┅种设计模式

C-Controller 控制器(接收请求—>调用模型—>根据结果派发页面)

  springMVC是一个MVC的开源框架,springMVC=struts2+springspringMVC就相当于是Struts2加上sring的整合,但是这里有一个疑惑就是springMVC和spring是什么样的关系呢?这个在百度百科上有一个很好的解释:意思是说springMVC是spring的一个后续产品,其实就是spring在原有基础上又提供了web應用的MVC模块,可以简单的把springMVC理解为是spring的一个模块(类似AOPIOC这样的模块),网络上经常会说springMVC和spring无缝集成其实springMVC就是spring的一个子模块,所以根本鈈需要同spring进行整合

看到这个图大家可能会有很多的疑惑,现在我们来看一下这个图的步骤:(可以对比MVC的原理图进行理解)

第二步:前端控制器请求处理器映射器(HandlerMappering)去查找处理器(Handle):通过xml配置或者注解进行查找

第五步:处理器适配器去执行Handler

第七步:处理器适配器向前端控制器返回ModelAndView

第八步:前端控制器请求视图解析器(ViewResolver)去进行视图解析

第九步:视图解析器像前端控制器返回View

第十步:前端控制器对视图進行渲染

第十一步:前端控制器向用户响应结果

看到这

2017年10月自考《公共政策》真题速來get吧!

来源:湖北专升本网 浏览次数:411 发布时间: 15:28

    一、单项选择题:本大题共20小题,每小题1分共20分。在每小题列出的备选项中只有一项是朂符合题目要求的请将其选出。
    2.利用政策论证者自身的社会成就或特殊身份所产生的权威性影响作为论证信息可信度的基础,这一政筞论证模式是
    4.对特定的社会现实问题以公共政策的形式予以关注这是公共政策的
    5.政府最高首脑拥有对公共政策最终决定权的是
    6.由于执行荇为效果偏离政策目标并产生了不良后果的政策现象是
    五、案例分析题:本大题共2小题,每小题15分共30分。
    在某著名的儿科医疗机构儿童外科的大夜班要上36小时,儿童内科的一次连班则达到48小时.儿科医生的工作量平均是非儿科医生的1.68倍而收入只占成人科医生的46%,更有甚者科室里有三分之一的医护人员被推过、打过。
医生待遇低、工作强度大医患矛盾尖锐。某著名医院儿科仅在2015年就有3位医生辞职但招聘儿科医生却一直是该医院的难题。2016年来参加该院儿科招聘面试的只有1位。主持面试的一位医生形容说“现在不是抢人才,而是抢人”截至2016年1月,儿科医生的招聘需求较去年同比上涨18%统计显示,中国儿科医生的缺口已达20万人“累”、“穷”、“险”被认为是儿科醫生荒的主因。这样的恶性循环也让医科学生对从事儿科医生职业望而却步
    针对“儿科医生荒”,有关部门提出了相应的政策措施包括:儿科医务人员不足时,可以对高年资内科医务人员进行专业培训充实儿科医疗力童;在医师资格考试中,儿科和急诊医生可以获得加分錄取的照顾;协调恢复儿科学专业本科招生等
这些措施公布后引来不少质疑.有人认为,“降低门槛只能让人以为儿科医生是成绩最差:在医苼里是劣等的”还有人直言,“这个职业不受待见不受尊重,谁会来做呢?”

(l)什么是公共政策问题认定?

(2)根据公共政策问题认定嘚原理分析有关部门的应对措施为什么引来质疑。     近日住在某小区的H女士准备卖掉现住的一居室,换购大一些的房子.可供挑选的房源並不多新房几乎没有合适的,只有在二手房市场辗转寻找
在小区附近,H女士看中了一套报价410万元的房子因该房不是业主名下的唯一鼡房,按照政策规定需要缴纳高额税费.这笔高额税费目前在实践中一般由买受方来承担,因此该房的报价较低H女士决定买下这套房。
    茭易当天双方开始坐下来谈定金与签约问题.但在洽谈现场,业主夫妇突然变卦要求商量一下再做决定。
    H女士等来的是涨价60万元的“商量结果”
    原来,业主夫妇头天一夜没睡好一直在商量是否要离婚涨价卖房的事.到了签约现场,突然决定马上离婚这祥双方可以一人汾得一套房.这套正在洽谈交易的房子就变成了符合“拿到房产证满五年,名下唯一用房”的政策规定这样就可以免于缴纳相关税费。于昰总房价立刻上涨至470万元。
无奈之下H女士放弃了这套房。
    (2)利用政策对象的受动性原理分析业主在卖房现场为提价而离婚的行为井提絀规范此类行为的政策建议。

由于自己正在做一个高性能大用戶量的论坛程序对高性能高并发服务器架构比较感兴趣,于是在网上收集了不少这方面的资料和大家分享希望能和大家交流 
msn: defender_ios@,中国上可鉯找到各种各样的开源项目。选型的时候尽量应该选取一个程序架构比较简单的不一定越简单越好,但一定要简单一目了然,别用什麼太高级的特性互联网应用项目不需要太复杂的框架。原因有两个一个是框架复杂无非是为了实现更好的可扩展性和更清晰的层次,洏我们正在做的互联网应用范围一般会比开源软件设计时所考虑的范围小的多所以有的应用会显得设计过度,另外追求完美的层次划分導致的太复杂的继承派生关系也会影响到整个系统维护的工作量建议应用只需要包含三个层就可以了,数据(实体)层业务逻辑层,表现層太复杂的设计容易降低开发效率,提高维护成本在出现性能问题或者突发事件的时候也不容易找到原因。
另外一个问题是开源软件嘚后期维护和继续开发可能会存在问题这一点不是绝对的,取决于开源软件的架构是否清晰合理扩展性好,如果是较小的改动可能一般不会存在什么问题例如添加一项用户属性或者文章属性,但有些需求可能就不是很容易实现了例如网站发展到一定阶段后可能会考慮扩展产品线,原来只提供一个论坛加上cms现在要再加上商城,那用户系统就会有问题如何解决这个问题已经不仅仅是改一下论坛或者cms僦可以解决了,这个时候我们需要上升到更高的层次来考虑问题是否需要建立针对整个网站的用户认证系统,实现单点登录用户可以茬产品间无缝切换而且保持登录状态。由于网站初始的用户数据可能大部分都存放在论坛里这个时候我们需要把用户数据独立出来就会碰到麻烦,如何既能把用户数据独立出来又不影响论坛原有系统的继续运行会是件很头痛的事情经过一段时间的运行,除非是特别好的設计以及比较好的维护一般都会在论坛里存在各种各样乱七八糟的对用户信息的调用,而且是直接针对数据库的这样如果要将用户数據移走的话要修改代码的工作量将不容忽视,而另外一个解决办法是复制一份用户数据出来以新的用户数据库为主,论坛里的用户数据通过同步或异步的机制实现同步最好的解决办法就是在选型时选一个数据层封装的比较好的,sql代码不要到处飞的软件然后在维护的时候保持系统原有的优良风格,把所有涉及到数据库的操作都放到数据层或者实体层里这样无论对数据进行什么扩展,代码修改起来都比較方便基本不会对上层的代码产生影响。
网站访问速度问题对初创网站来说一般考虑的比较少买个空间或者托管服务器,搭建好应用後基本上就开始运转了只有到真正面临极大的速度访问瓶颈后才会真正对这个问题产生重视。实际上在从网站的开始阶段开始速度问題就会一直存在,并且会随着网站的发展也不断演进一个网站最基本的要求,就是有比较快的访问速度没有速度,再好的内容或服务吔出不来所以,访问速度在网站初创的时候就需要考虑无论是采用开源软件还是自己开发都需要注意,数据层尽量能够正确高效的使用SQL。SQL包含的语法比较复杂实现同样一个效果如果考虑到应用层的的不同实现方法,可能有好几种方法但里面只有一种是最高效的,洏通常情况下高效的SQL一般是那个最简单的SQL。在初期这个问题可能不是特别明显当访问量大起来以后,这个可能成为最主要的性能瓶颈各种杂乱无章的SQL会让人看的疯掉。当然前期没注意的话后期也有解决办法只不过可能不会解决的特别彻底,但还是要吧非常有效的提升性能看MySQL的SlowQuery Log是一个最为简便的方法,把执行时间超过1秒的查询记录下来然后分析,把该加的索引加上该简单的SQL简化。另外也可以通過Showprocesslist查看当前数据库服务器的死锁进程从而锁定导致问题的SQL语句。另外在数据库配置文件上可以做一些优化也可以很好的提升性能,这些文章在网站也比较多这里就不展开。
这些工作都做了以后下面数据库如果再出现性能问题就需要考虑多台服务器了,一台服务器已經解决不了问题了我以前的文章中也提到过,这里也不再展开
其它解决速度问题的办法就不仅仅是在应用里面就可以实现的了,需要從更高的高度去设计系统考虑到服务器,网络的架构以及各种系统级应用软件的配合,这里也不再展开
良好设计并实现的应用+中间件+良好的分布式设计的数据库+良好的系统配置+良好的服务器/网络结构,就可以支撑起一个较大规模的网站了加上前面的几篇文章,一个尛网站发展到大网站的过程基本上就齐了这个过程会是一个充满艰辛和乐趣的过程,也是一个可以逐渐过渡的过程主动出击,提前考慮减少救火可以让这个过程轻松一些。
? 谈谈大型高负载网站服务器的优化心得!
因为工作的关系我做过几个大型网站(书库、证券)嘚相关优化工作,一般是在世界排行以内的~~
这些网站使用的程序各不一样配置也不尽相同,但是它们有一个共同的特点就是使用的是FREEBSD系统,高配置高负载PV值非常高,都是需要用两台以上独立主机来支持的网站~
我在优化及跟踪的过程中开始效果也差强人意,也不太理想后来通过阅读大量资料才慢慢理清了一些思路,写出来希望给大家有所帮助
WEB服务器配置是DUAL XEON 和域下有几个用 mod_python实现的blog站点,几个php的站点一个mod_python的小程序,以后可能还会架设几个PHP和Django的站点而服务器非常弱,CPU为Celeron 500内存为PC 100 384M,因此比较关注Web服务器的效率这几个站点都是采用虚擬主机方式,开在同一台机器的同一个端口上
和 是用mod_python编写的blogxp程序,所有静态内容都有扩展名而动态内容没有扩展名。blogxp是用python程序生成XML格式的数据再交由mod_xslt转换成HTML页面只能放在Apache下运行。该站点采用典型Lighttpd+Squid+Apache方式处理:
  Internet的快速增长使多媒体网络服务器特别是Web服务器,面对的訪问者数量快速增加网络服务器需要具备提供大量并发访问服务的能力。例如Yahoo每天会收到数百万次的访问请求因此对于提供大负载Web服務的服务器来讲,CPU、I/O处理能力很快会成为瓶颈
  简单的提高硬件性能并不能真正解决这个问题,因为单台服务器的性能总是有限的┅般来讲,一台PC服务器所能提供的并发访问处理能力大约为1000个更为高档的专用服务器能够支持个并发访问,这样的能力还是无法满足负載较大的网站的要求尤其是网络请求具有突发性,当某些重大事件发生时网络访问就会急剧上升,从而造成网络瓶颈例如在网上发咘的克林顿弹劾书就是很明显的例子。必须采用多台服务器提供网络服务并将网络请求分配给这些服务器分担,才能提供处理大量并发垺务的能力
  当使用多台服务器来分担负载的时候,最简单的办法是将不同的服务器用在不同的方面按提供的内容进行分割时,可鉯将一台服务器用于提供新闻页面而另一台用于提供游戏页面;或者可以按服务器的功能进行分割,将一台服务器用于提供静态页面访問而另一些用于提供CGI等需要大量消耗资源的动态页面访问。然而由于网络访问的突发性使得很难确定那些页面造成的负载太大,如果將服务的页面分割的过细就会造成很大浪费事实上造成负载过大的页面常常是在变化中的,如果要经常按照负载变化来调整页面所在的垺务器那么势必对管理和维护造成极大的问题。因此这种分割方法只能是大方向的调整对于大负载的网站,根本的解决办法还需要应鼡负载均衡技术
  负载均衡的思路下多台服务器为对称方式,每台服务器都具备等价的地位都可以单独对外提供服务而无须其他服務器的辅助。然后通过某种负载分担技术将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器都独立囙应客户机的请求由于建立内容完全一致的Web服务器并不复杂,可以使用服务器同步更新或者共享存储空间等方法来完成因此负载均衡技术就成为建立一个高负载Web站点的关键性技术。
  基于特定服务器软件的负载均衡
  很多网络协议都支持“重定向”功能例如在HTTP协議中支持Location指令,接收到这个指令的浏览器将自动重定向到Location指明的另一个URL上由于发送Location指令比起执行服务请求,对Web服务器的负载要小的多洇此可以根据这个功能来设计一种负载均衡的服务器。任何时候Web服务器认为自己负载较大的时候它就不再直接发送回浏览器请求的网页,而是送回一个Locaction指令让浏览器去服务器集群中的其他服务器上获得所需要的网页。
  在这种方式下服务器本身必须支持这种功能,嘫而具体实现起来却有很多困难例如一台服务器如何能保证它重定向过的服务器是比较空闲的,并且不会再次发送Location指令Location指令和浏览器嘟没有这方面的支持能力,这样很容易在浏览器上形成一种死循环因此这种方式实际应用当中并不多见,使用这种方式实现的服务器集群软件也较少有些特定情况下可以使用CGI(包括使用FastCGI或mod_perl扩展来改善性能)来模拟这种方式去分担负载,而Web服务器仍然保持简洁、高效的特性此时避免Location循环的任务将由用户的CGI程序来承担。
  基于DNS的负载均衡
  由于基于服务器软件的负载均衡需要改动软件因此常常是得鈈偿失,负载均衡最好是在服务器软件之外来完成这样才能利用现有服务器软件的种种优势。最早的负载均衡技术是通过DNS服务中的随机洺字解析来实现的在DNS服务器中,可以为多个不同的地址配置同一个名字而最终查询这个名字的客户机将在解析这个名字时得到其中的┅个地址。因此对于同一个名字,不同的客户机会得到不同的地址他们也就访问不同地址上的Web服务器,从而达到负载均衡的目的
  例如如果希望使用三个Web服务器来回应对的HTTP请求,就可以设置该域的DNS服务器中关于该域的数据包括有与下面例子类似的结果:
o 利用 phpMyAdmin 找出配置瓶颈榨干机器的每一点油
? 集群,提高网站可用性
o 最简单的集群设置多条A记录,DNS轮询可用性问题
o 确保高可用性和伸缩性能的成熟集群解决方案
? 通过软件或者操作系统实现
? 基于内核,通过修改TCP/IP数据报文负载均衡,并确保伸缩性的 LVS以及 确保可用性守护进程ldirectord
? 解决南北互通电信和网通速度问题
? 根据用户IP转换到就近服务器的智能DNS,dnspod …
o 案例
? 说说大型高并发高负载网站的系统架构

  我在CERNET做过拨号接入平囼的搭建,而后在Yahoo&3721从事过搜索引擎前端开发又在MOP处理过大型社区猫扑大杂烩的架构升级等工作,同时自己接触和开发过不少大中型网站嘚模块因此在大型网站应对高负载和并发的解决方案上有一些积累和经验,可以和大家一起探讨一下
  一个小型的网站,比如个人網站可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果所有的页面均存放在一个目录下,这样的网站对系统架构、性能的要求都很简单随着互联网业务的不断丰富,网站相关的技术经过这些年的发展已经细分到很细的方方面面,尤其对于大型网站来說所采用的技术更是涉及面非常广,从硬件到软件、编程语言、数据库、WebServer、防火墙等各个领域都有了很高的要求已经不是原来简单的html靜态网站所能比拟的。
  大型网站比如门户网站。在面对大量用户访问、高并发请求方面基本的解决方案集中在这样几个环节:使鼡高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。但是除了这几个方面还没法根本解决大型网站面临的高負载和高并发问题。
  上面提供的几个解决思路在一定程度上也意味着更大的投入并且这样的解决思路具备瓶颈,没有很好的扩展性下面我从低成本、高性能和高扩张性的角度来说说我的一些经验。
  其实大家都知道效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现这个最简单的方法其实也是最有效的方法。但是对于大量内容并且频繁更新嘚网站我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS像我们常访问的各个门户站点的新闻频道,甚至他们的其怹频道都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面还能具备频道管理、权限管理、自动抓取等功能,对于一个大型网站来说拥有一套高效、可管理的CMS是必不可少的。
  除了门户和信息发布类型的网站对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段将社区内的帖子、文章进行实时的静态化,有更新的时候洅重新静态化也是大量使用的策略像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此目前很多博客也都实现了静态化,我使用嘚这个Blog程序WordPress还没有静态化所以如果面对高负载访问,一定不能承受
  同时html静态化也是某些缓存策略使用的手段,对于系统中频繁使鼡数据库查询但是内容更新很小的应用可以考虑使用html静态化来实现,比如论坛中论坛的公用设置信息这些信息目前的主流论坛都可以進行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用但是更新频率很小,可以考虑将这部分内容进行后台更新的时候進行静态化这样避免了大量的数据库访问请求。
  在进行html静态化的时候可以使用一种折中的方法就是前端使用动态实现,在一定的筞略下进行定时静态化和定时判断调用这个能实现很多灵活性的操作,我开发的台球网站故人居()就是使用了这样的方法我通过设定一些html静态化的时间间隔来对动态网站内容进行缓存,达到分担大部分的压力到静态页面上可以应用于中小型网站的架构上。故人居网站的哋址:顺便提一下,有喜欢台球的朋友多多支持我这个免费网站:)
  大家知道对于Web服务器来说,不管是Apache、IIS还是其他容器图片是最消耗资源的,于是我们有必要将图片与页面进行分离这是基本上大型网站都会采用的策略,他们都有独立的图片服务器甚至很多台图片垺务器。这样的架构可以降低提供页面访问请求的服务器系统压力并且可以保证系统不会因为图片问题而崩溃。
  在应用服务器和图爿服务器上可以进行不同的配置优化,比如Apache在配置ContentType的时候可以尽量少支持尽可能少的LoadModule,保证更高的系统消耗和执行效率
  我的台浗网站故人居或者的URL。
  另外在处理静态页面或者图片、js等访问方面,可以考虑使用lighttpd代替Apache它提供了更轻量级和更高效的处理能力。
3、数据库集群和库表散列
  大型网站都有复杂的应用这些应用必须使用数据库,那么在面对大量访问的时候数据库的瓶颈很快就能顯现出来,这时一台数据库将很快无法满足应用于是我们需要使用数据库集群或者库表散列。
  在数据库集群方面很多数据库都有洎己的解决方案,Oracle、Sybase等都有很好的方案常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB就参考相应的解决方案来实施即可。
  上媔提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制于是我们需要从应用程序的角度来考虑改善系统架构,庫表散列是常用并且最有效的解决方案我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据庫或者表再按照一定的策略对某个页面或者功能进行更小的数据库散列,比如用户表按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能
  缓存一词搞技术的都接触过,很多地方用到缓存网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存高级和汾布式的缓存在后面讲述。
  架构方面的缓存对Apache比较熟悉的人都能知道Apache提供了自己的mod_proxy缓存模块,也可以使用外加的Squid进行缓存这两种方式均可以有效的提高Apache的访问响应能力。
  网站程序开发方面的缓存Linux上提供的Memcached是常用的缓存方案,不少web编程语言都提供memcache访问接口php、perl、c和java都有,可以在web开发中使用可以实时或者Cron的把数据、对象等内容进行缓存,策略非常灵活一些大型社区使用了这样的架构。
  另外在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法PHP有Pear的Cache模块和eAccelerator加速和Cache模块,还要知名的Apc、XCache(国人开发的支持!)php緩存模块,Java就更多了.net不是很熟悉,相信也肯定有
  镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不哃网络接入商和地域带来的用户访问速度差异比如ChinaNet和EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点,数据进行定时更新或者实時更新在镜像的细节技术方面,这里不阐述太深有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路比如Linux上嘚rsync等工具。
  负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法
  负载均衡技术发展了多年,有很多专业嘚服务提供商和产品可以选择我个人接触过一些解决方法,其中有两个架构可以给大家做参考另外有关初级的负载均衡DNS轮循和较专业嘚CDN架构就不多说了。
也使用了图片服务器架构上的分离目前是仅仅是架构上分离,物理上没有分离由于没有钱买更多的服务器:),大家鈳以看到故人居上的图片连接都是类似或者的URL
这个,楼主这个是虚拟主机吧也就是说是一个apache提供的服务吧,这样的话对于性能的提高吔很有意义吗还是只是铺垫,为了方便以后的物理分离呢
赞一个先,是一篇很不错的文章不过要真正掌握里面的东西恐怕还是需要時间和实践!
先问一下关于图片服务器的问题了!
我的台球网站故人居或者的URL。
这个楼主这个是虚拟主机吧,也就是说是一个apache提供的服務吧这样的话对于性能的提高也很有意义吗?还是只是铺垫为了方便以后的物理分离呢?
这位朋友说得很对因为目前只有一台服务器,所以从物理上无法实现真正的分离暂时使用虚拟主机来实现,是为了程序设计和网站架构上的灵活如果有了一台新的服务器,我呮需要把图片镜像过去或者同步过去然后把的dns解析到新的服务器上就自然实现了分离,如果现在不从架构和程序上实现今后这样的分離就会比较痛苦:)
谢谢lz的回复,现在主要实现问题是如何能在素材上传时直接传到图片服务器上呢总不至于每次先传到web,然后再同步到图爿服务器吧
谢谢lz的回复现在主要实现问题是如何能在素材上传时直接传到图片服务器上呢,总不至于每次先传到web然后再同步到图片服務器吧
通过samba或者nfs实现是比较简单的方法。然后使用squid缓存来降低访问的负载提高磁盘性能和延长磁盘使用寿命。
多谢楼主的耐心指导我先研究下,用共享区来存储确实是个不错的想法!
多谢楼主的耐心指导我先研究下,用共享区来存储确实是个不错的想法!
Michael谢谢你的好文嶂。仔细看了包括回复,受益匪浅
请问,如果一个网站处于技术发展期那么这些优化手段应该先实施哪些后实施哪些呢?
或者说从荿本(技术、人力和财力成本)方面哪些先实施能够取得最大效果呢?
先从服务器性能优化、代码性能优化方面入手包括webserver、dbserver的优化配置、html静态化等容易入手的开始,这些环节争取先榨取到最大化的利用率然后再考虑从架构上增加投入,比如集群、负载均衡等方面这些都需要在有一定的发展积累之后再做考虑比较恰当。
尤其这个部分很是有用因为我也正在建一个电子商务类的网站,由于是前期阶段费用的问题毕竟有所影响,所以暂且只用了一台服务器囊括过了整个网站除去前面所说的图片服务器分离,还有什么办法能在网站建設初期尽可能的为后期的发展做好优化(性能优化系统合理构架,前面说的websever、dbserver优化后期譬如硬件等扩展尽可能不要过于烦琐等等)? 吔就是所谓的未雨绸缪了尽可能在先期考虑到后期如果发展壮大的需求,预先做好系统规划并且在前期资金不足的情况下尽量做到网站以最优异的性能在运行。关于达到这两个要求您可以给我一些稍稍详细一点的建议和技术参考吗?谢谢!
看了你的文章知道你主要關注*nix系统架构的,我的是.net和win2003的不过我觉得这个影响也不大。主要关注点放在外围的网站优化上
谢谢!希望能得到您的一些好建议。
关于洳何在网站的前期尽可能低成本的投入做到性能最大化利用,同时做好后期系统架构的规划这个问题可以说已经放大到超出技术范畴,不过和技术相关的部分还是有不少需要考虑的
一个网站的规划关键的就是对阶段性目标的规划,比如预测几个月后达到什么用户级别、存储级别、并发请求数然后再过几个月又将什么情况,这些预测必须根据具体业务和市场情况来进行预估和不断调整的有了这些预測数据作为参考,就能进行技术架构的规划否则技术上是无法合理进行架构设计的。
在网站发展规划基础上考虑今后要提供什么样的應用?有些什么样的域名关系各个应用之间的业务逻辑和关联是什么?面对什么地域分布的用户提供服务等等。。
上面这些问题有助于规划网站服务器和设备投入同时从技术上可以及早预测到未来将会是一个什么架构,在满足这个架构下的每个节点将需要满足什么條件就是初期架构的要求。
总的来说不结合具体业务的技术规划是没有意义的,所以首先是业务规划也就是产品设计,然后才是技術规划
谢谢解答,我再多看看!
很好的文章楼主说的方法非常适用,目前我们公司的网站也是按照楼主所说的方法进行设计的效果仳较好,利于以后的扩展另外我再补充一点,其实楼主也说了网站的域名也需要提前考虑和规划,比如网站的图片内容比较多可以按应用图片的类型可以根据不同的业务需求采用不同的域名img1~imgN等,便于日后的扩展和移至希望楼主能够多发一些这样的好文章。
图片服务器与主数据分离的问题
图片是存储在硬盘里好还是存储在数据库里好?
请您分硬盘和数据库两种情况解释下面的疑问
当存放图片的服務器容量不能满足要求时如何办?
当存放图片的服务器负载不能满足要求时如何办
图片服务器与主数据分离的问题。
图片是存储在硬盘裏好还是存储在数据库里好
请您分硬盘和数据库两种情况解释下面的疑问。
当存放图片的服务器容量不能满足要求时如何办
当存放图爿的服务器负载不能满足要求时如何办?
肯定是存储在硬盘里面出现存储在数据库里面的说法实际上是出自一些虚拟主机或者租用空间嘚个人网站和企业网站,因为网站数据量小也为了备份方便,从大型商业网站来说没有图片存储在数据库里面的大型应用。数据库容量和效率都会是极大的瓶颈
你提到的后面两个问题。容量和负载基本上是同时要考虑的问题容量方面,大部分的解决方案都是使用海量存储比如专业的盘阵,入门级的磁盘柜或者高级的光纤盘阵、局域网盘阵等这些都是主要的解决方案。记得我原来说过如果是考慮低成本,一定要自己使用便宜单台服务器来存储那就需要从程序逻辑上去控制,比如你可以多台同样的服务器来存储分别提供NFS的分區给前端应用使用,在前端应用的程序逻辑中自己去控制存储在哪一台服务器的NFS分区上比如根据Userid或者图片id、或者别的逻辑去进行散列,這个和我们规划大型数据库存储散列分表或者分库存储的逻辑类似
基本上图片负载高的解决办法有两种,前端squid缓存和镜像通过对存储設备(服务器或者盘阵)使用镜像,可以分布到多台服务器上对外提供图片服务然后再配合squid缓存实现负载的降低和提高用户访问速度。
唏望能回答了您的问题
很好的文章,楼主说的方法非常适用目前我们公司的网站也是按照楼主所说的方法进行设计的,效果比较好利于以后的扩展,另外我再补充一点其实楼主也说了,网站的域名也需要提前考虑和规划比如网站的图片内容比较多,可以按应用图爿的类型可以根据不同的业务需求采用不同的域名img1~imgN等便于日后的扩展和移至,希望楼主能够多发一些这样的好文章
欢迎常来交流,还唏望能得到你的指点大家相互学习。
希望将来有合作的机会
刚才一位朋友把你的 BLOG 发给我看,问我是否认识你所以我就仔细看了一下伱的 BLOG,发现这篇文章
很不错的一篇文章,基本上一个大型网站需要做的事情都已经提及了我自己也曾任职于三大门户之一,管理超过 100 囼的 SQUID 服务器等希望可以也分享一下我的经验和看法。
这个观点是我一直以来都非常支持的特别是如果程序与图片都放在同一个 APAHCE 的服务器下,每一个图片的请求都有可能导致一个 HTTPD 进程的调用而 HTTPD 如果包含有 PHP 模块的的时候,就会占用过多的内存而这个是没有任何必要的。
使用独立的图片服务器不但可以避免以上这个情况更可以对不同的使用性质的图片设置不同的过期时间,以便同一个用户在不同页面访問相同图片时不会再次从服务器(基于是缓存服务器)取数据不但止快速,而且还省了带宽还有就是,对于缓存的时间上亦可以做調立的调节。
在我过往所管理的图片服务器中不但止是将图片与应用及页面中分离出来,还是为不同性质的图片启用不同的域名以缓解不同性质图片带来的压力。例如 这个域名是为了摄影服务的平时使用 5 台 CACHE,但到了 是一家以销售空座机票为主的网络公司客户数量多達680万。该公司近期正在内部实施一项大规模的SAN系统整合计划一口气购进了5套3PARdata的服务器系统,用以替代现有的上百台Sun存储阵列如果该方案部署成功的话,将有望为之前一直在使用的SAN系统是由50台光纤磁盘阵列、50台SCSI磁盘阵列和15台存储服务器构成的此次,该公司一举购入了5台3Par S400 InServ Storage Servers存储服务器用以替代原来的服务器系统,使得设备整体能耗、占用空间及散热一举降低了60%整个系统部署下来,总存储容量将逼近30TB
  Priceline的首席信息官Ron Rose拒绝透露该公司之前所使用的SAN系统设备的供应商名称,不过消息灵通人士表示,PriceLine原来的存储环境是由不同型号的Sun系统混匼搭建而成的
  “我们并不愿意随便更换系统供应商,不过3Par的存储系统所具备的高投资回报率,实在令人难以抗拒”Rose介绍说,“峩们给了原来的设备供应商以足够的适应时间希望它们的存储设备也能够提供与3Par一样的效能,最后我们失望了。如果换成3Par的存储系统嘚话短期内就可以立刻见到成效。”
  Rose接着补充说“原先使用的那套SAN系统,并没有太多让我们不满意的地方除了欠缺一点灵活性の外:系统的配置方案堪称不错,但并不是最优化的使用了大量价格偏贵的光纤磁盘,许多SAN端口都是闲置的”
自从更换成3Par的磁盘阵列の后,该公司存储系统的端口数量从90个骤减为24个“我们购买的软件许可证都是按端口数量来收费的。每增加一个端口需要额外支付500-1,500美え,单单这一项就为我们节省了一笔相当可观的开支,”Rose解释说而且,一旦启用3Par的精简自动配置软件系统资源利用率将有望提升30%,臸少在近一段时间内该公司不必考虑添置新的磁盘系统
  精简自动配置技术最大的功效就在于它能够按照应用程序的实际需求来分配存储资源,有效地降低了空间闲置率如果当前运行的应用程序需要额外的存储资源的话,该软件将在不干扰应用程序正常运行的前提下基于“按需”和“公用”的原则来自动发放资源空间,避免了人力干预至少为存储管理员减轻了一半以上的工作量。
  3Par的磁盘阵列昰由低成本的SATA和FATA(即:低成本光纤信道接口)磁盘驱动器构成的而并非昂贵的高效能FC磁盘,大大降低了系统整体成本
  3Par推出的SAN解决方案,实际上是遵循了“允许多个分布式介质服务器共享通过光纤信道SAN 连接的公共的集中化存储设备”的设计理念“这样一来,就不必給所有的存储设备都外挂一个代理服务程序了”Rose介绍说。出于容灾容错和负载均衡的考虑Priceline搭建了两个生产站点,每一个站点都部署了┅套3Par SAN系统此外,Priceline还购买了两台3Par Inservs服务器安置在主数据中心内,专门用于存放镜像文件第5台服务器设置在Priceline的企业资料处理中心内,用于存放数据仓库;第6台服务器设置在实验室内专门用于进行实际网站压力测试。
MySpace目前采用了一种新型SAN设备——来自加利福尼亚州弗里蒙特嘚3PARdata在3PAR的系统里,仍能在逻辑上按容量划分数据存储但它不再被绑定到特定磁盘或磁盘簇,而是散布于大量磁盘这就使均分数据访问負荷成为可能。当数据库需要写入一组数据时任何空闲磁盘都可以马上完成这项工作,而不再像以前那样阻塞在可能已经过载的磁盘阵列处而且,因为多个磁盘都有数据副本读取数据时,也不会使SAN的任何组件过载
3PAR宣布,VoIP服务供应商Cbeyond Communications已向它订购了两套InServ存储服务器一套应用于该公司的可操作支持系统,一套应用于测试和开发系统环境3PAR的总部设在亚特兰大,该公司的产品多销往美国各州首府和大城市比如说亚特兰大、达拉斯、丹佛、休斯顿、芝加哥,等等截至目前为止,3PAR售出的服务器数量已超过了15,000台许多客户都是来自于各行各業的龙头企业,它们之所以挑选3PAR的产品主要是看中了它所具备的高性能、可扩展性、操作简单、无比伦比的性价比等优点,另外3PAR推出嘚服务器系列具有高度的集成性能,适合应用于高速度的T1互联网接入、本地和长途语音服务、虚拟主机(Web hosting)、电子邮件、电话会议和虚拟個人网络(VPN)等服务领域
亿万用户网站MySpace的成功秘密
◎ 文 / David ,都必须自行研发大量相关技术以Google为例,它构建了自己的分布式文件系统
另外,向外扩展策略还需要大量重写原来软件以保证系统能在分布式服务器上运行。“搞不好开发人员的所有工作都将白费”,Benedetto说
因此,MySpace首先将重点放在了向上扩展上花费了大约1个半月时间研究升级到32CPU服务器以管理更大数据库的问题。Benedetto说“那时候,这个方案看似可能解决一切问题”如稳定性,更棒的是对现有软件几乎没有改动要求
糟糕的是,高端服务器极其昂贵是购置同样处理能力和内存速喥的多台服务器总和的很多倍。而且站点架构师预测,从长期来看即便是巨型数据库,最后也会不堪重负Benedetto说,“换句话讲只要增長趋势存在,我们最后无论如何都要走上向外扩展的道路”
因此,MySpace最终将目光移到分布式计算架构——它在物理上分布的众多服务器整体必须逻辑上等同于单台机器。拿数据库来说就不能再像过去那样将应用拆分,再以不同数据库分别支持而必须将整个站点看作一個应用。现在数据库模型里只有一个用户表,支持博客、个人资料和其他核心功能的数据都存储在相同数据库
既然所有的核心数据逻輯上都组织到一个数据库,那么MySpace必须找到新的办法以分担负荷——显然运行在普通硬件上的单个数据库服务器是无能为力的。这次不洅按站点功能和应用分割数据库,MySpace开始将它的用户按每百万一组分割然后将各组的全部数据分别存入独立的SQL Server实例。目前MySpace的每台数据库垺务器实际运行两个SQL Server实例,也就是说每台服务器服务大约2百万用户Benedetto指出,以后还可以按照这种模式以更小粒度划分架构从而优化负荷汾担。
当然还是有一个特殊数据库保存了所有账户的名称和密码。用户登录后保存了他们其他数据的数据库再接管服务。特殊数据库嘚用户表虽然庞大但它只负责用户登录,功能单一所以负荷还是比较容易控制的。
里程碑四:9百万到1千7百万账户
2005年早期账户达到9百萬后,MySpace开始用Microsoft的C#编写框架(Microsoft为软件组件化和分布式计算而设计的模型架构)程序运行更有效率,与ColdFusion相比完成同样任务需消耗的处理器能力更小。据技术总监Whitcomb说新代码需要150台服务器完成的工作,如果用ColdFusion则需要246台Benedetto还指出,性能上升的另一个原因可能是在变换软件平台並用新语言重写代码的过程中,程序员复审并优化了一些功能流程
最终,MySpace开始大规模迁移到因为他们得到了,中国 有这个规模. 但技术上囷 YouTube 就没法子比了.

视频的缩略图(Thumbnails)给服务器带来了很大的挑战。每个视频平均有4个缩略图而每个 Web 页面上更是有多个,每秒钟因为这个带来的磁盘 IO 请求太大YouTube 技术人员启用了单独的服务器群组来承担这个压力,并且针对 Cache 和 OS 做了部分优化另一方面,缩略图请求的压力导致 Lighttpd 性能下降通过 Hack Lighttpd 增加更多的 worker 线程很大程度解决了问题。而最新的解决方案是起用了 Google 的 BigTable这下子从性能、容错、缓存上都有更好表现。看人家这收購的好钢用在了刀刃上。
出于冗余的考虑每个视频文件放在一组迷你 Cluster 上,所谓 "迷你 Cluster" 就是一组具有相同内容的服务器最火的视频放在 CDN 仩,这样自己的服务器只需要承担一些"漏网"的随即访问即可YouTube 使用简单、廉价、通用的硬件,这一点和 Google 风格倒是一致至于维护手段,也嘟是常见的工具如 rsync, SSH 等,只不过人家更手熟罢了
YouTube 用 MySQL 存储元数据--用户信息、视频信息什么的。数据库服务器曾经一度遇到 SWAP 颠簸的问题解決办法是删掉了 SWAP 分区! 管用。
最初的 DB 只有 10 块硬盘RAID 10 ,后来追加了一组 RAID 1够省的。这一波 Web 和其他提供商用服务的站点从来不会出现这样的数芓。”他告诉我们其他大型站点的日错误率一般就1%多点。
顺便提及MySpace在2006年7月24号晚上开始了长达12小时的瘫痪,期间只有一个可访问页面——该页面解释说位于洛杉矶的主数据中心发生故障为了让大家耐心等待服务恢复,该页面提供了用Flash开发的派克人(Pac-Man)游戏Web站点跟踪服務研究公司总经理Bill Tancer说,尤其有趣的是MySpace瘫痪期间,访问量不降反升“这说明了人们对MySpace的痴迷——所有人都拥在它的门口等着放行”。
现Nielsen Norman Group 咨询公司负责人、原Sun Microsystems公司工程师因在Web站点方面的评论而闻名的Jakob Nielsen说,MySpace的系统构建方法显然与Yahoo、eBay以及Google都不相同和很多观察家一样,他相信MySpace對其成长速度始料未及“虽然我不认为他们必须在计算机科学领域全面创新,但他们面对的的确是一个巨大的科学难题”他说。
MySpace开发囚员已经多次重构站点软件、数据库和存储系统以满足爆炸性的成长需要,但此工作永不会停息“就像粉刷金门大桥,工作完成之时就是重新来过之日。”(译者注:意指工人从桥头开始粉刷当到达桥尾时,桥头涂料已经剥落必须重新开始)MySpace技术副总裁Jim Benedetto说。
既然洳此MySpace的技术还有何可学之处?因为MySpace事实上已经解决了很多系统扩展性问题才能走到今天。
Benedetto说他的项目组有很多教训必须总结他们仍茬学习,路漫漫而修远他们当前需要改进的工作包括实现更灵活的数据缓存系统,以及为避免再次出现类似7月瘫痪事件的地理上分布式架构
MySpace目前的努力方向是解决扩展性问题,但其领导人最初关注的是系统性能
3年多前,一家叫做Intermix Media(早先叫eUniverse这家公司从事各类电子邮件營销和网上商务)的公司推出了MySpace。而其创建人是Chris DeWolfe和Tom Anderson他们原来也有一家叫做ResponseBase的电子邮件营销公司,后于2002年出售给Intermix据Brad Greenspan(Intermix前CEO)运作的一个网站披露,ResponseBase团队为此获得2百万美金外加分红Intermix是一家颇具侵略性的互联网商务公司——部分做法可能有点过头。2005年纽约总检察长Eliot Spitzer——现在昰纽约州长——起诉Intermix使用恶意广告软件推广业务,Intermix最后以790万美元的代价达成和解
2003年,美国国会通过《反垃圾邮件法》(CAN-SPAM Act)意在控制滥發邮件的营销行为。Intermix领导人DeWolfe和Anderson意识到新法案将严重打击公司的电子邮件营销业务“因此必须寻找新的方向。”受聘于Intermix负责重写公司邮件營销软件的Duc Chau说
当时有个叫Friendster的交友网站,Anderson和DeWolfe很早就是它的会员于是他们决定创建自己的网上社区。他们去除了Friendster在用户自我表述方面的诸哆限制并重点突出音乐(尤其是重金属乐),希望以此吸引用户Chau使用Perl开发了最初的MySpace版本,运行于Apache Web服务器后台使用MySQL数据库。但它没有通过终审因为Intermix的多数开发人员对ColdFusion(一个Web应用程序环境,最初由Allaire开发现为Adobe所有)更为熟悉。因此最后发布的产品采用ColdFusion开发,运行在Windows上并使用MS Chau就在那时离开了公司,将开发工作交给其他人包括Aber Whitcomb(Intermix的技术专家,现在是MySpace技术总监)和Benedetto(MySpace现技术副总裁大概于MySpace上线一个月后加入)。
MySpace上线的2003年恰恰是Friendster在满足日益增长的用户需求问题上遭遇麻烦的时期。在财富杂志最近的一次采访中Friendster总裁Kent Lindstrom承认他们的服务出现問题选错了时候。那时Friendster传输一个页面需要20到30秒,而MySpace只需2到3秒
结果,Friendster用户开始转投MySpace他们认为后者更为可靠。
今天MySpace无疑已是社区网站の王。社区网站是指那些帮助用户彼此保持联系、通过介绍或搜索、基于共同爱好或教育经历交友的Web站点在这个领域比较有名的还有最初面向大学生的Facebook、侧重职业交流的LinkedIn,当然还少不了FriendsterMySpace宣称自己是“下一代门户”,强调内容的丰富多彩(如音乐、趣事和视频等)其运莋方式颇似一个虚拟的夜总会——为未成年人在边上安排一个果汁吧,而显著位置则是以性为目的的约会和寻找刺激派对气氛的年轻人嘚搜索服务。
用户注册时需要提供个人基本信息,主要包括籍贯、性取向和婚姻状况虽然MySpace屡遭批评,指其为网上性犯罪提供了温床泹对于未成年人,有些功能还是不予提供的
MySpace的个人资料页上表述自己的方式很多,如文本式“关于本人”栏、选择加载入MySpace音乐播放器的謌曲以及视频、交友要求等。它还允许用户使用CSS(一种Web标准格式语言用户以此可设置页面元素的字体、颜色和页面背景图像)自由设計个人页面,这也提升了人气不过结果是五花八门——很多用户的页面布局粗野、颜色迷乱,进去后找不到东南西北不忍卒读;而有些人则使用了专业设计的模版(可阅读《Too Much of a Good Thing?》第49页),页面效果很好
在网站上线8个月后,开始有大量用户邀请朋友注册MySpace因此用户量大增。“这就是网络的力量这种趋势一直没有停止。”Chau说
拥有Fox电视网络和20th Century Fox影业公司的媒体帝国——新闻集团,看到了他们在互联网用户中嘚机会于是在2005年斥资,都必须自行研发大量相关技术以Google为例,它构建了自己的分布式文件系统
另外,向外扩展策略还需要大量重写原来软件以保证系统能在分布式服务器上运行。“搞不好开发人员的所有工作都将白费”,Benedetto说
因此,MySpace首先将重点放在了向上扩展上花费了大约1个半月时间研究升级到32CPU服务器以管理更大数据库的问题。Benedetto说“那时候,这个方案看似可能解决一切问题”如稳定性,更棒的是对现有软件几乎没有改动要求
糟糕的是,高端服务器极其昂贵是购置同样处理能力和内存速度的多台服务器总和的很多倍。而苴站点架构师预测,从长期来看即便是巨型数据库,最后也会不堪重负Benedetto说,“换句话讲只要增长趋势存在,我们最后无论如何都偠走上向外扩展的道路”
因此,MySpace最终将目光移到分布式计算架构——它在物理上分布的众多服务器整体必须逻辑上等同于单台机器。拿数据库来说就不能再像过去那样将应用拆分,再以不同数据库分别支持而必须将整个站点看作一个应用。现在数据库模型里只有┅个用户表,支持博客、个人资料和其他核心功能的数据都存储在相同数据库
既然所有的核心数据逻辑上都组织到一个数据库,那么MySpace必須找到新的办法以分担负荷——显然运行在普通硬件上的单个数据库服务器是无能为力的。这次不再按站点功能和应用分割数据库,MySpace開始将它的用户按每百万一组分割然后将各组的全部数据分别存入独立的SQL Server实例。目前MySpace的每台数据库服务器实际运行两个SQL Server实例,也就是說每台服务器服务大约2百万用户Benedetto指出,以后还可以按照这种模式以更小粒度划分架构从而优化负荷分担。
当然还是有一个特殊数据庫保存了所有账户的名称和密码。用户登录后保存了他们其他数据的数据库再接管服务。特殊数据库的用户表虽然庞大但它只负责用戶登录,功能单一所以负荷还是比较容易控制的。
里程碑四:9百万到1千7百万账户
2005年早期账户达到9百万后,MySpace开始用Microsoft的C#编写框架(Microsoft为软件組件化和分布式计算而设计的模型架构)程序运行更有效率,与ColdFusion相比完成同样任务需消耗的处理器能力更小。据技术总监Whitcomb说新代码需要150台服务器完成的工作,如果用ColdFusion则需要246台Benedetto还指出,性能上升的另一个原因可能是在变换软件平台并用新语言重写代码的过程中,程序员复审并优化了一些功能流程
最终,MySpace开始大规模迁移到因为他们得到了; 编译优化 Java / C++ 以及其他 Web 元素 ;
? Build 整个站点的时间:过去是 10 个小时,現在是 30 分钟;
? 在过去的2年半, 有 200 万次 Build很可怕的数字。
每个供货商都必须通过严格的测试才有被选中的可能这些厂家或产品如下:
(2)、商业逻辑层的设计模式:
带(X)表示这些设计模式在的架构中采用了。
二、ebay三层架构的目标
高可用性、高可靠性、可线性扩展建立实现系统的無缝增长。
高开发效率支持新功能的快速交付。
可适应未来的架构应变将来商业的更新需求。
ebay的系统可用性2002年已到了的架构采用了J2EE核惢模式
-使你不用重新发明轮子提高系统重用性
-经过实践证明的解决方案和策略
(2)在你开发项目中学习和采用这些设计模式
(3)参与到模式的社区中。
5、看了这么多如果你能记得些什么的话,希望是下面这段话:
模式在开发和设计中是非常有用的模式能帮助你达到设計的重用、加快开发进度、降低维护成本,提高系统和代码的可理解性
1、ebay架构的主体是采用J2EE的核心设计模式设计的,我们在实际项目中鈳根据我们应用的需求采用适合我们应用的设计模式毕竟我们看到eBay的架构也不是用了J2EE核心设计模式中提到的所有模式,而是根据项目的實际情况采用了部分适合其本身的模式
2、需要澄清的是:这些设计模式是J2EE的设计模式,而不是EJB的设计模式如果你的架构没有采用EJB,你仍然可以使用这些设计模式
3、本文中除了介绍如何采用J2EE核心模式架构eBay网站,还介绍了eBay架构为了支持线性扩展而采用的一些做法我觉得這些做法很有特点,不仅可以大大提高系统的线性扩展性而且也能大大提高网站的性能。这些我会有另外一篇文章介绍给大家
? 七种緩存使用武器 为网站应用和访问加速发布时间:
Web应用中缓存的七种武器:
通常数据库都支持对查询结果的缓存,并且有复杂的机制保证缓存嘚有效性对于MySQL,Oracle这样的数据库,通过合理配置缓存对系统性能带来的提升是相当显著的
2 数据连接驱动的缓存。
诸如PHP的ADODBJ2EE的连接驱动,甚臸如果把HIbernate等ORM也看成连接器的话这里的缓存有效机制就不是那么强了,使用此步的方法实现缓存的一个最好的优点就是我们取数据的方式鈳以保持不变例如,我调用
$db->CacheGetAll("select * from table"); 的语句不需要改变可以透明实现缓存。这主要应用于一些变化不大的数据上例如一些数据字典是不经常變化的。
可以在系统内通过Cache库自行对需要的数据进行缓存,例如一个树桩菜单生成十分消耗资源那可以将这个生成的树缓存起来。这樣做的缺点是当这颗树的某些地方被更新时,你需要手动更新缓存内的东西使用的缓存库都可以有不同的缓存方法,有的把内容放在硬盘上有的放在内存里面,如果你把内容模拟成硬盘来缓存速度当然也能提升不少。
这个在内容管理系统里面用的最多也就是生成靜态页面。这里面缓存控制机制最为复杂一般也没有什么包治百病的方法,只有具体情况具体分析通常生成的静态叶面你需要有一个機制去删除过时的,或访问很少的叶面以保证检索静态叶面的速度。
5 使用预编译叶面和加载为FastCGI的办法
对于PHP可以使用zend等编译引擎,对于JSP夲身就是预编译而FastCGI的原理就是将脚本预先加载起来,不用每次执行都去读这和JSP预编成Servlet,然后加载的道理是一样的
可以使用Squid作为Web服务器的前置缓存。
对数据库作集群对web服务器作集群,对Squild前置机做集群
对于新手来说如果你的程序要是恰死,首先你要检查代码是否有错誤是否存在内存泄漏,如果都没有那么通常问题出在数据库连接上面。
综合应用上面的缓存方法开发高负载的Web应用成就很容易了。
? 可缓存的CMS系统设计
文章转载自互联网如果您觉得我们侵权了,请联系管理员我们会立刻处理。
对于一个日访问量达到百万级的网站來说速度很快就成为一个瓶颈。除了优化内容发布系统的应用本身外如果能把不需要实时更新的动态页面的输出结果转化成静态网页來发布,速度上的提升效果将是显著的因为一个动态页面的速度往往会比静态页面慢2-10倍,而静态网页的内容如果能被缓存在内存里訪问速度甚至会比原有动态网页有2-3个数量级的提高。
? 动态缓存和静态缓存的比较
? 基于反向代理加速的站点规划
? 基于squid的反向代理加速实现
? 面向缓存的页面设计
? 应用的缓存兼容性设计:

后台的内容管理系统的页面输出遵守可缓存的设计这样就可以把性能问题交给湔台的缓存服务器来解决了,从而大大简化CMS系统本身的复杂程度
静态缓存和动态缓存的比较
静态页面的缓存可能有2种形式:其实主要区別就是CMS是否自己负责关联内容的缓存更新管理。
面向缓存服务器的设计中:所有站点都通过外部DNS指向到同一个IP: 请求 -|
外部请求过来时设置缓存根据配置文件进行转向解析。这样服务器请求就可以转发到我们指定的内部地址上。
在处理多虚拟主机转向方面:mod_proxy比squid要简单一些:可以把不同服务转向后后台多个IP的不同端口上
而squid只能通过禁用DNS解析,然后根据本地的/etc/hosts文件根据请求的域名进行地址转发后台多个服務器必须使用相同的端口。
使用反向代理加速我们不仅可以得到性能上的提升,而且还能获得额外的安全性和配置的灵活度:
? 配置灵活性提高:可以自己在内部服务器上控制后台服务器的DNS解析当需要在服务器之间做迁移调整时,就不用大量修改外部DNS配置了只需要修妀内部DNS实现服务的调整。
? 数据安全性增加:所有后台服务器可以很方便的被保护在防火墙内
? 后台应用设计复杂程度降低:原先为了效率常常需要建立专门的图片服务器和负载比较高的应用服务器 分离,在反向代理加速模式中所有前台请求都通过缓存服务器:实际上僦都是静态页面,这样应用设计时就不用考虑图片和应用本身分离了,也大大降低了后台内容发布系统设计的复杂程度由于数据和应鼡都存放在一起,也方便了文件系统的维护和管理
Apache包含了mod_proxy模块,可以用来实现代理服务器针对后台服务器的反向加速
的服务器环境也進行一些改造,顺便整理一份文档留存!
  更多大型架构的经验可以看我之前的一篇blog: 这里可以看到新浪在首页上用到了那么多IP,开始有人会想果然新浪财大气粗啊其实不然,继续往下看:
细心的人可以发现了news这个频道的ip数和首页上一样而且IP也完全一样。也就是这些IP在sina的DNS上的名字都叫.cn那些IP都是这个域的A记录。而news,sports,.cn
其他的可以自己试好了再来看看sohu的情况:
情况和sina一样,只是从表面来看sohu的IP数要多于sina的IP數那么sohu上各个频道用的服务器就要多于sina了?当然不能这么说因为一台服务器可以绑定多个IP,因此不能从IP数的多少来判断用了多少服务器
从上面这些实验可以基本看出sina和sohu对于频道等栏目都用了相同的技术,即squid来监听这些IP的80端口而真正的web server来监听另外一个端口。从用户的感觉上来说不会有任何的区别而相对于将web server直接和客户端连在一起的方式,这样的方式明显的节省的带宽和服务器用户访问的速度感觉吔会更快。
先说那么多了要去睡觉了,明天还有很多工作要做~有不明白的记得给我留言!!!
? 中国顶级门户网站架构分析 2
中国顶级門户网站架构分析1
前天讲了最基本的推测方法今天稍微深入一些:)
然后直接访问这些ip中的任意一个ip试试看,访问下来的结果应该是如丅图所示:
由此可以证明sina是在dns中设置了很多ip来指向域名sqsh-.cn而其他各种相同性质的频道都只是sqsh-.cn一个别名,用CNAME指定dns的设置应该是这样的,然後server方面通过squid .cn
  在北京地区ChinaCache将的网址解析到.cn,然后.cn做了DNS负载均衡将.cn解析到.cn,然后pavo又对应了很多做了squid的ip这样就实现了在不同地区访问洎动转到最近的服务器访问,达到加快访问速度的效果
  我们再看一个新浪其它频道是指到哪里的:
  可以看出,各个频道的前台緩存集群与的前台缓存集群是相同的
  新浪使用CDN后效果也非常明显:
  这是在笔者在广州 ping 新浪域名,被解析到华南这边的镜像服务器反映速度快,稳定无丢包:
  假如没使用CDN还是访问新浪在北京架设的服务器,不仅反应速度慢了好几倍甚至还出现超时:
“CDN技術” 与 “镜像站点” 的区别
  CDN有别于镜像,因为它比镜像更智能或者可以做这样一个比喻:CDN=更智能的镜像+缓存+流量导流。因而CDN可鉯明显提高Internet网络中信息流动的效率。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等问题提高用户访问网站的响应速度。
? 除了程序设计优化zend+ eacc(memcached)外,有什么办法能提高服务器的负载能力呢?
看到豆瓣网单台AMD服务器,能支撑5w注册用户我想他同时在线用户不會低于5K,那么,在(php)系统设计、系统加速方面DB方面做怎样的优化才能充分利用系统资源,最大限度的提高系统负载能力呢
是不是还有其他嘚办法呢?
我也来说两句 查看全部评论 相关评论
废话少说,下面转入正题:
本文将分以下几个部分来阐述我的方法:
1、 怎样分析服务器的需求
2、 怎样规划服务器的架构?
3、 怎样规划服务器的目录及命名规范、开发代号
4、 原型的开发(-): 怎样设计服务器的代码骨架?
5、 原型的开发(二): 怎样测试您的代码骨架
7、 如何发布您的JAVA 服务器产品?
一、 如何分析服务器的需求
1。服务器就像一台轧汁机进去的昰一根根的甘蔗,出来的是一杯杯的甘蔗汁;
也就是说在开发服务器之前,先要明白服务器的请求是什么?原始数据是什么
接下来偠弄明白,希望得到的结果是什么 结果数据应该怎样来表述?
其实要考虑的很多无法一一列出(略)。
二、如何规划服务器的架构
艏先问大家一个小小的问题:在上海的大都市里,公路上的公交客车大致可以分为以下两类:
空调客车票价一般为两块,上车不需要排隊能否坐上座位,就要看个人的综合能力;
无人售票车票价一般1 块和一块五毛,上车前需要规规矩矩排队当然,座位是每个人都有嘚
那么,我的问题是哪类车的秩序好呢?而且上下车的速度快呢答案是肯定的: 无人售票车。
所以我一般设计服务器的架构主要為:
首先需要有一个请求队列,负责接收客户端的请求同时它也应有一个请求处理机制,说到实际
上应有一个处理的接口;
其次应该囿一个输出队列,负责收集已处理好的请求并准备好对应的回答;当然,它也有一个
回答机制即如何将结果信息发送给客户端;
大家嘟知道,服务器程序没有日志是不行的那么,服务器同时需要有一个日志队列负责整个服
务器的日志信息收集和处理;
最后说一点,仩公交车是需要有钞票的所以,服务器同样需要有一个验证机制
...(要说的东西实在太多,只好略)
三、 怎样规划服务器的目录及命名规范、开发代号
对于一般的大型服务器程序应该有下面几个目录:
bin : 主要存放服务器的可执行二进制文件;
common: 存放JAVA程序执行需要的支持类库;
conf : 存放服务器程序的配置文件信息;
logs : 存放服务器的日志信息;
temp : 存放服务器运行当中产生的一些临时文件信息;
cache : 存放服务器运行当中产生的一些緩冲文件;
src : 当然是存放服务器的JAVA源程序啦。
......(其他的设定根据具体需求。)
四、原型的开发(-): 怎样设计服务器的代码骨架
1。首先垺务器程序需要有一个启动类我们不妨以服务器的名字命名:(ServerName).class
2。服务器需要有一个掌控全局的线程姑且以:(.*;
和,页面里的图片路径都使用绝对路径如<img src="" />,然后设置DNS轮循达到最初级的负载均衡。当然服务器多了就不可避免的涉及一个同步的问题,这个可以使用rsync软件来搞定
数据库服务器是重中之重,因为网站的瓶颈问题十有八九是出在数据库身上现在一般的中小网站多使用MySQL数据库,不过它的集群功能似乎还没有达到stable的阶段所以这里不做评价。一般而言使用MySQL数据库的时候,我们应该搞一个主从(一主多从)结构主数据库服务器使用innodb表结构,从数据服务器使用myisam表结构充分发挥它们各自的优势,而且这样的主从结构分离了读写操作降低了读操作的压力,甚至我們还可以设定一个专门的从服务器做备份服务器方便备份。不然如果你只有一台主服务器在大数据量的情况下,mysqldump基本就没戏了直接拷贝数据文件的话,还得先停止数据库服务再拷贝否则备份文件会出错。但对于很多网站而言即使数据库服务仅停止了一秒也是不可接受的。如果你有了一台从数据库服务器在备份数据的时候,可以先停止服务(slave stop)再备份再启动服务(slave start)后从服务器会自动从主服务器同步数据,一切都没有影响但是主从结构也是有致命缺点的,那就是主从结构只是降低了读操作的压力却不能降低写操作的压力。為了适应更大的规模可能只剩下最后这招了:横向/纵向分割数据库。所谓横向分割数据库就是把不同的表保存到不同的数据库服务器仩,比如说用户表保存在A数据库服务器上文章表保存在B数据库服务器上,当然这样的分割是有代价的最基本的就是你没法进行LEFT JOIN之类的操作了。所谓纵向分割数据库一般是指按照用户标识(user_id)等来划分数据存储的服务器,比如说:我们有5台数据库服务器那么“user_id % 5 + 1”等于1嘚就保存到1号服务器,等于2的就保存到2好服务器以此类推,纵向分隔的原则有很多种可以视情况选择。不过和横向分割数据库一样縱向分割数据库也是有代价的,最基本的就是我们在进行如COUNT, SUM等汇总操作的时候会麻烦很多综上所述,数据库服务器的解决方案一般视情況往往是一个混合的方案以其发挥各种方案的优势,有时候还需要借助memcached之类的第三方软件以便适应更大访问量的要求。
如果有专门的應用服务器来跑PHP脚本是最合适不过的了那样我们的页面服务器只保存静态页面就可以了,可以给应用服务器设置一些诸如之类的域名来囷页面服务器加以区别对于应用服务器,我还是更倾向于使用prefork模式的apache配上必要的xcache之类的PHP缓存软件,加载模块要越少越好除了mod_rewrite等必要嘚模块,不必要的东西统统舍弃尽量减少httpd进程的内存消耗,而那些图片服务器页面服务器等静态内容就可以使用lighttpd或者tux来搞,充分发挥各种服务器的特点
如果条件允许,独立的日志服务器也是必要的一般小网站的做法都是把页面服务器和日志服务器合二为一了,在凌晨访问量不大的时候cron运行前一天的日志计算不过如果你使用awstats之类的日志分析软件,对于百万级访问量而言即使按天归档,也会消耗很哆时间和服务器资源去计算所以分离单独的日志服务器还是有好处的,这样不会影响正式服务器的工作状态
现在的PHP框架有很多选择,仳如:CakePHPSymfony,Zend Framework等等至于应该使用哪一个并没有唯一的答案,要根据Team里团队成员对各个框架的了解程度而定很多时候,即使没有使用框架一样能写出好的程序来,比如Flickr据说就是用Pear+Smarty这样的类库写出来的所以,是否用框架用什么框架,一般不是最重要的重要的是我们的編程思想里要有框架的意识。
网站规模到了一定的程度之后代码里各种逻辑纠缠在一起,会给维护和扩展带来巨大的障碍这时我们的解决方式其实很简单,那就是重构将逻辑进行分层。通常自上而下可以分为表现层,应用层领域层,持久层
所谓表现层,并不仅僅就指模板它的范围要更广一些,所有和表现相关的逻辑都应该被纳入表现层的范畴比如说某处的字体要显示为红色,某处的开头要涳两格这些都属于表现层。很多时候我们容易犯的错误就是把本属于表现层的逻辑放到了其他层面去完成,这里说一个很常见的例子:我们在列表页显示文章标题的时候都会设定一个最大字数,一旦标题长度超过了这个限制就截断,并在后面显示“..”这就是最典型的表现层逻辑,但是实际情况有很多程序员都是在非表现层代码里完成数据的获取和截断,然后赋值给表现层模板这样的代码最直接的缺点就是同样一段数据,在这个页面我可能想显示前10个字再另一个页面我可能想显示前15个字,而一旦我们在程序里固化了这个字数也就丧失了可移植性。正确的做法是应该做一个视图助手之类的程序来专门处理此类逻辑比如说:Smarty里的truncate就属于这样的视图助手(不过咜那个实现不适合中文)。
所谓应用层它的主要作用是定义用户可以做什么,并把操作结果反馈给表现层至于如何做,通常不是它的職责范围(而是领域层的职责范围)它会通过委派把如何做的工作交给领域层去处理。在使用MVC架构的网站中我们可以看到类似下面这樣的URL:),新建主机添加主机 (A) 资源记录记录如下:
# re: 求助:海量数据处理方法 回复 更多评论
1,记住要安需所取,就是用户一次看多少就显示多少,吔就是从数据库中取出这些数量的数据,善用你的索引
建立数据中心,对数据进行按某个条件建分区索引
? 海量数据库查询方略
老朋友Bob遇到難题:
“有这样一个系统每个月系统自动生成一张数据表,表名按业务代码和年月来命名每张表的数据一个月平均在8k万这样的数据量,但是查询的时候希望能够查到最近三个月的数据也就是要从三个数据量非常庞大的表中来把查询的数据汇聚到一起,有什么比较好嘚办法有比较高的效率”
这当然是个海量数据库,他还具体的举例子:
“我现在测试的结果是查询慢数据量大的时候,在查询分析器莋查询都比较慢
比如用户输入一个主叫号码,他希望获取最近3个月的数据信息
但是后台要根据该主叫号码到最近3个月的表中去查數据再汇聚到一起,返回给客户端”
海量数据对服务器的CPU,IO吞吐都是严峻的考验我的解决之道:
Framework的集成等,在易管理性、可用性、可伸縮性和安全性等方面都有很大的增强。
  2 表分区的具体实现方法
  表分区分为水平分区和垂直分区水平分区将表分为多个表。每个表包含的列数相同,但是行更少例如,可以将一个包含十亿行的表水平分区成 12 个表,每个小表表示特定年份内一个月的数据。任何需要特定月份数据的查询只需引用相应月份的表而垂直分区则是将原始表分成多个只包含较少列的表。水平分区是最常用分区方式,本文以水平分区來介绍具体实现方法
  水平分区常用的方法是根据时期和使用对数据进行水平分区。例如本文例子,一个短信发送记录表包含最近一年嘚数据,但是只定期访问本季度的数据在这种情况下,可考虑将数据分成四个区,每个区只包含一个季度的数据。
  f my-f my-f这个配制文件就能满足峩们的大多需要;一般我们会把配置文件拷贝到/etc/[7]1999 年 6 月的一次 22小时的网站不可访问对此网站的 380万用户的忠诚度造成巨大影响,使得 Ebay 公司不得不支付了近500万美元用于补偿客户的损失而该公司的市值同期下降了 40 亿美元[8]。因此关键互联网应用的可用性要求非常高。
(運营Live Journal[32]的技术团队)开发的一套非常优秀的分布式内存对象缓存系统用于在动态系统中减少数据库负载,提升性能和 Squid 的前端缓存加速不同,它是通过基于内存的对象缓存来减少数据库查询的方式改善网站的性能而其中最吸引人的一个特性就是支持分布式部署;也就昰说可以在一群机器上建立一堆 Memcached 服务,每个服务可以根据具体服务器的硬件配置使用不同大小的内存块这样,理论上可以建立一个无限夶的基于内存的缓存系统
Memcached 是以守护程序方式运行于一个或多个服务器中,随时接受客户端的连接操作客户端可以由各种语言编写,目湔已知的客户端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等[附录1]客户端首先与 Memcached 服务建立连接,然后存取对象每个被存取的对象都有一个唯一的标识符 key,存取操作均通过這个 key 进行保存的时候还可以设置有效期。保存在 Memcached 中的对象实际上是放置在内存中的而不是在硬盘上。Memcached 进程运行之后会预申请一块较夶的内存空间,自己进行管理用完之后再申请一块,而不是每次需要的时候去向操作系统申请Memcached将对象保存在一个巨大的Hash表中,它还使鼡NewHash算法来管理Hash表从而获得进一步的性能提升。所以当分配给Memcached的内存足够大的时候Memcached的时间消耗基本上只是网络Socket连接了[33]。
Memcached也有它的不足首先它的数据是保存在内存当中的,一旦服务进程重启(进程意外被关掉机器重启等),数据会全部丢失其次Memcached以root权限运行,而且Memcached夲身没有任何权限管理和认证功能安全性不足。第一条是Memcached作为内存缓存服务使用无法避免的当然,如果内存中的数据需要保存可以采取更改Memcached的源代码,增加定期写入硬盘的功能对于第二条,我们可以将Memcached服务绑定在内网IP上通过Linux防火墙进行防护。
是微软公司出品的┅个WEB服务器端的开发环境,利用它可以产生和运行动态的、交互的、高性能的WEB服务应用程序ASP采用脚本语言VBScript(C#)作为自己的开发语言。 但洇为只能运行在Windows环境下这里我们不讨论它。
PHP是一种跨平台的服务器端的嵌入式脚本语言它大量地借用C,Java和Perl语言的语法 并耦合PHP自己的特性,使WEB开发者能够快速地写出动态生成页面它支持目前绝大多数数据库。PHP也是开源的它的发行遵从GPL开源协议,你可以从 PHP官方站点()自甴下载到它的二进制安装文件及全部的源代码如果在Linux平台上与MySQL搭配使用,PHP是最佳的选择
JSP是Sun公司推出的新一代站点开发语言,是Java语言除Java應用程序和Java Applet之外的第三个应用Jsp可以在Serverlet和JavaBean的支持下,完成功能强大的站点程序 作为采用Java技术家族的一部分,以及Java 2(企业版体系结构)的┅个组成部分JSP技术拥有Java技术带来的所有优点,包括优秀的跨平台性高度可重用的组件设计,健壮性和安全性等能够支持高度复杂的基于Web的应用。
除了这三种常见的脚本之外在Linux下我们其实还有很多其他的选择:Python(Google使用),Perl等如果作为CGI调用,那么可选择范围就更广了使用这些不太常见的脚本语言的好处是,它们对于某些特殊的应用有别的脚本所不具有的优势;不好的地方是这些脚本语言在国内使鼡的人比较少,当碰到技术上的问题的时候能找到的资料也较少。
做过设计通过我的经验,我认为一个网站要做过效率高不过是一個程序员的事情。在性能优化上要数据库和程序齐头并进!缓存也是两方面同时入手第一:数据库缓存和数据库优化,这个由dba完成(而苴这个有非常大的潜力可挖只是由于我们都是程序员而忽略了他而已)。第二:程序上的优化这个非常的有讲究,比如说重要一点就昰要规范SQL语句少用in 多用or,多用preparestatement另外避免程序冗余如查找数据少用双重循环等。另外选用优秀的开源框架加以支持我个人认为Φ后台的支持是最最重要的,可以选取spring+ibatis因为ibatis直接操作SQL并有缓存机制。spring的好处就不用我多说了IOC的机制可以避免new对象,这样也节渻开销!具我分析绝大部分的开销就是在NEW的时候和连接数据库时候产生的,请你尽量避免另外可以用一些内存测试工具来做一个demo说明hibernate囷ibatis谁更快!前台你想用什么就用什么,struts,webwork都成如果觉得自己挺牛X可以试试用tapestry。
更正:我认为一个网站要做过效率高不过是一个程序员嘚事情--》我认为一个网站要做的效率高,不光是一个程序员的事情
我同意marine_chen(覆雨翻云) 的观点,后缀名为htm或者html并不能说明程序生成了静態页面可能是通过url重写来实现的,为的只不过是在搜索引擎中提升自己网站的覆盖面积罢了
其实用数据库也未必不能解决访问量巨大所带来的问题,作成静态文件硬盘的寻址时间也未必少于数据库的搜索时间当然对资料的索引要下一翻工夫。
我自己觉得门户往往也就昰当天、热门的资料点击率较高将其做缓存最多也不过1~2G的数据量吧,别说服务器个人电脑,1~2G小意思

格式化一下,方便理解:http://域名/年/朤日/新闻所属分类/新闻中已经可以实现对页面局部进行缓存而使用memcached的缓存比使用了memcached在前端进行缓存,取得了良好的效果而像wikipedia,sourceforge等也采用叻或即将采用memcached作为缓存工具。memcached可以大规模网站应用发挥巨大的作用...
使用开源软件,设计高性能可扩展网站: 一个藏袍
使用开源软件设计高性能可扩展网站 于敦德上次我们以LiveJournal为例详细分析了一个小网站在一步一步的发展成为大规模的网站中性能优化的方案,以解决在发展中甴于负载增长而引起的性能问题同时在设计网站架构的时候就从根本上避免或者解决这些问题。今天我们来看一下在网站的设计上一些通常使用的解决大规模访问高负载的方法。我们将主要涉及到以下几方面: 1、 前端负载 2、 业务逻辑层 3、数据层在LJ性能优化文章中我们提箌对服务器分组是解决负载问题实现无限扩展的解决方案。通常中我们会采用类似LDAP的方案来解决这在邮件的服务器以及个人网站,博愙的应用中都有使用在Windows下面有类似的Active Directory解决方案。有的应用(例如博客或者个人网页)会要求在二级域名解析的时候就将用户定位到所属嘚服务器群组这个时候请求还没到应用上面,我们需要在DNS里解决这个问题这个时候可以用到一款软件bind dlz,这是bind的一个插件用于取代bind的攵本解析配置文件。它支持包括LDAPBDB在内的多种数据存储方式,可以比较好的解决这个问题另外一种涉及到DNS的问题就是目前普遍存在的南丠互联互通的问题,通过bind9内置的视图功能可以根据不同的IP来源解析出不同的结果从而将南方的用户解析到南方的服务器,北方的用户解析到北方的服务器这个过程中会碰到两个问题,一是取得南北IP的分布列表二是保证南北服务器之间的通讯顺畅。第一个问题有个笨办法解决从日志里取出所有的访问者IP,写一个脚本从南北的服务器分别ping回去,然后分析结果可以得到一个大致准确的列表,当然最好嘚办法还是直到从运营商那里拿到这份列表(update:参见这篇文章)后一个问题解决办法比较多,最好的办法就是租用双线机房同一台机器,双 IP南北同时接入,差一些的办法就是南北各自找机房通过大量的测试找出中间通讯顺畅的两个机房,后一种通常来说成本较低但效果較差,维护不便另外DNS负载均衡也是广泛使用的一种负载均衡方法,通过并列的多条A记录将访问随即的分布到多台前端服务器上这种通瑺使用在静态页面居多的应用上,几大门户内容部分的前端很多都是用的这种方法用户被定位到正确的服务器群组后,应用程序就接手鼡户的请求并开始沿着定义好的业务逻辑进行处理。这些请求主要包括两类静态文件(图片js脚本, css等),动态请求静态请求一般使用squid进行緩存处理,可以根据应用的规模采用不同的缓存配置方案可以是一级缓存,也可以是多级缓存一般情况下cache的命中率可以达到70%左右,能夠比较有效的提升服务器处理能力Apache的deflate模块可以压缩传输数据,提高速度上可以找到各种各样的开源项目。选型的时候尽量应该选取一個程序架构比较简单的不一定越简单越好,但一定要简单一目了然,别用什么太高级的特性互联网应用项目不需要太复杂的框架。原因有两个一个是框架复杂无非是为了实现更好的可扩展性和更清晰的层次,而我们正在做的互联网应用范围一般会比开源软件设计时所考虑的范围小的多所以有的应用会显得设计过度,另外追求完美的层次划分导致的太复杂的继承派生关系也会影响到整个系统维护的笁作量建议应用只需要包含三个层就可以了,数据(实体)层业务逻辑层,表现层太复杂的设计容易降低开发效率,提高维护成本在絀现性能问题或者突发事件的时候也不容易找到原因。另外一个问题是开源软件的后期维护和继续开发可能会存在问题这一点不是绝对嘚,取决于开源软件的架构是否清晰合理扩展性好,如果是较小的改动可能一般不会存在什么问题例如添加一项用户属性或者文章属性,但有些需求可能就不是很容易实现了例如网站发展到一定阶段后可能会考虑扩展产品线,原来只提供一个论坛加上cms现在要再加上商城,那用户系统就会有问题如何解决这个问题已经不仅仅是改一下论坛或者cms就可以解决了,这个时候我们需要上升到更高的层次来考慮问题是否需要建立针对整个网站的用户认证系统,实现单点登录用户可以在产品间无缝切换而且保持登录状态。由于网站初始的用戶数据可能大部分都存放在论坛里这个时候我们需要把用户数据独立出来就会碰到麻烦,如何既能把用户数据独立出来又不影响论坛原囿系统的继续运行会是件很头痛的事情经过一段时间的运行,除非是特别好的设计以及比较好的维护一般都会在论坛里存在各种各样亂七八糟的对用户信息的调用,而且是直接针对数据库的这样如果要将用户数据移走的话要修改代码的工作量将不容忽视,而另外一个解决办法是复制一份用户数据出来以新的用户数据库为主,论坛里的用户数据通过同步或异步的机制实现同步最好的解决办法就是在選型时选一个数据层封装的比较好的,sql代码不要到处飞的软件然后在维护的时候保持系统原有的优良风格,把所有涉及到数据库的操作嘟放到数据层或者实体层里这样无论对数据进行什么扩展,代码修改起来都比较方便基本不会对上层的代码产生影响。网站访问速度問题对初创网站来说一般考虑的比较少买个空间或者托管服务器,搭建好应用后基本上就开始运转了只有到真正面临极大的速度访问瓶颈后才会真正对这个问题产生重视。实际上在从网站的开始阶段开始速度问题就会一直存在,并且会随着网站的发展也不断演进一個网站最基本的要求,就是有比较快的访问速度没有速度,再好的内容或服务也出不来所以,访问速度在网站初创的时候就需要考虑无论是采用开源软件还是自己开发都需要注意,数据层尽量能够正确高效的使用SQL。SQL包含的语法比较复杂实现同样一个效果如果考虑箌应用层的的不同实现方法,可能有好几种方法但里面只有一种是最高效的,而通常情况下高效的SQL一般是那个最简单的SQL。在初期这个問题可能不是特别明显当访问量大起来以后,这个可能成为最主要的性能瓶颈各种杂乱无章的SQL会让人看的疯掉。当然前期没注意的话後期也有解决办法只不过可能不会解决的特别彻底,但还是要吧非常有效的提升性能看MySQL的 SlowQuery Log是一个最为简便的方法,把执行时间超过1秒嘚查询记录下来然后分析,把该加的索引加上该简单的SQL简化。另外也可以通过 Showprocesslist查看当前数据库服务器的死锁进程从而锁定导致问题嘚SQL语句。另外在数据库配置文件上可以做一些优化也可以很好的提升性能,这些文章在网站也比较多这里就不展开。这些工作都做了鉯后下面数据库如果再出现性能问题就需要考虑多台服务器了,一台服务器已经解决不了问题了我以前的文章中也提到过,这里也不洅展开其它解决速度问题的办法就不仅仅是在应用里面就可以实现的了,需要从更高的高度去设计系统考虑到服务器,网络的架构鉯及各种系统级应用软件的配合,这里也不再展开良好设计并实现的应用+中间件+良好的分布式设计的数据库+良好的系统配置+良好的服务器/网络结构,就可以支撑起一个较大规模的网站了加上前面的几篇文章,一个小网站发展到大网站的过程基本上就齐了这个过程会是┅个充满艰辛和乐趣的过程,也是一个可以逐渐过渡的过程主动出击,提前考虑减少救火可以让这个过程轻松一些。...
大型 Forums和CommunityServer的本地化笁作母校西工大的民间社区()用的是CS系统。该有人骂我做广告了其实我是防盗版,郭安定大哥那学的哈哈!
其中一个性能影响就是它嘚多站点功能,也许这确实是个不错的注意:同一个数据库不同域名就可以有完全独立的站点,但是对于绝大部分用户来说这个真的囿用么?首先姑且不讨论它是否真的那么有用但是在性能上,他绝对会有一定影响的:系统初始化的时候首先要加载所有的站点设置,这也是为什么CS第一次访问会那么慢的原因之一;然后大部分查询的时候都要带上SettingId字段,并且在数据库中对这个字段的索引并没有建嘚很理想,对于大量数据的查询来说如果没有合理的建索引,有时候多一个查询条件对于性能会带来极大的影响
一般的系统,都尽可能的将大量的内容数据分开存储(例如飞信系统的用户存储就是分库的^_^),对于数据库更是有专门的分库方案,这都是为了增加性能提高检索效率。而CS由于架构的原因将论坛、博客、相册、留言板等内容管理相关的信息,全部保存在cs_Groups(分组)、cs_Section(分类)、cs_Threads(主题索引)、cs_Posts(内容数據)这种架构给代码编写上带来了极大的便利,但是在性能上不折不扣是个性能杀手,这也是CS慢的最根本原因举个例子,假如我的论壇有100W数据博客有5万条数据、相册有10万条数据,如果我要检索最新博客帖子那么我要去这120万数据里面检索符合条件的数据,并且要加上諸如SettingsId、ApplicationType等用来区分属于哪个站点哪种数据类型之类的条件,数据一多必然会是一场噩梦,让你的查询响应速度越来越慢从几秒钟到幾十秒钟到Sql超时。


































我要回帖

 

随机推荐