精华内容
下载资源
问答
  • Java开源高可用架构

    千次阅读 2014-05-09 13:36:52
    1)NIO(apache mino)非阻塞通信,...   2)Resutful ...REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 ...springmvc rest 实现: springmvc的resturl是通过@RequestMapping 及
    1)NIO(apache mino)非阻塞通信,通过通道绑定端口,然后将端口注册到selector上监听相应事件类型
    
        

    2)Resutful
    REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful
    springmvc rest 实现:
    springmvc的resturl是通过@RequestMapping 及@PathVariable annotation提供的,通过如@RequestMapping(value="/blog/{id}",method=RequestMethod.DELETE)即可处理/blog/1 的delete请求
    1. @RequestMapping(value="/blog/{id}",method=RequestMethod.DELETE)  
    2. public ModelAndView delete(@PathVariable Long id,HttpServletRequest request,HttpServletResponse response) {  
    3.     blogManager.removeById(id);  
    4.     return new ModelAndView(LIST_ACTION);  
    5. }  
    3)thrift
    thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发,传输二进制格式
    1.数据类型

    2.服务端编码基本步骤:

    • 实现服务处理接口impl
    • 创建TProcessor
    • 创建TServerTransport
    • 创建TProtocol
    • 创建TServer
    • 启动Server

    3.客户端编码基本步骤:

    • 创建Transport
    • 创建TProtocol
    • 基于TTransport和TProtocol创建 Client
    • 调用Client的相应方法

    4.数据传输协议

    • TBinaryProtocol : 二进制格式.
    • TCompactProtocol : 压缩格式
    • TJSONProtocol : JSON格式
    • TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析

    4)LMAX(Disruptor)线程间交换模式
    LMAX公司被创建去构建一种高性能的金融交易平台Disruptor是一个高性能的异步处理框架,或者可以认为是最快的消息框架(轻量的JMS),也可以认为是一个观察者模式实现,或者事件-监听模式的实现,直接称disruptor模式。disruptor最大特点是高性能,其LMAX架构可以获得每秒6百万订单,用1微秒的延迟获得吞吐量为100K+
    许多应用使用队列来实现在其线程间的数据交互。通过测试我们发现,非常戏剧性的——使用队列造成的延迟与磁盘IO操作(RAID、SSD磁盘)造成的延迟同样的多!如果在一个端对端操作中使用多个队列,这将会增加数百毫秒的总延迟。显然,这是一个需要优化的领域
    展开全文
  • zookeeper实现高可用

    千次阅读 2016-11-30 14:24:16
    原来的项目是main方法直接启动的jar包,但不能高可用,根据领导要求,增加高可用,在前面包一层。具体的看代码: 1、导入Jar包: org.apache.curator curator-recipes 2.7.1   2、 HAMain....

    原来的项目是main方法直接启动的jar包,但不能高可用,根据领导要求,增加高可用,在前面包一层。具体的看代码:

    1、导入Jar包:

    		<dependency>
    			<groupId>org.apache.curator</groupId>
    			<artifactId>curator-recipes</artifactId>
    			<version>2.7.1</version>
    		</dependency>


     

    2、

    HAMain.java

     

    package com.chinaunicom;
    
    import java.util.List;
    import java.util.Properties;
    import java.util.SortedSet;
    import java.util.TreeSet;
    import java.util.concurrent.CountDownLatch;
    
    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.ZooKeeper;
    import org.apache.zookeeper.Watcher.Event.EventType;
    import org.apache.zookeeper.ZooDefs.Ids;
    import org.apache.zookeeper.data.Stat;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.chinaunicom.util.FileReadUtil;
    
    public class HAMain {
    
    	private static Logger log = LoggerFactory.getLogger(HAMain.class.getName());
    	// 在zk上注册的机器节点列表
    		public static SortedSet<String> servers;
    		// 由zk自动递增分配的节点id
    		public static String myNodeID;
    
    		private ZooKeeper zk;
    		private final Stat stat = new Stat();
    		// 应用的顶层目录
    		private  String spath = "/dtsEs";
    		// 分隔符
    		private final String delimiter = "/";
    		//topicName
    		private static  String topicName="";
    		 //属性文件
    		 private static Properties prop;
    		 
    		 private static boolean isUP=false;
    		
    		private CountDownLatch connectedSignal = new CountDownLatch(1);
    
    		/**
    		 * 主程序,读取zookeeper配置信息,连接zookeeper
    		 * 监听节点变化信息。如果节点变化了,则判断当前节点是否为最小节点,如果是最小节点,则运行主程序
    		 * @param id
    		 * @throws Exception
    		 */
    		public HAMain(String id) throws Exception {
    			FileReadUtil propBean = new FileReadUtil();
    			//获得zookeeper配置信息
    			prop = propBean.getProperties("dts_es.properties");
    			String connectString=prop.getProperty("zookeeper.connectString");
    			int sessionTimeOut=Integer.parseInt(prop.getProperty("zookeeper.sessionTimeout"));
    			try {
    				// 创建一个与服务器的连接
    				zk = new ZooKeeper(connectString, sessionTimeOut , new Watcher() {
    					@Override
    					public void process(WatchedEvent event) {
    						log.info("-------node Change:" + event);
    						// 如果发生了spath节点下的子节点变化事件, 更新server列表, 并重新注册监听
    						if (event.getType() == EventType.NodeChildrenChanged
    								&& spath.equals(event.getPath())) {
    							try {
    								updateServerList();
    							} catch (Exception e) {
    								e.printStackTrace();
    							}
    						}
    					}
    				});
    				createParentDirectory(id);
    				createAppNode(id);
    				updateServerList();
    				//此处开始阻塞
    				connectedSignal.await();
    				//如果满足条件,则开始执行任务
    				log.info("我开始做任务啦!~~~myNodeID:"+HAMain.myNodeID);
    				ClusterClientCore coreMain=new ClusterClientCore();
    				String param[]={topicName};
    				coreMain.main(param);
    				log.error("我挂啦!~~~myNodeID:"+HAMain.myNodeID);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    
    		/**
    		 * 创建一个子目录节点
    		 * @param id
    		 * @throws Exception
    		 */
    		public void createAppNode(String id) throws Exception {
    			myNodeID = zk.create(spath + delimiter, id.getBytes("utf-8"),
    					Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
    			myNodeID = myNodeID.substring(myNodeID.lastIndexOf('/') + 1);
    		}
    
    		/**
    		 * 如果不存在则创建顶层目录
    		 * @param id
    		 * @throws Exception
    		 */
    		public void createParentDirectory(String id) throws Exception {
    			spath=spath+delimiter+id;
    			Stat stat = null;
    			try {
    				stat = zk.exists(spath, true);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    			if (stat == null) {
    				zk.create(spath, id.getBytes("utf-8"),
    						Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    			}
    		}
    
    		/**
    		 * 更新服务器节点列表
    		 * @throws Exception
    		 */
    		public void updateServerList() throws Exception {
    			SortedSet<String> set = new TreeSet<String>();
    			// 获取并监听spath的子节点变化
    			// watch参数为true, 表示监听子节点变化事件.
    			// 每次都需要重新注册监听, 因为一次注册, 只能监听一次事件, 如果还想继续保持监听, 必须重新注册
    			List<String> subList = zk.getChildren(spath, true);
    			for (String subNode : subList) {
    				// 获取每个子节点下关联的server地址
    //				 byte[] data = zk.getData(spath + delimiter + subNode, false, stat);
    //				 log.info(subNode + "\t" + stat);
    //				 String sdata = new String(data, "utf-8");
    				set.add(subNode);
    			}
    			servers = set;
    			 // 取消阻塞服务
    			cancelAwait();
    		}
    		
    		/**
    		 * 如果当前是最小的节点,则取消阻塞
    		 */
    		public void cancelAwait() {
    			String minNode = HAMain.servers.first();
    			log.info("当前节点:"+HAMain.myNodeID + ",最小的节点:  " + minNode);
    			if (HAMain.myNodeID.equals(minNode)) {// 验证本机是否是最小节点
    				if(!isUP){//如果没有启动过
    					isUP=true;
    				connectedSignal.countDown();
    				}
    			}
    		}
    
    		// 关闭连接
    		public void close() throws InterruptedException {
    			zk.close();
    		}
    		/**
    		 * chengxu rukou  
    		 * @param args
    		 * @throws Exception
    		 */
    		public static void main(String[] args) throws Exception {
    			String nodeid = "autoid";
    			if (args.length == 1) {
    				nodeid = args[0];
    				topicName=nodeid;
    			}
    			new HAMain(nodeid);
    		}
    }
    


    文件工具类:主要读取配置文件

    FileReadUtil:

    package com.chinaunicom.util;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    import com.alibaba.fastjson.JSON;
    
    
    /**
     * 属性文件工具类
     * @author zsh
     *
     */
    public class FileReadUtil {
     
     private static Logger log = LoggerFactory.getLogger(FileReadUtil.class);
     
     
     public static void main(String[] args) {
      FileReadUtil f = new FileReadUtil();
      f.getFileList();
     }
      
    
     
     
     
     /**
      * 获取某个jar包下面文件夹的文件集合
      * @return
      */
     public Resource[] getFileList(){
      Resource[] workflowResources  = null;
      try {
       final PathMatchingResourcePatternResolver pmrpr = new PathMatchingResourcePatternResolver(FileReadUtil.class.getClassLoader());
       workflowResources = pmrpr.getResources("classpath*:tableJson/*.json");
       if (workflowResources == null || workflowResources.length == 0) {
        workflowResources = pmrpr.getResources("classpath*:resources/tableJson/*.json");
       }
      } catch (IOException e1) {
       e1.printStackTrace();
      }
      /*
      try {
       String templateDir = fileName+File.separator;
       log.error(templateDir);
             URL templateUri = FileReadUtil.class.getClassLoader().getResource(templateDir);
             if(templateUri != null) {
                 File fileTemplateDir = new File(templateUri.toURI());
                 templateFiles = fileTemplateDir.listFiles(new FilenameFilter(){
                  public boolean accept(File dir, String name) {
                   return name.endsWith(".json");
                  }
                 });
             }
      } catch (URISyntaxException e) {
       e.printStackTrace();
      }*/
      return workflowResources;
     }
     
     
     
     /**
      * 获取文件夹中所有文件名
      * @param path
      * @return
      */
     public String[] getFileName(String fileName){
            File file = new File(fileName);
            String[] fileNames = file.list();
            return fileNames;
        }
     
     /**
         * 以行为单位读取文件,常用于读面向行的格式化文件
         */
        public String readFileByLines(InputStream inputStream) {
    //     InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName);  
         ByteArrayOutputStream outStream = new ByteArrayOutputStream();  
         try {
             byte[] data = new byte[1024];  
             int count = -1;  
             while((count = inputStream.read(data,0,1024)) != -1)  
                 outStream.write(data, 0, count);  
               
             data = null;  
             inputStream.close();
             outStream.close();
             return new String(outStream.toByteArray(),"utf-8"); 
         } catch (IOException e) {
          e.printStackTrace();
         }  
         return "";
         /*StringBuffer str = new StringBuffer();
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(file));
                String tempString = null;
                // 一次读入一行,直到读入null为文件结束
                while ((tempString = reader.readLine()) != null) {
                    // 显示行号
                 str.append(tempString);
                }
                reader.close();
                log.debug("表信息读取成功!");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e1) {
                    }
                }
            }
            return str.toString();*/
        }
     
     /**
      * 读取属性文件的内容
      * @return
      */
     public  Properties getProperties(String proName){  
      this.getClass().getClassLoader();
      Properties props = null;
         try {
          InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(proName);  
          props = new Properties();
          props.load(inputStream);
          log.error("加载配置文件属性实体类初始化成功!");
      } catch (IOException e) {
       e.printStackTrace();
      } finally{
      } 
         return props;
     }  
    }
    
    


    代码配置完毕。然后再在POM.XML中修改mian方法执行的入口。

     

    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-jar-plugin</artifactId>
    				<version>2.4</version>
    				<configuration>
    					<archive>
    						<manifest>
    							<addClasspath>true</addClasspath>
    							<classpathPrefix>lib/</classpathPrefix>
    							<mainClass>com.**.HAMain</mainClass>
    						</manifest>
    					</archive>
    				</configuration>
    			</plugin>
    		</plugins>
    
    	</build>
    


    至此,高可用配置完毕。把项目打完jar包,放在Linux下,执行 

    java -jar ***-0.0.1-SNAPSHOT.jar params> 1.log &    即可执行。

    也可以在命令前面增加 nohup 在后台执行。例如:nohup java -jar dtsEs-0.0.1-SNAPSHOT.jar rdsa365i83st0q3h8yi5 > 1.log &

     

    展开全文
  • 集群是如何实现高可用

    千次阅读 2021-01-06 09:49:15
    一、负载均衡 负载均衡算法 ...负载均衡器可以用来实现高可用以及伸缩性: 高可用:当某个节点故障时,负载均衡器会将用户请求转发到另外的节点上,从而保证所有服务持续可用; 伸缩性:根据系统整.
    
    

    一、负载均衡

    集群中的应用服务器(节点)通常被设计成无状态,用户可以请求任何一个节点。

    负载均衡器会根据集群中每个节点的负载情况,将用户请求转发到合适的节点上。

    负载均衡器可以用来实现高可用以及伸缩性:

    • 高可用:当某个节点故障时,负载均衡器会将用户请求转发到另外的节点上,从而保证所有服务持续可用;
    • 伸缩性:根据系统整体负载情况,可以很容易地添加或移除节点。

    负载均衡器运行过程包含两个部分:

    1. 根据负载均衡算法得到转发的节点;
    2. 进行转发。

    负载均衡算法

    1. 轮询(Round Robin)

    轮询算法把每个请求轮流发送到每个服务器上。

    下图中,一共有 6 个客户端产生了 6 个请求,这 6 个请求按 (1, 2, 3, 4, 5, 6) 的顺序发送。(1, 3, 5) 的请求会被发送到服务器 1,(2, 4, 6) 的请求会被发送到服务器 2。

    该算法比较适合每个服务器的性能差不多的场景,如果有性能存在差异的情况下,那么性能较差的服务器可能无法承担过大的负载(下图的 Server 2)。

    2. 加权轮询(Weighted Round Robbin)

    加权轮询是在轮询的基础上,根据服务器的性能差异,为服务器赋予一定的权值,性能高的服务器分配更高的权值。

    例如下图中,服务器 1 被赋予的权值为 5,服务器 2 被赋予的权值为 1,那么 (1, 2, 3, 4, 5) 请求会被发送到服务器 1,(6) 请求会被发送到服务器 2。

    3. 最少连接(least Connections)

    由于每个请求的连接时间不一样,使用轮询或者加权轮询算法的话,可能会让一台服务器当前连接数过大,而另一台服务器的连接过小,造成负载不均衡。

    例如下图中,(1, 3, 5) 请求会被发送到服务器 1,但是 (1, 3) 很快就断开连接,此时只有 (5) 请求连接服务器 1;(2, 4, 6) 请求被发送到服务器 2,只有 (2) 的连接断开,此时 (6, 4) 请求连接服务器 2。该系统继续运行时,服务器 2 会承担过大的负载。

    最少连接算法就是将请求发送给当前最少连接数的服务器上。

    例如下图中,服务器 1 当前连接数最小,那么新到来的请求 6 就会被发送到服务器 1 上。

    4. 加权最少连接(Weighted Least Connection)

    在最少连接的基础上,根据服务器的性能为每台服务器分配权重,再根据权重计算出每台服务器能处理的连接数。

    5. 随机算法(Random)

    把请求随机发送到服务器上。

    和轮询算法类似,该算法比较适合服务器性能差不多的场景。

    6. 源地址哈希法 (IP Hash)

    源地址哈希通过对客户端 IP 计算哈希值之后,再对服务器数量取模得到目标服务器的序号。

    可以保证同一 IP 的客户端的请求会转发到同一台服务器上,用来实现会话粘滞(Sticky Session)

    转发实现

    1. HTTP 重定向

    HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服务器的 IP 地址之后,将该地址写入 HTTP 重定向报文中,状态码为 302。客户端收到重定向报文之后,需要重新向服务器发起请求。

    缺点:

    • 需要两次请求,因此访问延迟比较高;
    • HTTP 负载均衡器处理能力有限,会限制集群的规模。

    该负载均衡转发的缺点比较明显,实际场景中很少使用它。

    2. DNS 域名解析

    在 DNS 解析域名的同时使用负载均衡算法计算服务器 IP 地址。

    优点:

    • DNS 能够根据地理位置进行域名解析,返回离用户最近的服务器 IP 地址。

    缺点:

    • 由于 DNS 具有多级结构,每一级的域名记录都可能被缓存,当下线一台服务器需要修改 DNS 记录时,需要过很长一段时间才能生效。

    大型网站基本使用了 DNS 做为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。也就是说,域名解析的结果为内部的负载均衡服务器 IP 地址。

    3. 反向代理服务器

    反向代理服务器位于源服务器前面,用户的请求需要先经过反向代理服务器才能到达源服务器。反向代理可以用来进行缓存、日志记录等,同时也可以用来做为负载均衡服务器。

    在这种负载均衡转发方式下,客户端不直接请求源服务器,因此源服务器不需要外部 IP 地址,而反向代理需要配置内部和外部两套 IP 地址。

    优点:

    • 与其它功能集成在一起,部署简单。

    缺点:

    • 所有请求和响应都需要经过反向代理服务器,它可能会成为性能瓶颈。

    4. 网络层

    在操作系统内核进程获取网络数据包,根据负载均衡算法计算源服务器的 IP 地址,并修改请求数据包的目的 IP 地址,最后进行转发。

    源服务器返回的响应也需要经过负载均衡服务器,通常是让负载均衡服务器同时作为集群的网关服务器来实现。

    优点:

    • 在内核进程中进行处理,性能比较高。

    缺点:

    • 和反向代理一样,所有的请求和响应都经过负载均衡服务器,会成为性能瓶颈。

    5. 链路层

    在链路层根据负载均衡算法计算源服务器的 MAC 地址,并修改请求数据包的目的 MAC 地址,并进行转发。

    通过配置源服务器的虚拟 IP 地址和负载均衡服务器的 IP 地址一致,从而不需要修改 IP 地址就可以进行转发。也正因为 IP 地址一样,所以源服务器的响应不需要转发回负载均衡服务器,可以直接转发给客户端,避免了负载均衡服务器的成为瓶颈。

    这是一种三角传输模式,被称为直接路由。对于提供下载和视频服务的网站来说,直接路由避免了大量的网络传输数据经过负载均衡服务器。

    这是目前大型网站使用最广负载均衡转发方式,在 Linux 平台可以使用的负载均衡服务器为 LVS(Linux Virtual Server)。

    二、集群下的 Session 管理

    一个用户的 Session 信息如果存储在一个服务器上,那么当负载均衡器把用户的下一个请求转发到另一个服务器,由于服务器没有用户的 Session 信息,那么该用户就需要重新进行登录等操作。

    Sticky Session

    需要配置负载均衡器,使得一个用户的所有请求都路由到同一个服务器,这样就可以把用户的 Session 存放在该服务器中。

    缺点:

    • 当服务器宕机时,将丢失该服务器上的所有 Session。

    Session Replication

    在服务器之间进行 Session 同步操作,每个服务器都有所有用户的 Session 信息,因此用户可以向任何一个服务器进行请求。

    缺点:

    • 占用过多内存;
    • 同步过程占用网络带宽以及服务器处理器时间。

    Session Server

    使用一个单独的服务器存储 Session 数据,可以使用传统的 MySQL,也使用 Redis 或者 Memcached 这种内存型数据库。

    优点:

    • 为了使得大型网站具有伸缩性,集群中的应用服务器通常需要保持无状态,那么应用服务器不能存储用户的会话信息。Session Server 将用户的会话信息单独进行存储,从而保证了应用服务器的无状态。

    缺点:

    • 需要去实现存取 Session 的代码。
    展开全文
  • Java实现高并发的处理的方式

    千次阅读 2017-08-11 23:38:46
    并发处理的方式

    转载博客地址:http://blog.csdn.NET/zxl333/article/details/8454319

    转载博客地址:http://blog.csdn.net/zxl333/article/details/8685157

    转载博客地址:http://blog.csdn.net/jimmy609/article/details/37810591

    一个小型的网站,比如个人网站,可以使用最简单的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。尤其是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对应的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://www.ablanxue.com/shtml/201207/776.shtml的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(request.getParameter("chapterId") != null){
    String chapterFileName = "bookChapterRead_"+request.getParameter("chapterId")+".html";
    String chapterFilePath = getServletContext().getRealPath("/") + chapterFileName;
    File chapterFile = new File(chapterFilePath);
    if(chapterFile.exists()){response.sendRedirect(chapterFileName);return;}//如果有这个文件就告诉浏览器转向
    INovelChapterBiz novelChapterBiz = new NovelChapterBizImpl();
    NovelChapter novelChapter = novelChapterBiz.searchNovelChapterById(Integer.parseInt(request.getParameter("chapterId")));//章节信息
    int lastPageId = novelChapterBiz.searchLastCHapterId(novelChapter.getNovelId().getId(), novelChapter.getId());
    int nextPageId = novelChapterBiz.searchNextChapterId(novelChapter.getNovelId().getId(), novelChapter.getId());
    request.setAttribute("novelChapter", novelChapter);
    request.setAttribute("lastPageId", lastPageId);
    request.setAttribute("nextPageId", nextPageId);
    new CreateStaticHTMLPage().createStaticHTMLPage(request, response, getServletContext(),
    chapterFileName, chapterFilePath, "/bookRead.jsp");
    }
    }
    生成HTML静态页面的类:

    package com.jb.y2t034.thefifth.web.servlet;
    import java.io.ByteArrayOutputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    /**
    * 创建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{
    response.setContentType("text/html;charset=gb2312");//设置HTML结果流编码(即HTML文件编码)
    RequestDispatcher rd = servletContext.getRequestDispatcher(jspPath);//得到JSP资源
    final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//用于从ServletOutputStream中接收资源
    final ServletOutputStream servletOuputStream = new ServletOutputStream(){//用于从HttpServletResponse中接收资源
    public void write(byte[] b, int off,int len){
    byteArrayOutputStream.write(b, off, len);
    }
    public void write(int b){
    byteArrayOutputStream.write(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;
    }
    };
    rd.include(request, httpServletResponse);//发送结果流
    printWriter.flush();//刷新缓冲区,把缓冲区的数据输出
    FileOutputStream fileOutputStream = new FileOutputStream(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来进行分布。或者干脆使用Redhat的GFS,优点是应用透明,缺点是费用较高。我是指
    你购买盘阵的问题。我的项目中,存储量是2-10Tb,我采用了分布式存储。这里要解决文件的复制和冗余。
    这样每个文件有不同的冗余,这方面可以参考google的gfs的论文。
    大文件的存储,可以参考nutch的方案,现在已经独立为Hadoop子项目。(你可以google it)

    其他:
    此外,passport等也是考虑的,不过都属于比较简单的了。
    四:高并发高负载网站的系统架构之图片服务器分离
    大家知道,对于Web 服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离,这是基本上大型网站都会采用的策略,他 们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为图片问题而崩溃,在应用 服务器和图片服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持,尽可能少的LoadModule, 保证更高的系统消耗和执行效率。


    利用Apache实现图片服务器的分离
    缘由:
    起步阶段的应用,都可能部署在一台服务器上(费用上的原因)
    第一个优先分离的,肯定是数据库和应用服务器。
    第二个分离的,会是什么呢?各有各的考虑,我所在的项目组重点考虑的节约带宽,服务器性能再好,带宽再高,并发来了,也容易撑不住。因此,我这篇文章的重点在这里。这里重点是介绍实践,不一定符合所有情况,供看者参考吧,
    环境介绍:
    WEB应用服务器:4CPU双核2G, 内存4G
    部署:Win2003/Apache Http Server 2.1/Tomcat6
    数据库服务器:4CPU双核2G, 内存4G
    部署:Win2003/MSSQL2000
    步骤:
    步骤一:增加2台配置为:2CPU双核2G,内存2G普通服务器,做资源服务器
    部署:Tomcat6,跑了一个图片上传的简单应用,(记得指定web.xml的<distributable/>),并指定域名为res1.***.com,res2.***.com,采用ajp协议
    步骤二:修改Apache httpd.conf配置
    原来应用的文件上传功能网址为:
    1、/fileupload.html
    2、/otherupload.html
    在httpd.conf中增加如下配置

    <VirtualHost *:80>
    ServerAdmin webmaster@***.com
    ProxyPass /fileupload.html balancer://rescluster/fileupload lbmethod=byrequests stickysession=JSESSIONID nofailover=Off timeout=5 maxattempts=3
    ProxyPass /otherupload.html balancer://rescluster/otherupload.html lbmethod=byrequests stickysession=JSESSIONID nofailover=Off timeout=5 maxattempts=3
    #<!--负载均衡-->
    <Proxy balancer://rescluster/>
    BalancerMember ajp://res1.***.com:8009 smax=5 max=500 ttl=120 retry=300 loadfactor=100 route=tomcat1
    BalancerMember ajp://res2.***.com:8009 smax=5 max=500 ttl=120 retry=300 loadfactor=100 route=tomcat2
    </Proxy>

    < /VirtualHost>
    步骤三,修改业务逻辑:
    所有上传文件在数据库中均采用全url的方式保存,例如产品图片路径存成:http://res1.***.com/upload/20090101/product120302005.jpg

    现在,你可以高枕无忧了,带宽不够时,增加个几十台图片服务器,只需要稍微修改一下apache的配置文件,即可。

    五:高并发高负载网站的系统架构之数据库集群和库表散列

    大型网站都有复杂的应用,这些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓶颈很快就能显现出来,这时一台数据库将很快无法满足应用,于是我们需要使用数据库集群或者库表散列。
      
      在数据库集群方面,很多数据库都有自己的解决方案,oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB,就参考相应的解决方案来实施即可。
      
       上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并 且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者 功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的 架构,将论坛的用户、设置、帖子等信息进行数据库分离,然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系 统随时增加一台低成本的数据库进来补充系统性能。


    集群软件的分类:
    一般来讲,集群软件根据侧重的方向和试图解决的问题,分为三大类:高性能集群(High performance cluster,HPC)、负载均衡集群(Load balance cluster, LBC),高可用性集群(High availability cluster,HAC)。
    高性能集群(High performance cluster,HPC),它是利用一个集群中的多台机器共同完成同一件任务,使得完成任务的速度和可靠性都远远高于单机运行的效果。弥补了单机性能上的不足。该集群在天气预报、环境监控等数据量大,计算复杂的环境中应用比较多;
    负载均衡集群(Load balance cluster, LBC),它是利用一个集群中的多台单机,完成许多并行的小的工作。一般情况下,如果一个应用使用的人多了,那么用户请求的响应时间就会增大,机器的性能也会受到影响,如果使用负载均衡集群,那么集群中任意一台机器都能响应用户的请求,这样集群就会在用户发出服务请求之后,选择当时负载最小,能够提供最好的服务的这台机器来接受请求并相应,这样就可用用集群来增加系统的可用性和稳定性。这类集群在网站中使用较多;
    高可用性集群(High availability cluster,HAC),它是利用集群中系统 的冗余,当系统中某台机器发生损坏的时候,其他后备的机器可以迅速的接替它来启动服务,等待故障机的维修和返回。最大限度的保证集群中服务的可用性。这类系统一般在银行,电信服务这类对系统可靠性有高的要求的领域有着广泛的应用。
    2 数据库集群的现状
    数据库集群是将计算机集群技术引入到数据库中来实现的,尽管各厂商宣称自己的架构如何的完美,但是始终不能改变Oracle当先,大家追逐的事实,在集群的解决方案上Oracle RAC还是领先于包括微软在内的其它数据库厂商,它能满足客户高可用性、高性能、数据库负载均衡和方便扩展的需求。
    Oracle’s Real Application Cluster (RAC)
    Microsoft SQL Cluster Server (MSCS)
    IBM’s DB2 UDB High Availability Cluster(UDB)
    Sybase ASE High Availability Cluster (ASE)
    MySQL High Availability Cluster (MySQL CS)
    基于IO的第三方HA(高可用性)集群
    当前主要的数据库集群技术有以上六大类,有数据库厂商自己开发的;也有第三方的集群公司开发的;还有数据库厂商与第三方集群公司合作开发的,各类集群实现的功能及架构也不尽相同。
    RAC(Real Application Cluster,真正应用集群)是Oracle9i数据库中采用的一项新技术,也是Oracle数据库支持网格计算环境的核心技术。它的出现解决了传统数据库应用中面临的一个重要问题:高性能、高可伸缩性与低价格之间的矛盾。在很长一段时间里,甲骨文都以其实时应用集群技术(Real Application Cluster,RAC)统治着集群数据库市场

    六:高并发高负载网站的系统架构之缓存

    缓存一词搞技术的都接触过,很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。
      架构方面的缓存,对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力。
       网站程序开发方面的缓存,Linux上提供的Memory Cache是常用的缓存接口,可以在web开发中使用,比如用Java开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享,一些大 型社区使用了这样的架构。另外,在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法,PHP有Pear的Cache模块,Java就更多 了,.net不是很熟悉,相信也肯定有。

    Java开源缓存框架
    JBossCache/TreeCache JBossCache是一个复制的事务处理缓存,它允许你缓存企业级应用数据来更好的改善性能。缓存数据被自动复制,让你轻松进行Jboss服务器之间的集群工作。JBossCache能够通过Jboss应用服务或其他J2EE容器来运行一个Mbean服务,当然,它也能独立运行。 JBossCache包括两个模块:TreeCache和TreeCacheAOP。 TreeCache --是一个树形结构复制的事务处理缓存。 TreeCacheAOP --是一个“面向对象”缓存,它使用AOP来动态管理POJO
    OSCache OSCache标记库由OpenSymphony设计,它是一种开创性的JSP定制标记应用,提供了在现有JSP页面之内实现快速内存缓冲的功能。OSCache是个一个广泛采用的高性能的J2EE缓存框架,OSCache能用于任何Java应用程序的普通的缓存解决方案。OSCache有以下特点:缓存任何对象,你可以不受限制的缓存部分jsp页面或HTTP请求,任何java对象都可以缓存。 拥有全面的API--OSCache API给你全面的程序来控制所有的OSCache特性。 永久缓存--缓存能随意的写入硬盘,因此允许昂贵的创建(expensive-to-create)数据来保持缓存,甚至能让应用重启。 支持集群--集群缓存数据能被单个的进行参数配置,不需要修改代码。 缓存记录的过期--你可以有最大限度的控制缓存对象的过期,包括可插入式的刷新策略(如果默认性能不需要时)。
    JCACHE JCACHE是一种即将公布的标准规范(JSR 107),说明了一种对Java对象临时在内存中进行缓存的方法,包括对象的创建、共享访问、假脱机(spooling)、失效、各JVM的一致性等。它可被用于缓存JSP内最经常读取的数据,如产品目录和价格列表。利用JCACHE,多数查询的反应时间会因为有缓存的数据而加快(内部测试表明反应时间大约快15倍)。
    Ehcache Ehcache出自hibernate,在Hibernate中使用它作为数据缓存的解决方案。
    Java Caching System JCS是Jakarta的项目Turbine的子项目。它是一个复合式的缓冲工具。可以将对象缓冲到内存、硬盘。具有缓冲对象时间过期设定。还可以通过JCS构建具有缓冲的分布式构架,以实现高性能的应用。 对于一些需要频繁访问而每访问一次都非常消耗资源的对象,可以临时存放在缓冲区中,这样可以提高服务的性能。而JCS正是一个很好的缓冲工具。缓冲工具对于读操作远远多于写操作的应用性能提高非常显著。
    SwarmCache SwarmCache是一个简单而功能强大的分布式缓存机制。它使用IP组播来有效地在缓存的实例之间进行通信。它是快速提高集群式Web应用程序的性能的理想选择。
    ShiftOne ShiftOne Object Cache这个Java库提供了基本的对象缓存能力。实现的策略有先进先出(FIFO),最近使用(LRU),最不常使用(LFU)。所有的策略可以最大化元素的大小,最大化其生存时间。
    WhirlyCache Whirlycache是一个快速的、可配置的、存在于内存中的对象的缓存。它能够通过缓存对象来加快网站或应用程序的速度,否则就必须通过查询数据库或其他代价较高的处理程序来建立。
    Jofti Jofti可对在缓存层中(支持EHCache,JBossCache和OSCache)的对象或在支持Map接口的存储结构中的对象进行索引与搜索。这个框架还为对象在索引中的增删改提供透明的功能同样也为搜索提供易于使用的查询功能。
    cache4j cache4j是一个有简单API与实现快速的Java对象缓存。它的特性包括:在内存中进行缓存,设计用于多线程环境,两种实现:同步与阻塞,多种缓存清除策略:LFU, LRU, FIFO,可使用强引用(strong reference)与软引用(soft reference)存储对象。
    Open Terracotta 一个JVM级的开源群集框架,提供:HTTP Session复制,分布式缓存,POJO群集,跨越群集的JVM来实现分布式应用程序协调(采用代码注入的方式,所以你不需要修改任何)。
    sccache SHOP.COM使用的对象缓存系统。sccache是一个in-process cache和二级、共享缓存。它将缓存对象存储到磁盘上。支持关联Key,任意大小的Key和任意大小的数据。能够自动进行垃圾收集。
    Shoal Shoal是一个基于Java可扩展的动态集群框架,能够为构建容错、可靠和可用的Java应用程序提供了基础架构支持。这个框架还可以集成到不希望绑定到特定通信协议,但需要集群和分布式系统支持的任何Java产品中。Shoal是GlassFish和JonAS应用服务器的集群引擎。
    Simple-spring-Memcached Simple-Spring-Memcached,它封装了对MemCached的调用,使MemCached的客户端开发变得超乎寻常的简单。

    展开全文
  • 利用zookeeper模拟实现HA高可用

    万次阅读 2019-06-19 19:16:26
    利用zookeeper模拟实现HA高可用 1、需求 在分布式场景中,对于主从架构来说,最大的问题就是单点故障。当学过zookeeper之后,我们都知道,可以利用zookeeper集群来帮助实现Hadoop的HA,那到底Hadoop的HA是如何...
  • java实现发送短信(亲测可用)

    千次阅读 2018-08-31 11:57:55
    TextDemo.java   public class TextDemo { public static void main(String [] args){ execute(); } private static String operation = "/industrySMS/sendSMS"; private static String ...
  • java实现websocket client

    千次下载 热门讨论 2013-11-08 17:47:12
    java_websocket.jar最新jar包 可用java实现websocket客户端,使用demo: https://github.com/TooTallNate/Java-WebSocket/blob/master/src/main/example/ExampleClient.java
  • JAVA实现扫雷游戏

    万次阅读 多人点赞 2019-06-04 12:56:48
    学习完java事件处理.........Java语言实现的扫雷游戏(一) Java语言实现的扫雷游戏(二) 先把代码贴出来,需要注意的东西都写在注释里了,有空把教程写出来 package sixth; import javax.swing.*...
  • ... public class SevenZDiskUtilTester { public static void main(String[] args) throws Exception { String srcDirPath = "C:/Users/Administrator/Downloads/个人文件/7z-test";... String tarFilePath = "C:/...
  • zookeeper实现分布式高可用

    千次阅读 2018-11-23 09:37:42
    我们通常部署zookeeper集群来实现高可用性,那么zookeeper是如何实现高可用性的呢? 集群组成 要搭建一个高可用的 ZooKeeper 集群,我们首先需要确定好集群的规模。关于 ZooKeeper 集群的服务器组成,相信很多对 ...
  • 先来看下java连接redis主从结构图: redis主从 ...Sentinel(哨兵)是Redis高可用性的解决方案,一个或者多个sentinel实例监视任意多个主服务器及其从服务器。sentinel每隔1秒向master发送【ping...
  • 如何用最简单的方法来搭建一个效率可用的服务端JAVA呢? 停工的原因一般有: 服务器故障。例如服务器宕机,服务器网络出现问题,机房或者机架出现问题等;访问量急剧上升,导致服务器压力过大导致访问量急剧...
  • JAVA发送手机短信,流传有几种方法:(1)使用webservice接口发送手机短信,这个可以使用sina提供的webservice进行发送,但是需要进行注册;(2)使用短信mao的方式进行短信的发送,这种方式应该是比较的常用,前提是需要购买...
  • —————————————————————————————————————————————————–java架构师项目实战,并发集群分布式,大数据高可用视频教程,共760G下载地址:... 02.Java高级系统培训架构...
  • Java实现ping ip

    千次阅读 2018-04-24 20:45:44
    Java实现ping功能的三种方法检测设备的运行状态,有的是使用ping的方式来检测的。所以需要使用java来实现ping功能。为了使用java来实现ping的功能,有人推荐使用java的 Runtime.exec()方法来直接调用系统的Ping命令,也...
  • Java与Netty实现高性能并发

    万次阅读 2017-02-13 14:36:11
    最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于Java序列化+BIO(同步阻塞IO)的通信框架,性
  • 使用Java实现串口通信

    万次阅读 多人点赞 2016-08-24 17:07:16
    1.介绍使用Java实现的串口通信程序,支持十六进制数据的发送与接收。 效果图如下: 2.RXTXcommJava串口通信依赖的jar包RXTXcomm.jar 下载地址:http://download.csdn.net/detail/kong_gu_you_lan/9611334内含32位...
  • 有状态配置可通过配置中⼼实现⽆状态 实践: Disconf、Yaconf、Zookpeer、Consul、Confd、Diamond、Xdiamond等 拆分: 系统维度:按照系统功能、业务拆分,如购物⻋,结算,订单等 功能维度:对系统功能在做细粒度...
  • Redis Sentinel高可用集群Java客户端

    万次阅读 2015-04-10 16:57:12
    java客户端Jedis在2.2.2及以上版本实现了对Sentinel的支持,介绍开源项目sharded-jedis-sentinel-pool,能及时感知所有分片主从切换行为,进行连接池重建。
  • 根据《SpringCloud微服务实战》第三章,使用SpringBoot 2.0.1.RELEASE版本,对应的SpringCloud版本为...所以我们需要构建高可用的服务注册中心以增强系统的可用性。 在Eureka的服务治理设计中,所有节点即是服...
  • Nginx实现微服务网关高可用方案

    千次阅读 2020-02-10 15:58:36
    Nginx实现微服务网关高可用方案 作者:杨文培** **版本:**v1.0 **时间:**2020年2月10日 一、微服务的高可用方案 在微服务架构中,为保证微服务的并发和高可用,在不同的服务器中部署多个微服务实例并注册到...
  • 从单体到集群系列目录 从单体到集群(1) - 使用Nginx配置静态资源并搭建Tomcat集群 从单体到集群(2) - keepalived+Nginx实现高可用集群 从单体到集群(3) - LVS+Keepalived+Nginx实现高可用集群负载均衡 -------------...
  • Java校验url是否可用

    千次阅读 2017-05-23 14:25:29
    使用java.net 下的URL类来实现,URL 是统一资源标识符的引用,一个URL实例代表着一个url的引用,然后使用了URL中的的openStream()方法。 java代码: import java.io.InputStream; import java.net.URL; public ...
  • 扫雷游戏(java实现)java小程序

    万次阅读 多人点赞 2018-08-08 08:50:41
    学了两周的java,想着做点东西玩玩,萌生了写一个扫雷的想法,这个想法其实在学c语言时就有了,当时并不知道c也有图形库,在后来就搁置了,最近看了大概两周的java,刚好看完 java Swing图形界面,老师说应该做个小...
  • ... /** * @author Securitit. * @note ZipDiskUtil工具类测试. */ public class ZipDiskUtilTester { ... public static void main(String[] args) throws Exception { ZipDiskUtil.compressByZip("C:/Users/...
  • Java实现Ping命令

    万次阅读 2018-09-18 11:06:47
    在项目中需要判断目录服务器是否在线,需要用到ping命令,调研有两种方法: ...自Java 1.5开始,java.net包中就实现了ping的功能。详见InetAddress.isReachable()方法。 public static boolea...
  • java 实现 生成短链接服务

    千次阅读 2020-06-24 14:19:24
    短链接生成的java常用实现
  • 默认情况下,standalone cluster manager对于worker节点的失败是具有容错性的(迄今为止,Spark自身而言对于丢失部分计算工作是有容错性的,它会将丢失的计算...为了解决这个问题,spark提供了两种高可用性方案,...
  •   GZip是常用的无损压缩算法实现,在Linux中较为常见,像我们在Linux安装软件时,基本都是.tar.gz格式。.tar.gz格式文件需要先对目录内文件进行tar压缩,然后使用GZip进行压缩。   本文针对基于磁盘的压缩和解压...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 513,338
精华内容 205,335
关键字:

java实现高可用

java 订阅