zoukankan      html  css  js  c++  java
  • Ribbon 和 wowza 的集成开发

            前言
            Ribbon 是提供 REST 服务的区域感知负载均衡器,它在 wowza 的前端,应该部署在专业的 REST 容器下,而不是流媒体服务器 wowza 下。

    本文介绍了 Ribbon 和 wowza 的集成,Ribbon 作为 wowza 的一个插件部署在了 wowza 容器下,仅供 Ribbon 开发、部署的技术參考,现实中绝不可能出现这样的情况。由于 Wowza 毕竟不是专业提供 REST 服务的容器。关于 Ribbon 和 Wowza 真实场景的架构部署,请关注作者兴许博客。
            本文是在《让你的 wowza 服务器提供 RESTful web 服务》样例的基础上进一步进行研发。
            1. 新建 maven 项目
            參考《让你的 wowza 服务器提供 RESTful web 服务》步骤。新建的 maven 项目 defonds-server-module 例如以下:
    新建好的mvn项目
            2. 编辑 Ribbon 配置文件
            依据你自己的集群。配置 Ribbon。比方作者 demo 用的配置文件例如以下:

    # Max number of retries on the same server (excluding the first try)
    sample-client.ribbon.MaxAutoRetries=1
    
    
    # Max number of next servers to retry (excluding the first server)
    sample-client.ribbon.MaxAutoRetriesNextServer=1
    
    
    # Whether all operations can be retried for this client
    sample-client.ribbon.OkToRetryOnAllOperations=true
    
    
    # Interval to refresh the server list from the source
    sample-client.ribbon.ServerListRefreshInterval=2000
    
    
    # Connect timeout used by Apache HttpClient
    sample-client.ribbon.ConnectTimeout=3000
    
    
    # Read timeout used by Apache HttpClient
    sample-client.ribbon.ReadTimeout=3000
    
    
    # Initial list of servers, can be changed via Archaius dynamic property at runtime
    sample-client.ribbon.listOfServers=www.baidu.com:80,www.163.com:80,www.csdn.net:80

            然后把这个文件放在你的 classpath 下。
            3. 编写 LB 调用类
    package com.defonds.wms.module.server;
    
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.URI;
    import java.net.URISyntaxException;
    
    
    import com.netflix.client.ClientException;
    import com.netflix.client.ClientFactory;
    import com.netflix.client.http.HttpRequest;
    import com.netflix.client.http.HttpResponse;
    import com.netflix.config.ConfigurationManager;
    import com.netflix.niws.client.http.RestClient;
    import com.wowza.wms.http.HTTProvider2Base;
    import com.wowza.wms.http.IHTTPRequest;
    import com.wowza.wms.http.IHTTPResponse;
    import com.wowza.wms.logging.WMSLogger;
    import com.wowza.wms.logging.WMSLoggerFactory;
    import com.wowza.wms.vhost.IVHost;
    
    
    public class RibbonLBRestService extends HTTProvider2Base {
    	private static final WMSLogger logger = WMSLoggerFactory.getInstance().getLoggerObj(RibbonLBRestService.class.getName());
    	public static RestClient restClient = null;
    	
    	static {
    		try {
    			// Load the properties file using Archaius ConfigurationManager
    			ConfigurationManager.loadPropertiesFromResources("sample-client.properties"); 
    			// Use ClientFactory to create client and the load balancer
    			RibbonLBRestService.restClient = (RestClient) ClientFactory.getNamedClient("sample-client");  
    		} catch (IOException e) {
    			logger.error(e.getMessage(), e);
    		}  
    		
    	}
    	
    	@Override
    	public void onHTTPRequest(IVHost arg0, IHTTPRequest request, IHTTPResponse response) {
    		String jsonObject = null;
    		response.setHeader("Content-Type", "application/json");
    		try {
    			String serverURI = RibbonLBRestService.getURI();
    			response.setResponseCode(200);
    			jsonObject = "{"server_uri":"" + serverURI + ""}";
    		} catch (ClientException e2) {
    			response.setResponseCode(400);
    			jsonObject = "{"error_code":"40039"}";
    			logger.error(e2.getMessage(), e2);
    			
    		} catch (URISyntaxException e3) {
    			response.setResponseCode(400);
    			jsonObject = "{"error_code":"40023"}";
    			logger.error(e3.getMessage(), e3);
    		} finally {
    			// Get the printwriter object from response to write the required json object to the output stream      
    			OutputStream out = response.getOutputStream();
    			try {
    				out.write(jsonObject.getBytes());
    				out.flush();
    			} catch (IOException e) {
    				logger.error(e.getMessage(), e);
    			}
    		}
    		
    	}
    	
    	public synchronized static String getURI() throws ClientException, URISyntaxException {
    		// Build the http request using the builder
    		// Note that we only supply the path part (“/”) of the URI
    		// The complete URI will be computed by the client once the server is chosen by the load balancer
    		HttpRequest ribbonRequest = HttpRequest.newBuilder().uri(new URI("/")).build(); 
            HttpResponse ribbonResponse;
            // Call client.executeWithLoadBalancer() API, not the execute() API
    		ribbonResponse = RibbonLBRestService.restClient.executeWithLoadBalancer(ribbonRequest); 
    		return ribbonResponse.getRequestedURI().toString();
    	}
    	
    	public synchronized static void changeServersPoolDynamically(String serverList) throws ClientException {
            // Dynamically change the server pool from the configuration
            ConfigurationManager.getConfigInstance().setProperty(
            		"sample-client.ribbon.listOfServers", serverList); 
            logger.debug("changing servers ...");
            try {
            	// Wait until server list is refreshed (2 seconds refresh interval defined in properties file)
    			Thread.sleep(3000); 
    		} catch (InterruptedException e) {
    			logger.error(e.getMessage(), e);
    		} 
    	}
    
    
    }

            这个类将会给 ribbonLB 的 REST 请求返回一台服务器地址。假设请求失败,返回对应的错误码。

    这个类还提供了一个公开方法,用于动态调整负载均衡节点。
            4. 编写动态改动负载均衡节点接口

    package com.defonds.wms.module.server;
    
    
    import java.io.IOException;
    import java.io.OutputStream;
    
    
    import com.netflix.client.ClientException;
    import com.wowza.wms.http.HTTProvider2Base;
    import com.wowza.wms.http.IHTTPRequest;
    import com.wowza.wms.http.IHTTPResponse;
    import com.wowza.wms.logging.WMSLogger;
    import com.wowza.wms.logging.WMSLoggerFactory;
    import com.wowza.wms.vhost.IVHost;
    
    
    public class RibbonChangeInstanceService extends HTTProvider2Base {
    	private static final WMSLogger logger = WMSLoggerFactory.getInstance().getLoggerObj(RibbonChangeInstanceService.class.getName());
    	
    	@Override
    	public void onHTTPRequest(IVHost arg0, IHTTPRequest request, IHTTPResponse response) {
    		String serverList = request.getParameter("server_list");
    		
    		// TODO Authorization
    		
    		// TODO serverList str check
    		
    		String jsonObject = null;
    		response.setHeader("Content-Type", "application/json");
    		try {
    			RibbonLBRestService.changeServersPoolDynamically(serverList);
    			response.setResponseCode(200);
    			jsonObject = "{"error_code":"0"}"; // server list is changed successfully
    		} catch (ClientException e2) {
    			response.setResponseCode(400);
    			jsonObject = "{"error_code":"40039"}";
    			logger.error(e2.getMessage(), e2);
    		} finally {
    			// Get the printwriter object from response to write the required json object to the output stream      
    			OutputStream out = response.getOutputStream();
    			try {
    				out.write(jsonObject.getBytes());
    				out.flush();
    			} catch (IOException e) {
    				logger.error(e.getMessage(), e);
    			}
    		}
    		
    	} 
    
    
    }

            这个类提供了一个用于动态改动负载均衡节点池的接口。假设改动成功返回错误码为 0,否则为其它值。

            5. 编辑 maven 依赖

            编辑项目 pom.xml。将上边依赖到的包导入:

    		<!-- ribbon -->
    		<dependency>
    			<groupId>com.netflix.ribbon</groupId>
    			<artifactId>ribbon-core</artifactId>
    			<version>0.3.12</version>
    		</dependency>
    		<dependency>
    			<groupId>com.netflix.ribbon</groupId>
    			<artifactId>ribbon-httpclient</artifactId>
    			<version>0.3.12</version>
    		</dependency>

            6. 编辑 VHost.xml
            编辑 %wowza%/conf/VHost.xml,把上边写的两个 HTTPProvider 加入进去:
    					<HTTPProvider>
    						<BaseClass>com.defonds.wms.module.server.RibbonLBRestService</BaseClass>
    						<RequestFilters>ribbonLB*</RequestFilters>
    						<AuthenticationMethod>none</AuthenticationMethod>
    					</HTTPProvider>
    					<HTTPProvider>
    						<BaseClass>com.defonds.wms.module.server.RibbonChangeInstanceService</BaseClass>
    						<RequestFilters>ribbonChange*</RequestFilters>
    						<AuthenticationMethod>none</AuthenticationMethod>
    					</HTTPProvider>

            7. 项目又一次打包部署
            命令行切换到你的 defonds-server-module 项目文件夹下,运行
    mvn package
            8. 訪问接口

            debug 启动 defonds-server-module,然后在浏览器訪问 http://localhost:1935/ribbonLB,以向 Ribbon 要一个服务器地址,返回结果例如以下:
    {"server_uri":"http://www.csdn.net:80/"}
            返回的是服务器 URL 是 http://www.csdn.net:80/。然后在浏览器訪问 http://localhost:1935/ribbonChange?server_list=www.qq.com:80,www.126.com:80。以动态调整负载均衡节点。返回结果例如以下:
    {"error_code":"0"}
            这个返回码说明已经调整成功。我们能够继续訪问 http://localhost:1935/ribbonLB 验证一下,返回结果是:
    {"server_uri":"http://www.qq.com:80/"}
            没错,确实成功了。


            注意
            以上 Ribbon 动态调整的负载均衡节点是内存里的配置。服务器下的 sample-client.properties 配置的节点依然是:

    sample-client.ribbon.listOfServers=www.baidu.com:80,www.163.com:80,www.csdn.net:80

            这样 REST 服务重新启动后。读取的负载均衡节点依然是改动前的。假设你想在 REST 服务器断电重新启动后读取改动后的。最好把 Ribbon 属性在分布式缓存服务器中进行存放和读取,比方 Redis。

    另:本文演示样例代码已上传 CSDN 资源。下载地址:http://download.csdn.net/detail/defonds/7526359

  • 相关阅读:
    wxpython笔记:应用骨架
    go 优雅的检查channel关闭
    Golang并发模型:流水线模型
    go http数据转发
    go 互斥锁与读写锁
    go 工作池配合消息队列
    实现Tcp服务器需要考虑哪些方面
    go Goroutine泄露
    关于个人博客转移的那些事
    Java并发编程:Thread类的使用介绍
  • 原文地址:https://www.cnblogs.com/llguanli/p/6773734.html
Copyright © 2011-2022 走看看