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 例如以下:
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 的集成开发的更多相关文章
- neurosolutions 人工神经网络集成开发环境 keras
人工神经网络集成开发环境 : http://www.neurosolutions.com/ keras: https://github.com/fchollet/keras 文档 http ...
- windows和linux中搭建python集成开发环境IDE——如何设置多个python环境
本系列分为两篇: 1.[转]windows和linux中搭建python集成开发环境IDE 2.[转]linux和windows下安装python集成开发环境及其python包 3.windows和l ...
- 【超全整理】J2EE集成开发环境MyEclipse使用心得汇总
一.首先我们为什么需要MyEclipse? 下面允许我做一些简要的介绍: 应该大家都知道另一个MyEclipse的近亲——Eclipse的优点:免费.程序代码排版功能.有中文汉化包.可增设许多功能强大 ...
- 【Python基础学习一】在OSX系统下搭建Python语言集成开发环境 附激活码
Python是一门简单易学,功能强大的编程语言.它具有高效的高级数据结构和简单而有效的面向对象编程方法.Python优雅的语法和动态类型以及其解释性的性质,使它在许多领域和大多数平台成为编写脚本和快速 ...
- 使用IntelliJ IDEA 13搭建Android集成开发环境(图文教程)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
- 【转】windows和linux中搭建python集成开发环境IDE
本系列分为两篇: 1.[转]windows和linux中搭建python集成开发环境IDE 2.[转]linux和windows下安装python集成开发环境及其python包 3.windows和l ...
- 【转】linux和windows下安装python集成开发环境及其python包
本系列分为两篇: 1.[转]windows和linux中搭建python集成开发环境IDE 2.[转]linux和windows下安装python集成开发环境及其python包 3.windows和l ...
- Windows下的Objective-C集成开发环境(IDE)(转)
Objective-C是苹果软件的编程语言,想要上机学习.调试,有一个集成开发环境(IDE)方便很多.有三类方法搭建Objective-C的集成开发环境: 1) 使用苹果的平台,集成开发环境使用X ...
- Linux搭建Scrapy爬虫集成开发环境
安装Python 下载地址:http://www.python.org/, Python 有 Python 2 和 Python 3 两个版本, 语法有些区别,ubuntu上自带了python2.7. ...
随机推荐
- redis cluster 设置密码做集群时gem下client.rb文件修改
redis节点有设置密码,然后在创建集群的时候没有设置密码的命令 ./redis-trib.rb create --replicas 1 127.0.0.1:6381 127.0.0.1:6382 1 ...
- 安装完Framework后如何不重启系统?
在.net平台下客户端部署时,如果客户端没有安装Framework时,部署程序安装Framework后,有一个要求重启选项,当然是非强制的.如果不想出现这个提示“重启”选项,可以做如下选择: 1.启动 ...
- Selenium2+python自动化70-unittest之跳过用例(skip)
前言 当测试用例写完后,有些模块有改动时候,会影响到部分用例的执行,这个时候我们希望暂时跳过这些用例. 或者前面某个功能运行失败了,后面的几个用例是依赖于这个功能的用例,如果第一步就失败了,后面的用例 ...
- Spring Bean 注入 2 注解篇
1. 自动装配注解 配置applicationContext.xml开启注解 <?xml version="1.0" encoding="UTF-8"?& ...
- zedboard--基于zedboard的demo系统的boa服务器搭建(二十一)
zedboard提供的demo系统很迷你,但是也能移植嵌入式Web服务器的.这里就移植boa服务器. 1.下载Boa服务器源代码(安装好了交叉编译器) http://www.boa.org/,选择最后 ...
- 了解Redis 和 Memcached 的区别
1.Redis支持服务器端的数据操作:Redis相比Memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去. ...
- 用Sass创建MetaFizzy效果
来源:GBin1.com Hugo发现了一个绚丽的css效果应用于web中并教会你如何聪明的重建和使用它.两天前,我看见笔者Hugo在css帮助下重写MetaFizzy的效果,Hugo帮助我们找到了一 ...
- 裸裸的线段树(hdu 1754)
线段树的第一发. 哪天忘了还能够让自己找找回顾. 线段树操作: build : 建树. update:点改动: query:查询 Input 在每一个測试的第一行,有两个正整数 N 和 M ( 0& ...
- STL - 函数作为算法的参数
函数作为参数,相当于C++的函数指针, C#的委托 for_each函数参数: #include <iostream> #include <algorithm> #includ ...
- 在div 底部显示背景图片
下面代码实现div层背景图片在底部显示: div { background : url (/images/bg.jpg) no-repeat fixed ; background-position-y ...