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. ...
随机推荐
- jdbc如何锁定某一条数据或者表,不让别人操作?
jdbc如何锁定某一条数据或者表,不让别人操作? 只有并发的时候才会有死锁,你要把多个涉及到这个表的地方检查一下,排除死锁可能. 为了避免修改冲突,所以我要锁定.请问该如何实现 答: 例如:selec ...
- Fiddler2 中文手册
原文:http://blog.sina.com.cn/s/blog_66a13b8f0100vgfi.html 最近一阵研究 Fiddler2 的使用来着,一开始看起来有点找不着北,索性就根据官网资料 ...
- c#封装三维向量,另外也看了下别人的C++封装
一. c#实现 /* Vector3 Definition Created by taotao man on 2016-4-12 brief:封装三位向量类Vector3 // 修改记录: date: ...
- DevExpress Winform 通用控件打印方法(允许可自定义边距) z
DevExpress Winform 通用控件打印方法,包括gridcontrol,treelist,pivotGridControl,ChartControl,LayoutControl...(所有 ...
- jquery通过ajax提交form
$.ajax({ type: "POST", url: "some.php", data: "name=John&location=Bosto ...
- Android之获取内外部存储器的容量
先来了解一下存储卡的相关知识: 我们新购买的磁盘或SD卡在使用之前,要让操作系统认得它,须先写入一些磁性的记号到磁盘上的每一扇区,便可在该操作系统下取用磁盘上的数据,这个过程就是格式化. 格式化可以直 ...
- Python学习(四)数据结构 —— list tuple range
序列类型 list tuple range list 和 tuple list: 列表,由 [] 标识: 有序:可改变列表元素 tuple: 元组,由 () 标识: 有序:不可改变元组元素(和 ...
- spring mvc 基于注解 配置默认 handlermapping
spring mvc 是类似于 Struts 的框架.他们都有一个最主要的功能就是URL路由.URL路由能将请求与响应请求处理逻辑的类(在Struts中即是action,在spring mvc 中即是 ...
- Spark Streaming:大规模流式数据处理的新贵(转)
原文链接:Spark Streaming:大规模流式数据处理的新贵 摘要:Spark Streaming是大规模流式数据处理的新贵,将流式计算分解成一系列短小的批处理作业.本文阐释了Spark Str ...
- 【Python】Django filter 如何支持 or 条件过滤?
from django.db.models import Q Item.objects.filter(Q(creator=owner) | Q(moderated=False)) 代码示例: if(r ...