怎样实现java系统的可配置性
一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构、性能的要求都很简单,随着互联网业务的不断丰富,网站相关的技术经过这些年的发展,已经细分到很细的方方面面,尤其对于大型网站来说,所采用的技术更是涉及面非常广,从硬件到软件、编程语言、数据库、WebServer、防火墙等各个领域都有了很高的要求,已经不是原来简单的html静态网站所能比拟的。
大型网站,比如门户网站。在面对大量用户访问、高并发请求方面,基本的解决方案集中在这样几个环节:使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。但是除了这几个方面,还没法根本解决大型网站面临的高负载和高并发问题。
上面提供的几个解决思路在一定程度上也意味着更大的投入,并且这样的解决思路具备瓶颈,没有很好的扩展性,下面我从低成本、高性能和高扩张性的角度来说说我的一些经验。
1、HTML静态化
其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。
除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化,有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。
同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求。
2、服务器分离
大家知道,对于Web服务器来说,不管是Apache、IIS还是其他容器,是最消耗资源的,于是我们有必要将与页面进行分离,这是基本上大型网站都会采用的策略,他们都有独立的服务器,甚至很多台服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为问题而崩溃,在应用服务器和服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持,尽可能少的LoadModule,保证更高的系统消耗和执行效率。
3、数据库集群和库表散列
大型网站都有复杂的应用,这些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓶颈很快就能显现出来,这时一台数据库将很快无法满足应用,于是我们需要使用数据库集群或者库表散列。
在数据库集群方面,很多数据库都有自己的解决方案,Oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB,就参考相应的解决方案来实施即可。
上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离,然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。
4、缓存
缓存一词搞技术的都接触过,很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。
架构方面的缓存,对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力。
网站程序开发方面的缓存,Linux上提供的Memory Cache是常用的缓存接口,可以在web开发中使用,比如用Java开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享,一些大型社区使用了这样的架构。另外,在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法,PHP有Pear的Cache模块,Java就更多了,net不是很熟悉,相信也肯定有。
5、镜像
镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异,比如ChinaNet和EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点,数据进行定时更新或者实时更新。在镜像的细节技术方面,这里不阐述太深,有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路,比如Linux上的rsync等工具。
6、负载均衡
负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。
负载均衡技术发展了多年,有很多专业的服务提供商和产品可以选择,我个人接触过一些解决方法,其中有两个架构可以给大家做参考。
1)硬件四层交换
第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用服务器进行处理。 第四层交换功能就象是虚IP,指向物理服务器。它传输的业务服从的协议多种多样,有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上,需要复杂的载量平衡算法。在IP世界,业务类型由终端TCP或UDP端口地址来决定,在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。
在硬件四层交换产品领域,有一些知名的产品可以选择,比如Alteon、F5等,这些产品很昂贵,但是物有所值,能够提供非常优秀的性能和很灵活的管理能力。Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。
2)软件四层交换
大家知道了硬件四层交换机的原理后,基于OSI模型来实现的软件四层交换也就应运而生,这样的解决方案实现的原理一致,不过性能稍差。但是满足一定量的压力还是游刃有余的,有人说软件实现方式其实更灵活,处理能力完全看你配置的熟悉能力。
软件四层交换我们可以使用Linux上常用的LVS来解决,LVS就是Linux Virtual Server,他提供了基于心跳线heartbeat的实时灾难应对解决方案,提高系统的鲁棒性,同时可供了灵活的虚拟VIP配置和管理功能,可以同时满足多种应用需求,这对于分布式的系统来说必不可少。
一个典型的使用负载均衡的策略就是,在软件或者硬件四层交换的基础上搭建squid集群,这种思路在很多大型网站包括搜索引擎上被采用,这样的架构低成本、高性能还有很强的扩张性,随时往架构里面增减节点都非常容易。这样的架构我准备空了专门详细整理一下和大家探讨。
一:高并发高负载类网站关注点之数据库
没错,首先是数据库,这是大多数应用所面临的首个SPOF。尤其是Web20的应用,数据库的响应是首先要解决的。
一般来说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对应的cluster id,然后再到指定的cluster找到nightsailer的实际数据。
每个cluster可以用m-m方式,或者m-m-slaves方式。这是一个可以扩展的结构,随着负载的增加,你可以简单的增加新的mysql cluster进去。
需要注意的是:
1、禁用全部auto_increment的字段
2、id需要采用通用的算法集中分配
3、要具有比较好的方法来监控mysql主机的负载和服务的运行状态。如果你有30台以上的mysql数据库在跑就明白我的意思了。
4、不要使用持久性链接(不要用pconnect),相反,使用sqlrelay这种第三方的数据库链接池,或者干脆自己做,因为php4中mysql的链接池经常出问题。
二:高并发高负载网站的系统架构之HTML静态化
其实大家都知道,效率最高、消耗最小的就是纯静态化 http://wwwablanxuecom/shtml/201207/776shtml的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是 最有效的方法。但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点 的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限 管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。
除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化,有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。
同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛 中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这 部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求高并发。
网站HTML静态化解决方案
当一个Servlet资源请求到达WEB服务器之后我们会填充指定的JSP页面来响应请求:
HTTP请求---Web服务器---Servlet--业务逻辑处理--访问数据--填充JSP--响应请求
HTML静态化之后:
HTTP请求---Web服务器---Servlet--HTML--响应请求
静态访求如下
Servlet:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if(requestgetParameter("chapterId") != null){
String chapterFileName = "bookChapterRead_"+requestgetParameter("chapterId")+"html";
String chapterFilePath = getServletContext()getRealPath("/") + chapterFileName;
File chapterFile = new File(chapterFilePath);
if(chapterFileexists()){responsesendRedirect(chapterFileName);return;}//如果有这个文件就告诉浏览器转向
INovelChapterBiz novelChapterBiz = new NovelChapterBizImpl();
NovelChapter novelChapter = novelChapterBizsearchNovelChapterById(IntegerparseInt(requestgetParameter("chapterId")));//章节信息
int lastPageId = novelChapterBizsearchLastCHapterId(novelChaptergetNovelId()getId(), novelChaptergetId());
int nextPageId = novelChapterBizsearchNextChapterId(novelChaptergetNovelId()getId(), novelChaptergetId());
requestsetAttribute("novelChapter", novelChapter);
requestsetAttribute("lastPageId", lastPageId);
requestsetAttribute("nextPageId", nextPageId);
new CreateStaticHTMLPage()createStaticHTMLPage(request, response, getServletContext(),
chapterFileName, chapterFilePath, "/bookReadjsp");
}
}
生成HTML静态页面的类:
package comjby2t034thefifthwebservlet;
import javaioByteArrayOutputStream;
import javaioFileOutputStream;
import javaioIOException;
import javaioOutputStreamWriter;
import javaioPrintWriter;
import javaxservletRequestDispatcher;
import javaxservletServletContext;
import javaxservletServletException;
import javaxservletServletOutputStream;
import javaxservlethttpHttpServletRequest;
import javaxservlethttpHttpServletResponse;
import javaxservlethttpHttpServletResponseWrapper;
/
创建HTML静态页面
功能:创建HTML静态页面
时间:2009年1011日
地点:home
@author mavk
/
public class CreateStaticHTMLPage {
/
生成静态HTML页面的方法
@param request 请求对象
@param response 响应对象
@param servletContext Servlet上下文
@param fileName 文件名称
@param fileFullPath 文件完整路径
@param jspPath 需要生成静态文件的JSP路径(相对即可)
@throws IOException
@throws ServletException
/
public void createStaticHTMLPage(HttpServletRequest request, HttpServletResponse response,ServletContext servletContext,String fileName,String fileFullPath,String jspPath) throws ServletException, IOException{
responsesetContentType("text/html;charset=gb2312");//设置HTML结果流编码(即HTML文件编码)
RequestDispatcher rd = servletContextgetRequestDispatcher(jspPath);//得到JSP资源
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//用于从ServletOutputStream中接收资源
final ServletOutputStream servletOuputStream = new ServletOutputStream(){//用于从HttpServletResponse中接收资源
public void write(byte[] b, int off,int len){
byteArrayOutputStreamwrite(b, off, len);
}
public void write(int b){
byteArrayOutputStreamwrite(b);
}
};
final PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream));//把转换字节流转换成字符流
HttpServletResponse httpServletResponse = new HttpServletResponseWrapper(response){//用于从response获取结果流资源(重写了两个方法)
public ServletOutputStream getOutputStream(){
return servletOuputStream;
}
public PrintWriter getWriter(){
return printWriter;
}
};
rdinclude(request, httpServletResponse);//发送结果流
printWriterflush();//刷新缓冲区,把缓冲区的数据输出
FileOutputStream fileOutputStream = new FileOutputStream(fileFullPath);
byteArrayOutputStreamwriteTo(fileOutputStream);//把byteArrayOuputStream中的资源全部写入到fileOuputStream中
fileOutputStreamclose();//关闭输出流,并释放相关资源
responsesendRedirect(fileName);//发送指定文件流到客户端
}
}
在Java程序员行业中,有不少Java开发人员的理想是成为一名优秀的Java架构师,Java架构师的主要任务不是从事具体的软件程序的编写,而是从事更高层次的开发构架工作。他必须对开发技术非常了解,并且需要有良好的组织管理能力。可以这样说,一个Java架构师工作的好坏决定了整个软件开发项目的成败。那么Java架构师需要掌握哪些知识点呢?
1、框架源码分析
设计模式:Singleton单例模式,Factory工厂模式,Proxy代理模式,Template模板模式,Prototype原型模式等
Spring5:Spring提醒结构,IOC注入原理,AOP设计原理,Spring事务处理机制,SpringMVC,Spring源码分析。
Mybatis:Mybatis体系结构,Mybatis核心应用与配置,Mybatis关联查询,与Spring集成,Mybatis源码分析。
2、性能优化
JVM性能优化:剖析JVM整体结构,详解垃圾回收机制GC,JVM性能调优与工具排查
Nginx调优:Nginx项目架构,Nginx核心配置,Nginx负载算法配置
Tomcat调优:Tomcat运行机制及框架,Tomcat线程模型,Tomcat性能调优
MySQL性能优化:SQL执行计划,AQL优化,索引优化。
3、掌握池技术
对象池,连接池,线程池,Java反射技术,写框架必备的技术,但是有严重的性能问题,替代方案Java字节码技术。
4、掌握nio,值得注意的是“直接内存”的特点,使用场景。
5、掌握Java多线程同步异步。
6、掌握Java各种集合对象的实现原理,了解这些可以让你在解决问题时选择合适的数据结构,高效的解决问题。
7、熟练使用各种数据结构和算法,数组、哈希、链表、排序树就是一句话要么是时间换空间要么是空间换时间。
8、熟悉tcp协议,创建连接三次握手和断开连接四次握手的整个过程,不了解的话,无法对高并发网络应用做优化。
9、熟悉http协议,尤其是http头,我发现好多工作五年以上的都弄不清session和cookie的生命周期以及它们之间的关联。
10、熟悉系统集群、负载均衡、反向代理、动静分离,网站静态化。
11、掌握分布式。
Java并发编程和网络编程:Java线程状态,线程池,线程通信,线程安全,Netty高性能原理
分布式开发框架:分布式系统口调用技术:RPC,Apache分布式系统Zookeeper原理与应用,阿里Dubbo设计思想与应用
分布式中间件:分布式服务器治理,分布式消息通信,分布式数据缓存,MongoDB企业集群解决方案
12、掌握数据库的设计能力,对它基本的参数优化,慢查询日志分析,主从复制的配置,至少要成为半个mysqldba。
1、语法:
Java程序员必须比较熟悉语法,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知道任何修正。
2、命令:
必须熟悉JDK带的一些常用命令及其常用选项,命令至少需要熟悉:
appletviewer、HtmlConverter、jar、java、javac、javadoc、javap、javaw、native2ascii、serialver,
如果这些命令你没有全部使用过,那么你对java 实际上还很不了解。
3、工具:
必须至少熟练使用一种IDE的开发工具,
例如Eclipse、Netbeans、JBuilder、Jdeveloper、IDEA、JCreator或者Workshop,
包括进行工程管理、常用选项的设置、插件的安装配置以及进行调试。
4、API:
Java的核心API是非常庞大的,但是有一些内容笔者认为是Java程序员必须熟悉的,否则不可能熟练的运用Java,
包括:
javalang包下的80%以上的类的功能的灵活运用。
javautil包下的80%以上的类的灵活运用,特别是集合类体系、规则表达式、zip、以及时间、随机数、属性、资源和Timer
javaio包下的60%以上的类的使用,理解IO体系的基于管道模型的设计思路以及常用IO类的特性和使用场合。
javamath包下的100%的内容。
javanet包下的60%以上的内容,对各个类的功能比较熟悉。
javatext包下的60%以上的内容,特别是各种格式化类。
熟练运用JDBC 8)、javasecurity包下40%以上的内容,如果对于安全没有接触的话根本就不可能掌握java
AWT的基本内容,包括各种组件事件、监听器、布局管理器、常用组件、打印。
Swing的基本内容,和AWT的要求类似。
XML处理,熟悉SAX、DOM以及JDOM的优缺点并且能够使用其中的一种完成XML的解析及内容处理。
5、测试:
必须熟悉使用junit编写测试用例完成代码的自动测试。
6、管理:
Java程序员必须熟悉使用ant完成工程管理的常用任务,
例如工程编译、生成javadoc、生成jar、版本控制、自动测试。
7、排错:
应该可以根据异常信息比较快速的定位问题的原因和大致位置。
8、思想:
必须掌握OOP的主要要求,这样使用Java开发的系统才能是真正的Java系统。
9、规范:
编写的代码必须符合流行的编码规范,
例如类名首字母大写,成员和方法名首字母小写,方法名的第一个单词一般是动词,包名全部小写等,这样程序的可读性才比较好。
10、博学:
Java程序员除了精通Java意外,还要掌握J2EE 、Oracle 、WebLogic、Jboss、Spring、Struts、Hibernate
等流行技术,掌握软件架构设计思想、搜索引擎优化、缓存系统设计、网站负载均衡、系统性能调优等。
想要学好Java技术,成为一名优秀的程序员,郑州的童鞋,可以选择尚学堂
有些网站并发量比较高,例如:12306,到了春节的时候,访问量就非常高了。以前不是经常卡住、崩溃吗?
就是因为架构设计的不行。去年好多了。
高吞吐、高并发指的是一种种业务场景,访问人数很多,同一时刻点击也很多。
类似的还有双十一,双12。
高峰期的时候 涉及大量的读写操作,读取网页资源、数据,写入订单等等。
小型网站可以通过增加服务器的方法解决,分离应用程序和数据库,放在两台服务器上。
大型的网站涉及的技术就更多了:缓存技术、读写分离、分布式部署服务器、业务拆分、数据库优化等等。
一般系统是分成:访问方式、数据存储方式、外围系统连接方式、本系统的服务器这四个方面来叙述
比如访问方式是B/S模式,数据库是oracle,外围系统可能不存在或者也是一个JAVA系统,本系统比如搭建在TOMCAT或者WEBLOGIC上面
那么接下来叙述就是实现系统用到的技术有哪些
比如说系统用到了很多技术,如使用flex做前台展示,用hibernate做数据库存储,用webservice做外围系统接入
然后叙述这些单独的技术是怎么进行整合的,比如通过spring将这些技术进行整合,并叙述是使用哪种方式进行连接
把这些东西讲清楚,简单的技术架构应该就出来了
JVM
JEE容器中运行的JVM参数配置参数的正确使用直接关系到整个系统的性能和处理能力,JVM的调优主要是对内存管理方面的调优,优化的方向分为以下4点:
HeapSize
堆的大小,也可以说Java虚拟机使用内存的策略,这点是非常关键的。
2GarbageCollector
通过配置相关的参数进行Java中的垃圾收集器的4个算法(策略)进行使用。
3StackSize
栈是JVM的内存指令区,每个线程都有他自己的Stack,Stack的大小限制着线程的数量。
4DeBug/Log
在JVM中还可以设置对JVM运行时的日志和JVM挂掉后的日志输出,这点非常的关键,根据各类JVM的日志输出才能配置合适的参数。
网上随处可见JVM的配置技巧,但是我还是推荐阅读Sun官方的2篇文章,可以对配置参数的其所依然有一个了解
Java HotSpot VM Options
Java HotSpot VM Options
2Troubleshooting Guide for Java SE 6 with HotSpot VMTroubleshooting Guide for Java SE 6 with HotSpot VM
另外,我相信不是每个人攻城师都是天天对着这些JVM参数的,如果你忘记了那些关键的参数你可以输入Java -X(大写X)进行提示。
JDBC
针对MySQL的JDBC的参数在之前的文章中也有介绍过,在单台机器或者集群的环境下合理的使用JDBC中的配置参数对操作数据库也有很大的影响。
一些所谓高性能的 Java ORM开源框架也就是打开了很多JDBC中的默认参数:
例如:autoReconnect、prepStmtCacheSize、cachePrepStmts、useNewIO、blobSendChunkSize 等,
2例如集群环境下:roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster。
数据库连接池(DataSource)
应用程序与数据库连接频繁的交互会给系统带来瓶颈和大量的开销会影响到系统的性能,JDBC连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用
一个现有的数据库连接,而再不是重新建立一个连接,因此应用程序不需要频繁的与数据库开关连接,并且可以释放空闲时间超过最大空闲时间的数据库连接来避免
因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
在此我认为有一点需要说明:
连接池的使用也是需要关闭,因为在数据库连接池启动的时候就预先和数据库获得了相应的连接,之后不再需要应用程序直接的和数据库打交道,因为应用程序使用数据库连接池是一个
“借”的概念,应用程序从数据库连接池中获得资源是“借出”,还需要还回去,就好比有20个水桶放在这里,需要拿水的人都可以使用这些木桶从水池里面拿水,如果20个人都拿完水,不将水桶还回原地,那么后面来的人再需要拿水,只能在旁边等待有人将木桶还回去,之前的人用完后需要放回去,不然后面的人就会一直等待,造成资源堵塞,同理,应用程序获取数据库连接的时候Connection连接对象的时候是从“池”中分配一个数据库连接出去,在使用完毕后,归还这个数据库连接,这样才能保持数据库的连接“有借有还”准则。
数据存取
数据库服务器的优化和数据的存取,什么类型的数据放在什么地方更好是值得去思考的问题,将来的存储很可能是混用的,Cache,NOSQL,DFS,DataBase 在一个系统中都会有,生活的餐具和平日里穿衣服需要摆放在家里,但是不会用同一种类型的家具存放,貌似没有那个人家把餐具和衣服放在同一个柜子里面的。这就像是系统中不同类型的数据一样,对不同类型的数据需要使用合适的存储环境。文件和的存储,首先按照访问的热度分类,或者按照文件的大小。强关系类型并且需要事务支持的采用传统的数据库,弱关系型不需要事务支持的可以考虑NOSQL,海量文件存储可以考虑一下支持网络存储的DFS,至于缓存要看你单个数据存储的大小和读写的比例。
还有一点值得注意就是数据读写分离,无论在DataBase还是NOSQL的环境中大部分都是读大于写,因此在设计时还需考虑 不仅仅需要让数据的读分散在多台机器上,还需要考虑多台机器之间的数据一致性,MySQL的一主多从,在加上MySQL-Proxy或者借用JDBC中的一些参数(roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster)对后续应用程序开发,可以将读和写分离,将大量读的压力分散在多台机器上,并且还保证了数据的一致性。
缓存
在宏观上看缓存一般分为2种:本地缓存和分布式缓存
本地缓存
对于Java的本地缓存而言就是讲数据放入静态(static)的数据结合中,然后需要用的时候就从静态数据结合中拿出来,对于高并发的环境建议使用 ConcurrentHashMap或者CopyOnWriteArrayList作为本地缓存。缓存的使用更具体点说就是对系统内存的使用,使用多少内存的资源需要有一个适当比例,如果超过适当的使用存储访问,将会适得其反,导致整个系统的运行效率低下。
2 分布式缓存
一般用于分布式的环境,将每台机器上的缓存进行集中化的存储,并且不仅仅用于缓存的使用范畴,还可以作为分布式系统数据同步/传输的一种手段,一般被使用最多的就是Memcached和Redis。
数据存储在不同的介质上读/写得到的效率是不同的,在系统中如何善用缓存,让你的数据更靠近cpu。
并发/多线程
在高并发环境下建议开发者使用JDK中自带的并发包(javautilconcurrent),在JDK15以后使用javautilconcurrent下的工具类可以简化多线程开发,在javautilconcurrent的工具中主要分为以下几个主要部分:
线程池
线程池的接口(Executor、ExecutorService)与实现类(ThreadPoolExecutor、
ScheduledThreadPoolExecutor),利用jdk自带的线程池框架可以管理任务的排队和安排,并允许受控制的关闭。因为运行一个线程需要消耗系统CPU资源,而创建、结束一个线程也对系统CPU资源有开销,使用线程池不仅仅可以有效的管理多线程的使用,还是可以提高线程的运行效率。
2本地队列
提供了高效的、可伸缩的、线程安全的非阻塞 FIFO 队列。javautilconcurrent 中的五个实现都支持扩展的 BlockingQueue 接口,该接口定义了 put 和 take的阻塞版本:LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、
PriorityBlockingQueue 和 DelayQueue。这些不同的类覆盖了生产者-使用者、消息传递、并行任务执行和相关并发设计的大多数常见使用的上下文。
0条评论