java处理高并发高负载类网站的优化方法.docx
《java处理高并发高负载类网站的优化方法.docx》由会员分享,可在线阅读,更多相关《java处理高并发高负载类网站的优化方法.docx(13页珍藏版)》请在冰豆网上搜索。
java处理高并发高负载类网站的优化方法
java处理高并发高负载类网站的优化方法
一:
高并发高负载类网站关注点之数据库
没错,首先是数据库,这是大多数应用所面临的首个SPOF。
尤其是Web2.0的应用,数据库的响应是首先要解决的。
一般来说MySQL是最常用的,可能最初是一个mysql主机,当数据增加到100万以上,那么,MySQL的效能急剧下降。
常用的优化措施是M-S(主-从)方式进行同步复制,将查询和操作和分别在不同的服务器上进行操作。
我推荐的是M-M-Slaves方式,2个主Mysql,多个Slaves,需要注意的是,虽然有2个Master,但是同时只有1个是Active,我们可以在一定时候切换。
之所以用2个M,是保证M不会又成为系统的SPOF。
Slaves可以进一步负载均衡,可以结合LVS,从而将select操作适当的平衡到不同的slaves上。
以上架构可以抗衡到一定量的负载,但是随着用户进一步增加,你的用户表数据超过1千万,这时那个M变成了SPOF。
你不能任意扩充Slaves,否则复制同步的开销将直线上升,怎么办?
我的方法是表分区,从业务层面上进行分区。
最简单的,以用户数据为例。
根据一定的切分方式,比如id,切分到不同的数据库集群去。
全局数据库用于meta数据的查询。
缺点是每次查询,会增加一次,比如你要查一个用户nightsailer,你首先要到全局数据库群找到nightsailer对应的clusterid,然后再到指定的cluster找到nightsailer的实际数据。
每个cluster可以用m-m方式,或者m-m-slaves方式。
这是一个可以扩展的结构,随着负载的增加,你可以简单的增加新的mysqlcluster进去。
需要注意的是:
1、禁用全部auto_increment的字段
2、id需要采用通用的算法集中分配
3、要具有比较好的方法来监控mysql主机的负载和服务的运行状态。
如果你有30台以上的mysql数据库在跑就明白我的意思了。
4、不要使用持久性链接(不要用pconnect),相反,使用sqlrelay这种第三方的数据库链接池,或者干脆自己做,因为php4中mysql的链接池经常出问题。
二:
高并发高负载网站的系统架构之HTML静态化
其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。
但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。
除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化,有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。
同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求高并发。
网站HTML静态化解决方案
当一个Servlet资源请求到达WEB服务器之后我们会填充指定的JSP页面来响应请求:
HTTP请求---Web服务器---Servlet--业务逻辑处理--访问数据--填充JSP--响应请求
HTML静态化之后:
HTTP请求---Web服务器---Servlet--HTML--响应请求
静态访求如下
Servlet:
[java]viewplaincopyprint?
1.publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
2.throwsServletException,IOException{
3.if(request.getParameter("chapterId")!
=null){
4.StringchapterFileName="bookChapterRead_"+request.getParameter("chapterId")+".html";
5.StringchapterFilePath=getServletContext().getRealPath("/")+chapterFileName;
6.FilechapterFile=newFile(chapterFilePath);
7.if(chapterFile.exists()){response.sendRedirect(chapterFileName);return;}//如果有这个文件就告诉浏览器转向
8.INovelChapterBiznovelChapterBiz=newNovelChapterBizImpl();
9.NovelChapternovelChapter=novelChapterBiz.searchNovelChapterById(Integer.parseInt(request.getParameter("chapterId")));//章节信息
10.intlastPageId=novelChapterBiz.searchLastCHapterId(novelChapter.getNovelId().getId(),novelChapter.getId());
11.intnextPageId=novelChapterBiz.searchNextChapterId(novelChapter.getNovelId().getId(),novelChapter.getId());
12.request.setAttribute("novelChapter",novelChapter);
13.request.setAttribute("lastPageId",lastPageId);
14.request.setAttribute("nextPageId",nextPageId);
15.newCreateStaticHTMLPage().createStaticHTMLPage(request,response,getServletContext(),
16.chapterFileName,chapterFilePath,"/bookRead.jsp");
17.}
18.}
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
if(request.getParameter("chapterId")!
=null){
StringchapterFileName="bookChapterRead_"+request.getParameter("chapterId")+".html";
StringchapterFilePath=getServletContext().getRealPath("/")+chapterFileName;
FilechapterFile=newFile(chapterFilePath);
if(chapterFile.exists()){response.sendRedirect(chapterFileName);return;}//如果有这个文件就告诉浏览器转向
INovelChapterBiznovelChapterBiz=newNovelChapterBizImpl();
NovelChapternovelChapter=novelChapterBiz.searchNovelChapterById(Integer.parseInt(request.getParameter("chapterId")));//章节信息
intlastPageId=novelChapterBiz.searchLastCHapterId(novelChapter.getNovelId().getId(),novelChapter.getId());
intnextPageId=novelChapterBiz.searchNextChapterId(novelChapter.getNovelId().getId(),novelChapter.getId());
request.setAttribute("novelChapter",novelChapter);
request.setAttribute("lastPageId",lastPageId);
request.setAttribute("nextPageId",nextPageId);
newCreateStaticHTMLPage().createStaticHTMLPage(request,response,getServletContext(),
chapterFileName,chapterFilePath,"/bookRead.jsp");
}
}
生成HTML静态页面的类:
[java]viewplaincopyprint?
1.packagecom.jb.y2t034.thefifth.web.servlet;
2.importjava.io.ByteArrayOutputStream;
3.importjava.io.FileOutputStream;
4.importjava.io.IOException;
5.importjava.io.OutputStreamWriter;
6.importjava.io.PrintWriter;
7.importjavax.servlet.RequestDispatcher;
8.importjavax.servlet.ServletContext;
9.importjavax.servlet.ServletException;
10.importjavax.servlet.ServletOutputStream;
11.importjavax.servlet.http.HttpServletRequest;
12.importjavax.servlet.http.HttpServletResponse;
13.importjavax.servlet.http.HttpServletResponseWrapper;
14./**
15.*创建HTML静态页面
16.*功能:
创建HTML静态页面
17.*时间:
2009年1011日
18.*地点:
home
19.*@authormavk
20.*
21.*/
22.publicclassCreateStaticHTMLPage{
23./**
24.*生成静态HTML页面的方法
25.*@paramrequest请求对象
26.*@paramresponse响应对象
27.*@paramservletContextServlet上下文
28.*@paramfileName文件名称
29.*@paramfileFullPath文件完整路径
30.*@paramjspPath需要生成静态文件的JSP路径(相对即可)
31.*@throwsIOException
32.*@throwsServletException
33.*/
34.publicvoidcreateStaticHTMLPage(HttpServletRequestrequest,HttpServletResponseresponse,ServletContextservletContext,StringfileName,StringfileFullPath,StringjspPath)throwsServletException,IOException{
35.response.setContentType("text/html;charset=gb2312");//设置HTML结果流编码(即HTML文件编码)
36.RequestDispatcherrd=servletContext.getRequestDispatcher(jspPath);//得到JSP资源
37.finalByteArrayOutputStreambyteArrayOutputStream=newByteArrayOutputStream();//用于从ServletOutputStream中接收资源
38.finalServletOutputStreamservletOuputStream=newServletOutputStream(){//用于从HttpServletResponse中接收资源
39.publicvoidwrite(byte[]b,intoff,intlen){
40.byteArrayOutputStream.write(b,off,len);
41.}
42.publicvoidwrite(intb){
43.byteArrayOutputStream.write(b);
44.}
45.};
46.finalPrintWriterprintWriter=newPrintWriter(newOutputStreamWriter(byteArrayOutputStream));//把转换字节流转换成字符流
47.HttpServletResponsehttpServletResponse=newHttpServletResponseWrapper(response){//用于从response获取结果流资源(重写了两个方法)
48.publicServletOutputStreamgetOutputStream(){
49.returnservletOuputStream;
50.}
51.publicPrintWritergetWriter(){
52.returnprintWriter;
53.}
54.};
55.rd.include(request,httpServletResponse);//发送结果流
56.printWriter.flush();//刷新缓冲区,把缓冲区的数据输出
57.FileOutputStreamfileOutputStream=newFileOutputStream(fileFullPath);
58.byteArrayOutputStream.writeTo(fileOutputStream);//把byteArrayOuputStream中的资源全部写入到fileOuputStream中
59.fileOutputStream.close();//关闭输出流,并释放相关资源
60.response.sendRedirect(fileName);//发送指定文件流到客户端
61.}
62.}
packagecom.jb.y2t034.thefifth.web.servlet;
importjava.io.ByteArrayOutputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.OutputStreamWriter;
importjava.io.PrintWriter;
importjavax.servlet.RequestDispatcher;
importjavax.servlet.ServletContext;
importjavax.servlet.ServletException;
importjavax.servlet.ServletOutputStream;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjavax.servlet.http.HttpServletResponseWrapper;
/**
*创建HTML静态页面
*功能:
创建HTML静态页面
*时间:
2009年1011日
*地点:
home
*@authormavk
*
*/
publicclassCreateStaticHTMLPage{
/**
*生成静态HTML页面的方法
*@paramrequest请求对象
*@paramresponse响应对象
*@paramservletContextServlet上下文
*@paramfileName文件名称
*@paramfileFullPath文件完整路径
*@paramjspPath需要生成静态文件的JSP路径(相对即可)
*@throwsIOException
*@throwsServletException
*/
publicvoidcreateStaticHTMLPage(HttpServletRequestrequest,HttpServletResponseresponse,ServletContextservletContext,StringfileName,StringfileFullPath,StringjspPath)throwsServletException,IOException{
response.setContentType("text/html;charset=gb2312");//设置HTML结果流编码(即HTML文件编码)
RequestDispatcherrd=servletContext.getRequestDispatcher(jspPath);//得到JSP资源
finalByteArrayOutputStreambyteArrayOutputStream=newByteArrayOutputStream();//用于从ServletOutputStream中接收资源
finalServletOutputStreamservletOuputStream=newServletOutputStream(){//用于从HttpServletResponse中接收资源
publicvoidwrite(byte[]b,intoff,intlen){
byteArrayOutputStream.write(b,off,len);
}
publicvoidwrite(intb){
byteArrayOutputStream.write(b);
}
};
finalPrintWriterprintWriter=newPrintWriter(newOutputStreamWriter(byteArrayOutputStream));//把转换字节流转换成字符流
HttpServletResponsehttpServletResponse=newHttpServletResponseWrapper(response){//用于从response获取结果流资源(重写了两个方法)
publicServletOutputStreamgetOutputStream(){
returnservletOuputStream;
}
publicPrintWritergetWriter(){
returnprintWriter;
}
};
rd.include(request,httpServletResponse);//发送结果流
printWriter.flush();//刷新缓冲区,把缓冲区的数据输出
FileOutputStreamfileOutputStream=newFileOutputStream(fileFullPath);
byteArrayOutputStream.writeTo(fileOutputStream);//把byteArrayOuputStream中的资源全部写入到fileOuputStream中
fileOutputStream.close();//关闭输出流,并释放相关资源
response.sendRedirect(fileName);//发送指定文件流到客户端
}
}
三:
高并发高负载类网站关注点之缓存、负载均衡、存储
缓存是另一个大问题,我一般用memcached来做缓存集群,一般来说部署10台左右就差不多(10g内存池)。
需要注意一点,千万不能用使用swap,最好关闭linux的swap。
负载均衡/加速
可能上面说缓存的时候,有人第一想的是页面静态化,所谓的静态html,我认为这是常识,不属于要点了。
页面的静态化随之带来的是静态服务的负载均衡和加速。
我认为Lighttped+Squid是最好的方式了。
LVS<------->lighttped====>squid(s)====lighttpd
上面是我经常用的。
注意,我没有用apache,除非特定的需求,否则我不部署apache,因为我一般用php-fastcgi配合lighttpd,性能比apache+mod_php要强很多。
squid的使用可以解决文件的同步等等问题,但是需要注意,你要很好的监控缓存的命中率,尽可能的提高的90%以上。
squid和lighttped也有很多的话题要讨论,这里不赘述。
存储
存储也是一个大问题,一种是小文件的存储,比如图片这类。
另一种是大文件的存储,比如搜索引擎的索引,一般单文件都超过2g以上。
小文件的存储最简单的方法是结合lighttpd来进行分布。
或者干