前言
        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 例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVmb25kcw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="新建好的mvn项目" align="middle" />
        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

Ribbon 和 wowza 的集成开发的更多相关文章

  1. neurosolutions 人工神经网络集成开发环境 keras

    人工神经网络集成开发环境 :  http://www.neurosolutions.com/ keras:   https://github.com/fchollet/keras 文档    http ...

  2. windows和linux中搭建python集成开发环境IDE——如何设置多个python环境

    本系列分为两篇: 1.[转]windows和linux中搭建python集成开发环境IDE 2.[转]linux和windows下安装python集成开发环境及其python包 3.windows和l ...

  3. 【超全整理】J2EE集成开发环境MyEclipse使用心得汇总

    一.首先我们为什么需要MyEclipse? 下面允许我做一些简要的介绍: 应该大家都知道另一个MyEclipse的近亲——Eclipse的优点:免费.程序代码排版功能.有中文汉化包.可增设许多功能强大 ...

  4. 【Python基础学习一】在OSX系统下搭建Python语言集成开发环境 附激活码

    Python是一门简单易学,功能强大的编程语言.它具有高效的高级数据结构和简单而有效的面向对象编程方法.Python优雅的语法和动态类型以及其解释性的性质,使它在许多领域和大多数平台成为编写脚本和快速 ...

  5. 使用IntelliJ IDEA 13搭建Android集成开发环境(图文教程)

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  6. 【转】windows和linux中搭建python集成开发环境IDE

    本系列分为两篇: 1.[转]windows和linux中搭建python集成开发环境IDE 2.[转]linux和windows下安装python集成开发环境及其python包 3.windows和l ...

  7. 【转】linux和windows下安装python集成开发环境及其python包

    本系列分为两篇: 1.[转]windows和linux中搭建python集成开发环境IDE 2.[转]linux和windows下安装python集成开发环境及其python包 3.windows和l ...

  8. Windows下的Objective-C集成开发环境(IDE)(转)

    Objective-C是苹果软件的编程语言,想要上机学习.调试,有一个集成开发环境(IDE)方便很多.有三类方法搭建Objective-C的集成开发环境: 1)   使用苹果的平台,集成开发环境使用X ...

  9. Linux搭建Scrapy爬虫集成开发环境

    安装Python 下载地址:http://www.python.org/, Python 有 Python 2 和 Python 3 两个版本, 语法有些区别,ubuntu上自带了python2.7. ...

随机推荐

  1. CloudStack 4.0.2 vRouter导致重启后状态不正常

    最近总玩CloudStack + KVM,发现在重启CloudStack服务后,host(kvm)的状态老是为alert.日志里出现如下错误提示: ERROR [agent.manager.Agent ...

  2. Python学习(四)数据结构 —— int float

    Python 数字类型 int float 数字常量 int: 一般的整数, long:   长整型,2.x版本需在数字后加 “L” 或 “l” ,表示长整型 如 100000000L: python ...

  3. JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别以及接口里default方法

    使用大写字母A,B,C,D......X,Y,Z定义的,就都是泛型,把T换成A也一样,这里T只是名字上的意义而已 ? 表示不确定的java类型 T (type) 表示具体的一个java类型 K V ( ...

  4. linux系统安装gcc

    安装nginx时会遇到错误提示gcc: command not found,需要先安装gcc 在centos7上安装成功. # yum group list # yum group install & ...

  5. java 中函数的参数传递详细介绍

    java中函数的参数传递 总结: 1.将对象(对象的引用)作为参数传递时传递的是引用(相当于指针).也就是说函数内对参数所做的修改会影响原来的对象.  2.当将基本类型或基本类型的包装集作为参数传递时 ...

  6. C#模拟MSN窗体抖动

    C#模拟MSN窗体抖动 窗体抖动是件很有意思的事情,就让我们看看一起来看看它的原理吧. 其实是生成随机数,然后改变Form的左上角的坐标.我用的是循环来弄得,其实可以用timer来控制. 我把抖动分成 ...

  7. springmvc+jsp引用本地图片文件

    1.图片文件路径,注意图片文件夹和WEB-INFO文件夹同级 2.web.xml配置 <servlet-mapping> <servlet-name>default</s ...

  8. cannot resolve symbol AppCompatActivity 心得

    新建Active 默认用的AppCompatActivity竟然报错cannot resolve symbol AppCompatActivity,网上找了半天,最后在朋友的帮助下解决,记录下 一.导 ...

  9. 【转】word排版宏的使用

    原文: https://blog.csdn.net/bruce_shan/article/details/73302756 -------------------------------------- ...

  10. 【pyhon】nvshens图片批量下载爬虫1.01

    # nvshens图片批量下载爬虫1.01 # 原先版本在遇到网络故障时回下载不全,这回更改了模式使得下载不成就重新下载,直到全部下载完毕 from bs4 import BeautifulSoup ...