Java9新功能之HTTP2和REPL

本文转自:云栖社区云

【摘要】对Java 9的炒作将不再局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正作为Java增强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。 在这篇文章中,我们将重点关注一些或将在Java 9整个生命周期中,对开发者的工作生…

对Java 9的炒作将不再局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正作为Java增强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。

在这篇文章中,我们将重点关注一些或将在Java 9整个生命周期中,对开发者的工作生活影响最大的JEP,包括新的HTTP/2支持和JShell REPL(读取-求值-打印-循环),后者带来了基于shell的交互式Java开发环境和探索性开发API。

HTTP/2

HTTP/2标准是HTTP协议的最新版本。当前版本HTTP/1.1始于1999年,存在着非常严重的问题,包括:

对头阻塞

在HTTP/1.1中,响应接收的顺序和请求发送的顺序相同。这意味着,例如,当查看一个包含许多小图像的大HTML页面时,图像资源将不得不在HTML页面资源之后排队,在浏览器完全加载完HTML页面之前,图像资源无法被发送。这就是“对头阻塞”,会导致许多潜在的页面渲染问题。

在HTTP/2中,响应数据可以按块(chunk)传输,甚至可以交叉传输,因此真正实现了请求和响应的多路复用。

一个站点的连接数限制

在HTTP/1.1标准中有这样的描述:“一个单用户的客户端不能与任何服务器保持2个以上的连接”。这个限制和对头阻塞问题一起,严重限制了页面的性能。

HTTP/2打破这种限制并认为连接是持久的,只有当用户跳转后或者发生技术性故障事件时,连接才会关闭。对多路复用的使用将有助于降低页面性能瓶颈。

HTTP控制头的开销

当前的HTTP版本使用简单的、基于文本的HTTP头信息来控制通信。这样做的优点是非常简单且易于理解,调试也很简单,只需通过连接指定端口并输入一些文本。然而,使用基于文本的协议会让小的响应包不成比例地膨胀。此外,大量的HTTP响应几乎没有或者根本没有有效负载(比如,HEAD请求只是要确定资源是否发生变化)。为实际上只包含最后修改时间的响应,使用完全基于文本的头信息(大约有700个字节,在HTTP1.1中,它们不能被压缩,尽管很容易做到)是当前HTTP标准中,不可思议的浪费。

另一个思路是对HTTP头信息使用二进制编码。这种方式能够极大地提高较小请求的速度且占用的网络带宽非常小。这正是HTTP/2已经选择的方法,虽然以协议精神制定标准应该选择基于文本的协议,但是二进制的效率有令人信服的理由,让我们这样做。

HTTP/2带来的期望

HTTP/2标准是由IETF HTTP工作组创建的,该组织由来自Mozilla、Google、 Microsoft、Apple,以及其他公司的代表和工程师组成,由来自CDN领军公司Akamai的高级工程师Mark Nottingham任主 席。因此,HTTP/2是一个为优化大型、高流量的网站而生的版本,它在实现简单、易于调试的基础上,确保了性能和网络带宽消耗。

该组织主 席总结了一些HTTP/2的关键属性:

相同的HTTP API成本更低的请求网络和服务器端友好缓存推送思维革命更多加密方式

带给Java的意义

自从1.0版本开始,Java就支持HTTP,但是多数代码出自完全不同的时代。例如,Java对HTTP的支持是围绕相对协议无关的框架(URL类)设计的,因此在网站成为主导地位的90年代,这种实现显得很不清晰。

Java对HTTP的支持是基于当时最好的设计思想,但是时过境迁,最重要的是Java对HTTP原始的支持出来时,HTTPS还没有出现。因此,Java的API将HTTPS作为一种移花接木,导致了不能简化的复杂性。

在现代社会,HTTPS开始变得无所不在,让HTTP日渐成为落后的技术。甚至,美国政府现在都通过了完全迁到HTTPS-only的计划。

JDK内核对HTTP的支持已经无法跟上现实网络的发展步伐。实际上,甚至JDK8也只不过是交付了一个支持HTTP/1.0的客户端,然而,大多数的开发者早已转而使用第三方客户端库了,比如Apache的HttpComponents。

所有这一切意味着,对HTTP/2的支持将是Java未来十年的核心功能。这也让我们重新审视我们的固有思维,重新写一套API并提供重新来过的机会。HTTP/2将是未来数年内,每位开发者主要面对的API。

新的API不再坚持协议中立性,使开发者可以完全抛弃过去的使用方式。这套API只关注HTTP协议,但是要进一步理解的是HTTP/2并没有从根本上改变原有的语义。因此,这套API是HTTP协议独立的,同时提供了对新协议中帧和连接处理的支持。

在新的API中,一个简单的HTTP请求,可以这样创建和处理:

HttpResponse response = HttpRequest .create(new URI(“http://www.infoq.com”)) .body(noBody()) .GET().send(); int responseCode = response.responseCode(); String responseBody = response.body(asString()); System.out.println(responseBody);

这种符合流畅风格/建造者模式(fluent/builder)的API,与现存的遗留系统相比,对开发者来说,更具现代感和舒适感。

虽然当前的代码库只支持HTTP/1.1,但是已经包含了新的API。这使得在对HTTP/2支持完成对过程中,开发者可以实验性地使用和验证新的API。

相关代码已经进入OpenJDK沙箱仓库中,并很快登陆JDK 9的主干。到那个时候,新的API将开始自动构建到Oracle的二进制beta版本中。现在,对HTTP/2的支持已经可用,并将在未来数月内最终完成。

在此期间,你可以使用Mercurial迁出源代码,并根据AdoptOpenJDK构建指导编译你迁出地代码,这样你就可以实验性地使用新的API了。

第一批完成的功能之一是当前版本力不能及的异步API。这个功能让长期运行的请求,可以通过sendAsync()方法,切换到VM管理的后台线程中:

HttpRequest req = HttpRequest .create(new URI(“http://www.infoq.com”)) .body(noBody()) .GET(); CompletableFuture<HttpResponse> aResp = req.sendAsync(); Thread.sleep(10); if (!aResp.isDone()) { aResp.cancel(true); System.out.println(“Failed to reply quickly…”); return; } HttpResponse response = aResp.get();

相比HTTP/1.1的实现,新的API带给开发者最多的是方便性,因为HTTP/1.1没有提供对已经发送到服务器端的请求的取消机制,而HTTP/2可以让客户端向已经被服务器端处理的请求,发送取消命令。

JShell

很多语言都为探索性开发提供了交互式环境。在某些情况下(特别是Clojure和其他Lisp方言),交互式环境占据了开发者的大部分编码时间,甚至是全部。其他语言,比如Scala或者JRuby也广泛使用REPL。

当然,此前Java曾经推出过Beanshell脚本语言,但是它没有实现完全标准化,而且近年来,该项目已经处于不活跃状态。在Java 8(以及jjs REPL)中引入的Nashorn Java实现打开了更广泛地考虑REPL并将交互式开发成为可能的大门。

一项努力将现代REPL引入Java 9的工作,以JEP 222作为开始,收录在OpenJDK的Kulla项目中。Kulla这个名字来自古巴比伦神话,是建造之神。该项目的主旨是提供最近距离的“完整Java”体验。该项目没有引入新的非Java语义,并禁用了Java语言中对交互式开发没有用处的语义(比如上层的访问控制修改或同步的语义)。

与所有REPL一样,JShell提供了命令行,而不是类似IDE的体验。语句和表达式能够在执行状态上下文中,被立即求值,而不是非得打包到类中。方法也是自由浮动的,而不必属于某个特定的类。相反,JShell使用代码片断“snippets”来提供上层执行环境。

与HTTP/2 API相似,JShell已经在独立的项目开发,以免在快速发展的时期影响主干构建的稳定性。JShell预计在2015年8月期间合并到主干。

现在,开发者可以参考AdoptOpenJDK说明指导,从头构建Kulla(源代码可以从Mercurial地址获得)。

对于一些上手实验,最简单的可能是使用一个独立的试验jar。这些jar包是社区专为不想从头构建的开发者构建好的。

这些试验jar包可以从AdoptOpenJDK CloudBees的CI构建实例中获得。

要使用它们,你需要安装Java 9 beta版(或者OpenJDK 9的构建版本)。然后下载jar文件,重命名为kulla.jar,然后在命令行输入如下:

$ java -jar kulla.jar | Welcome to JShell — Version 0.610 | Type /help for help ->

这是REPL的标准界面,和往常一样,命令是从单个字符开始并最终发出的。

JShell有一个相当完整(但仍在发展)的帮助语法,可以通过如下命令轻松获得:

-> /help Type a Java language expression, statement, or declaration. Or type one of the following commands: /l or /list [all] — list the source you have typed /seteditor <executable> — set the external editor command to use /e or /edit <name or id> — edit a source entry referenced by name or id /d or /drop <name or id> — delete a source entry referenced by name or id /s or /save [all|history] <file> — save the source you have typed /o or /open <file> — open a file as source input /v or /vars — list the declared variables and their values /m or /methods — list the declared methods and their signatures /c or /classes — list the declared classes /x or /exit — exit the REPL /r or /reset — reset everything in the REPL /f or /feedback <level> — feedback information: off, concise, normal, verbose, default, or ? /p or /prompt — toggle display of a prompt /cp or /classpath <path> — add a path to the classpath /h or /history — history of what you have typed /setstart <file> — read file and set as the new start-up definitions /savestart <file> — save the default start-up definitions to the file /? or /help — this help message /! — re-run last snippet /<n> — re-run n-th snippet /-<n> — re-run n-th previous snippet Supported shortcuts include: — show possible completions for the current text Shift- — for current method or constructor invocation, show a synopsis of the method/constructor

JShell支持TAB键自动补全, 因此我们可以很容易找到println()或者其他我们想使用的方法:

-> System.out.print print( printf( println(

传统的表达式求值也很容易,但是相比其他动态类型语言,Java的静态类型特征会更严格一点。JShell会自动创建临时变量来保存表达式的值,并确保它们保持在上下文域内供以后使用:

-> 3 * (4 + 5) | Expression value is: 27 | assigned to temporary variable $1 of type int -> System.out.println($1); 27

我们还可以使用/list命令,查看到目前为止输入的所有源代码:

-> /list 9 : 3 * (4 + 5) 10 : System.out.println($1);

使用/vars命令显示所有的变量(包括显式定义的和临时的),以及他们当前持有的值:

-> String s = “Dydh da” | Added variable s of type String with initial value “Dydh da” -> /vars | int $1 = 27 | String s = “Dydh da”

除了支持简单的代码行,REPL还允许非常简单地创建类和其它用户定义的类型。例如,可以用如下短短一行来创建类(请注意,开始和结束括号是必需的):

-> class Pet {} | Added class Pet -> class Cat extends Pet {} | Added class Cat

JShell代码非常简洁、自由浮动的性质意味着我们可以非常简单地使用REPL来演示Java语言的功能。例如,让我们来看看著名的类型问题,即Java数组的协变问题:

-> Pet[] pets = new Pet[1] | Added variable pets of type Pet[] with initial value [LPet;@2be94b0f -> Cat[] cats = new Cat[1] | Added variable cats of type Cat[] with initial value [LCat;@3ac42916 -> pets = cats | Variable pets has been assigned the value [LCat;@3ac42916 -> pets[0] = new Pet() | java.lang.ArrayStoreException thrown: REPL.$REPL13$Pet | at (#20:1)

这样的功能使JShell成为一种伟大的教学或研究工具,而且最接近Scala REPL的体验。使用/classpath切换,可以加载额外的jar包,从而可以在REPL直接使用互动式探索性API。

参与

主要的IDE已开始提供支持JDK 9早期版本的构建——包括Netbeans和Eclipse Mars。[urlhttps://www.jetbrains.com/idea/download/?spm=5176.blog26632.yqblogcon1.14.tXFWPP=””]IntelliJ 14.1[/url]据称支持JDK9,但目前还不清楚对新的模块化JDK扩展的支持力度。

到目前为止,这些IDE还不支持HTTP/2和JShell,因为这些功能还没有登陆OpenJDK的主干,但是开发者应该很期望它们能够早日出现在标准的JDK beta版本中,并且有IDE插件可以紧随其后。这些API仍在开发中,项目的领导者正在积极寻求最终用户的使用和参与。

The JDK 9 Outreach programme is also underway to encourage developers to test their code and applications on JDK 9 before it arrives. HTTP/2 & JShell aren’t the only new features being worked on – other new JDK 9 functionality under development as JEPs includes

JDK 9的宣传计划也正在鼓励开发者测试他们的代码并在JDK 9上运行应用程序。正在开发的新功能不止包括HTTP/2和JShell—— 其他作为JEP,JDK 9正在开发的新功能还包括:

102 Process API的更新(Process API Updates)165 编译器控制(Compiler Control)227 Unicode 7.0245 验证虚拟机代码行标记参数(Validate JVM Command-Line Flag Arguments)248: G1作为默认的垃圾回收器(Make G1 the Default Garbage Collector)TLS的一系列更新(TLS Updates) (JEP 219, 244, 249)

目前正在审议(以及考虑应该放在哪个Java版本)的所有JEP的完整列表可以在这里找到。

Spring Data JPA 查询方法支持的关键字

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = 1?
Between findByStartDateBetween … where x.startDate between 1? and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> age) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

通过解析方法名创建查询

通过前面的例子,读者基本上对解析方法名创建查询的方式有了一个大致的了解,这也是 Spring Data JPA 吸引开发者的一个很重要的因素。该功能其实并非 Spring Data JPA 首创,而是源自一个开源的 JPA 框架 Hades,该框架的作者 Oliver Gierke 本身又是 Spring Data JPA 项目的 Leader,所以把 Hades 的优势引入到 Spring Data JPA 也就是顺理成章的了。

框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。

在创建查询时,我们通过在方法名中使用属性名称来表达,比如 findByUserAddressZip ()。框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,详细规则如下(此处假设该方法针对的域对象为 AccountInfo 类型):

  • 先判断 userAddressZip (根据 POJO 规范,首字母变为小写,下同)是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,继续第二步;
  • 从右往左截取第一个大写字母开头的字符串(此处为 Zip),然后检查剩下的字符串是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设 user 为 AccountInfo 的一个属性;
  • 接着处理剩下部分( AddressZip ),先判断 user 所对应的类型是否有 addressZip 属性,如果有,则表示该方法最终是根据 “AccountInfo.user.addressZip” 的取值进行查询;否则继续按照步骤 2 的规则从右往左截取,最终表示根据 “AccountInfo.user.address.zip” 的值进行查询。

可能会存在一种特殊情况,比如 AccountInfo 包含一个 user 的属性,也有一个 userAddress 属性,此时会存在混淆。读者可以明确在属性之间加上 “_” 以显式表达意图,比如 “findByUser_AddressZip()” 或者 “findByUserAddress_Zip()”。

在查询时,通常需要同时根据多个属性进行查询,且查询的条件也格式各样(大于某个值、在某个范围等等),Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下:

  • And — 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);
  • Or — 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);
  • Between — 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min);
  • LessThan — 等价于 SQL 中的 “<“,比如 findBySalaryLessThan(int max);
  • GreaterThan — 等价于 SQL 中的”>”,比如 findBySalaryGreaterThan(int min);
  • IsNull — 等价于 SQL 中的 “is null”,比如 findByUsernameIsNull();
  • IsNotNull — 等价于 SQL 中的 “is not null”,比如 findByUsernameIsNotNull();
  • NotNull — 与 IsNotNull 等价;
  • Like — 等价于 SQL 中的 “like”,比如 findByUsernameLike(String user);
  • NotLike — 等价于 SQL 中的 “not like”,比如 findByUsernameNotLike(String user);
  • OrderBy — 等价于 SQL 中的 “order by”,比如 findByUsernameOrderBySalaryAsc(String user);
  • Not — 等价于 SQL 中的 “! =”,比如 findByUsernameNot(String user);
  • In — 等价于 SQL 中的 “in”,比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
  • NotIn — 等价于 SQL 中的 “not in”,比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;

开发高效率 Git命令 Cherry-Pick 摘樱桃

在实际的项目开发中(使用Git版本控制),在所难免会遇到没有切换分支开发、需要在另一个分支修改bug然后合并到当前分支的情况。之前遇到这种第一反应就是将分支合并过去来解决问题。如果你那些提交当中也穿插了其他人的提交而且他们的提交不可以合并到另一个分支,那么使用分支的合并将明显变得困难。下面分享给大家一个非常好用Git的命令Cherry-Pick来处理这些情况,从而提高开发的效率。

git Cherry-Pick 命令可以选择某一个分支中的一个或几个commit(s)来进行操作。你可以理解merge的个性定制版本

多次使用时要按提交的顺序进行合并,不然会导致某些文件发生冲突。这也是 容易 踩的坑。

  1. 当你的需求还没有完成的时候,其他人应该切换到另一分支开发的时候,你可以先在当前分支继续开发完,然后再选择Cherry-Pick命令合并过去就可以了。
  2. 当你需要将某个人的commits合并到另一开分时候,可以选择Cherry-Pick命令。(在实际的项目开发中,在所难免有人会提交错分支)
  3. 当你切换到某条分支修改Bug后,需要将修改提交合并另一分支,可以选择Cherry-Pick命令。

Go 1.8 正式发布,编译时间比 Go 1.7 提高约 15%

今天Go 团队很高兴地宣布Go 1.8发布了。现已提供下载。整个标准库有了显著的性能提升和变化。该版本主要的更新内容如下:

  • Go 1.7中为64位x86引入的编译器后端现在用于所有体系结构,这些体系结构将会有显著的性能改进。例如,我们的基准程序所需的CPU时间在32位ARM系统上减少了20-30%。在此版本中,64位x86系统还有一些性能改进,编译器和链接器更快了,编译时间应该比Go 1.7提高约15%。但是在这一领域还有很长的路要走:我们希望在未来版本中实现更快的编译速度。
  • 垃圾收集暂停时间明显更短,通常在100微秒以下,有时候甚至低至10微秒。
  • HTTP服务器添加对 HTTP/2 Push的支持,允许服务器抢先发送响应到客户端。这对于通过消除往返行程来最小化网络延迟非常有用。HTTP服务器现在还支持正常关机了,允许服务器通过在服务所有正在运行的请求之后关闭,而最小化停机时间。
  • 上下文(添加到Go 1.7中的标准库)提供了取消和超时机制。Go 1.8在标准库中添加了更多对上下文的支持,包括数据库/ sql和net包以及net / http包中的Server.Shutdown。
  • 现在使用新添加的Slice函数在排序包中对切片进行排序更简单。例如,要通过“名称”字段对结构体片段进行排序:
sort.Slice(s,func(i,j intbool {return s [i] .Name <s [j] .Name})

更多新版本的添加、改进和修复内容,以及上面列出的改进的详细信息请查看Go 1.8发行说明。

为了庆祝发布,世界各地的Go用户组都在本周举办发布会,这已经成为Go社区的一个传统,所以如果你错过了这一次,那么请在 GO 1.9 发布前留意。

via:https://blog.golang.org/go1.8

Java 9进入第一轮问题修复阶段

来源:infoq.com  作者:Abraham Marín Pérez ,译者 尚剑

Java 9功能特性正式完成,这意味着第一个问题修复阶段已经开始。HTTP/2客户端没有在截止日期前完成,现已降级为孵化器功能。由于现在的目标是在7月准备好可发布的Java 9,所以目前不太可能添加任何新的JEP。

InfoQ此前的报道中提到,第一轮问题修复阶段,或者说“启动Rampdown”阶段的目的是解决P1至P3级别的问题。其中,根据Java平台的首席架构师Mark Reinhold提出的流程,问题修复应该优先考虑Java 9中的新问题,而不是影响Java 9但已经存在于Java 8或更早版本Java中的问题,之所以这么做,可能是因为相对于新的问题,公众更容易忍受已经存在的问题。Reinhold提供的缺陷列表显式地过滤掉了只与文档、演示和测试相关的缺陷,这似乎表明了他们对用户体验的关注。在撰写本文时,该列表中有194个缺陷。

这一阶段还包括一个规定,如果有正当理由,可以留下一些未解决的P1至P2级别的问题。希望推迟其解决方案的问题所有者必须在错误报告中指出其请求的原因(复杂性、风险、时间不足等),然后相关区域负责人、小组负责人和JDK 9 Project 负责人将分析这些数据并同意或拒绝延期。在写这篇文章的时候,这个列表中暂时还没有推迟请求,但以后可能会出现。

这个Rampdown阶段在特定的扩展功能完成阶段之后进行,以给予一些JEP完成的时间。HTTP/2客户端以及增强弃用、jlink、和新的HotSpot编译系统都是在2016年7月出现风险的功能。其中,HTTP/2 Client是唯一一个没有最终做出来的功能,转而成为孵化器功能。这意味着,尽管HTTP/2 Client将包含在Java 9中,但默认情况下不可访问:该功能将被打包在前缀为jdk.incubator.的模块下,开发人员必须显式地使用–add-mod标记才能访问该功能。然而,如果开发人员选择这样做,他们将需要考虑到孵化器功能不是标准API的一部分,因此该功能可能随时被修改。

阅读英文原文Java 9 Enters First Bug Fixing Round

大型网站架构演化

原创地址:https://my.oschina.net/u/3039671/blog/836750

1. 最初始的网站架构

就像我们在自己电脑上搭建了一个论坛的网站,应用程序(例如Apache服务器)、数据库等都部署在我们自己的电脑上的。就可以正常运行了。

2. 应用服务和数据服务分离

我们的论坛越来越受欢迎,用户越来越多,论坛也十分越活。但是面临的问题是数据库中的信息越来越多,存储不够了。这个时候我们又多弄了几台服务器,应用程序(Apache服务器)、数据库和保存用户上传的文件(图片)单独部署在不同的服务器上。

应用服务器处理大量的业务逻辑,所以需要更好的CPU

数据库服务器需要完成数据的快速查询,所以需要更大的硬盘和内存

文件服务器保存用户上传的图片等文件,所以需要更大的硬盘

3. 使用缓存改善网站性能

我们的论坛用户继续快速增涨,我们发现访问速度越来越慢,原因就是很多请求都要访问数据库(例如,读取用户的个人信息,打个不恰当的比喻,每次进入一个话题,该话题中的每一个发言用户的信息都要从数据库中读取)。这个时候如果我们能缓存这些用户信息,每次从缓存中读取,这样对数据库的压力会大大降低,并且读取的性能也提升了很多。

4. 使用应用服务器集群改善网站的并发处理能力。

使用缓存后,又出现问题了,在论坛使用高峰的时候,单一应用服务器处理请求连接有限,这个时候就需要部署应用服务器集群,然后在使用一个负载均衡服务器(例如Nginx,apache Server)。

5. 数据库读写分离

用户继续增加,使用缓存后,虽然大部分读的操作都不会直接访问数据库,但是还是有一些读操作(缓存未命中,缓存过期)和全部的写操作还是必须操作数据库。当用户达到一定规模,数据库又成了系统的性能瓶颈。

在原来单一数据库的模式上,设置一个主数据库和从数据库,写操作的时候写入主数据库,然后从主数据库同步到从数据库中。读操作就在从数据库中读。当然我们需要一个数据访问的模块来处理这些逻辑

6. 使用反向代理和CDN加速网站响应

论坛用户反应,打开你们的论坛速度太慢了,再不改善我就不用了。

原因也很简单,一个访问请求中,也许存在很多静态资源(CSS,图片)等,又或者用户的使用的联通,我们的服务器在电信。适应反向代理和CDN技术可以大大改善用户请求的响应速度

7. 使用分布式数据库和分布式文件系统

虽然数据库进行读写分离以后,但是在我们论坛疯狂增涨下,任何强大的单一服务器的性能都是有限的,只有使用分布式系统,才能在业务不断增涨进行横向扩展。这个是我们最后手段了,使用之前应该先考虑能否根据业务不同来拆分数据库。例如我们论坛的包括了不同主题(汽车、房子、以及你懂的话题),如果按照这些主题来区分数据库,也是好的选择。(注意这个虽然也是要使用多个数据库,但和分布式数据库的概念是有很大区别的)

8. 使用NoSql和搜索引擎

论坛中,要搜索一些帖子,如果每次进行数据库查询,在数据量十分大的情况,显然是不可取的。还有就是对数据存储的要求,需要使用NoSql。

9. 业务拆分

为了以后以后的发展,我们的业务需要扩展,我们需要增加即时通讯的业务(类似微信),知识问答(类似知乎)。但是这些业务是分开开发的,如果和原有的论坛业务耦合在一起,在代码发布的时候,就会十分麻烦。这个时候,根据不同的业务,分别进行部署和发布。

10. 分布式服务

虽然按照业务进行拆分以后,虽然不同业务之间的管理隔离开来,但是问题又出现了,但我们部署了上万台服务器的时候,每个服务器都保持有与数据库的连接,这样会导致数据集的连接资源不够。而且还有个问题就是对一些基础功能每个业务之间有重复开发的问题。

所以,我们把一些基础业务功能提取出来,做成基础服务独立部署(登录服务、用户信息管理,日志功能等)。这样上层只用关系自己的业务逻辑,调用底层统一的基础服务。

Linux Kernel 3.18 LTS 终止支持 请升至 4.9 或 4.4 分支

在发布最后一个维护版本更新之后,Linux 稳定版内核维护者 Greg Kroah-Hartman 宣布 Linux Kernel 3.18 分支走到了生命的尽头。而 3.18 LTS 原计划于今年 1 月终止支持。

Linux Kernel 3.18.48 LTS 是该分支的最后版本,根据短日志显示该版本共计调整了 50 个文件,插入 159 处删除 351 处。升级网络堆栈的同时改善了 Bluetooth, Bridge, IPv4, IPv6, CAIF 和 Netfilter,并升级了 USB, SCSI, ATA, media, GPU, ATM, HID, MTD, SPI 和网络(有线和无线)驱动。新发布的 3.18.48 还修正了 3.18.47 和 3.18.27 中的一个 bug。

LTS 版通常会提供大约两年的支持时间,3.18 是在 2014 年 12 月发布的。如果你当前还在使用该内核分支,那么现在你应该升级至更新的 LTS 版本,例如 Linux Kernel 4.9 或者 4.4,这两个版本要比 3.18 更加的安全和强悍。不过 Linux Kernel 3.18 主要被 Google 和其他供应商应用于一些 Android 设备、部分 Chromebook 上,Kroah-Hartman 建议用户拒绝购买仍然使用 3.18 LTS 的供应商的设备。如果无法升级内核开发者也提供了一些建议。

“如果你在使用 Linux Kernel 3.18 中有困难,那么我可以给你提供一些帮助。首先,你需要和硬件供应商反馈,要求尽快升级否则不再购买他们的产品。如果供应商还是不升级,请致信我们让我们出面和厂商进行沟通,出现这个问题的肯定不止你一个人。”

来源:http://www.oschina.net/news/81799/linux-kernel-3-18-48-released