• 【转】Nginx与长连接服务—低延迟信息推送


    http://bigtoy4boy.com/blog/tag/nginx/

    服务器推送(Server Push)是高效的、延迟低的数据交换方式。如果数据发送端与接收端都在互联网中公开可见,可以使用PubSubHubbubsimpler Webhook等方法完成任务。但是如果数据接收方在防火墙内、在内网或它只是一个浏览器(只可以向外发送数据请求,无法处理传入的数据),则实现服务器推送就更难了。如果你有冒险精神,你可以建立一个反向HTTP服务器。如果你寻求可靠的解决方案,也许你要等待HTML5的WebSocket’s API特性了。但如果你需要即刻可以实现的解决方案,你可以妥协一下,使用异步推送模式来代替,你可以使用Comet,也被称为反向Ajax、HTTP服务器推送或HTTP流。

    早在2006年Alex Russel提出了一个不坏的技术思路,那就是长连接(Comet)概念:从客户端发起并保持一个连接直到数据出现并传送(long polling),或者永远保持一个连接,通过它推送数据到客户端(streaming)。这两种方法的好处是数据传送非常及时。因此长连接技术广泛用于聊天应用(Facebook, Google, Meebo等)以及实现即时触发的机制。

    Nginx变成一个长连接服务器

    实现长连接服务比较大的问题是特殊的隐形需求以及事件驱动web服务器能否高效处理众多的长连接。Friendfeed的Tornado服务器是一个标准应用级服务器的好例子。另外,感谢Leo Ponomarev的努力,你现在可以用nginx_http_push_module插件使你的Nginx服务器变身成为一台完全功能的长连接服务器。

    使用自定义的一套框架结构,Leo的插件只提供两个对外的接口:一个是订阅者,一个是发布者。客户端连接Nginx服务器,创建针对一个频道的long-polling长连接并等待数据。同时,发布者只是简单的将数据使用POST方法提交给Nginx,插件收到数据后将它一个个发给等待的客户端。这表明发布者不需要直接传递数据,它只是一个简单的事件产生器!没有比这个更简单的方法了。

    还有更高的功能是,客户端和发布端可以建立任意的频道,并且插件也提供消息队列功能,这表明Nginx服务器会在客户端断线的情况下临时保存消息。队列消息可以按照时间、等待列表长度或内存限制大小来失效释放。

    NginxRuby配置例子

    一开始,你需要从源代码编译一个Nginx。解压源代码包,从GitHub获取插件的源码并放入Nginx的源码目录,然后使用下面的参数编译(./configure –add-module=/path/to/plugin && make && make install)。下一步,参考readme文件和协议文件,了解所有的参数选项。一个多客户端接收信息的配置例子如下:

    内部发布点(保证私有或不对外公开)

    location /publish {

    set $push_channel_id $arg_id;      #/?id=239aff3 或类似的文本标示

    push_sender;

    push_store_messages on;            打开消息队列

    push_message_timeout 2h;           # 2小时后消息失效

    push_max_message_buffer_length 10; 保存10条消息

    push_min_message_recipients 0;     清除前最小接收人数目

    }

    公开的长连接接收点

    location /activity {

    push_listener;

    一个频道编号能有多少客户端同时连接

    # – last: 只有最频繁请求的客户端能保持,其它连接返回409

    # – first: 只有最早连接的那个客户端可以保持,其它连接返回409

    # – broadcast: 任何数量的客户端连接都会是长连接

    push_listener_concurrency broadcast;

    set $push_channel_id $arg_id;

    default_type text/plain;

    }

    当你编译配置好你的Nginx服务器,并且启动它,我们可以建立一个简单的广播场景,一个数据发送广播方,几个订阅信息接收方来测试我们的长连接服务器。

    require ‘rubygems’

    require ‘em-http’

    def subscribe(opts)

    listener = EventMachine::HttpRequest.new(‘http://127.0.0.1/activity?id=’+ opts[:channel]).get :head => opts[:head]

    listener.callback {

    打印所获取的内容,并重新订阅这个频道

    使用last-modified头去忽略之前已经获取的数据。

    puts “Listener recieved: ” + listener.response + “\\n”

    modified = listener.response_header['LAST_MODIFIED']

    subscribe({:channel => opts[:channel]:head => {‘If-Modified-Since’ => modified}})

    }

    end

    EventMachine.run {

    channel = “pub”

    每5秒钟发布一个新的消息

    EM.add_periodic_timer(5) do

    time = Time.now

    publisher = EventMachine::HttpRequest.new(‘http://127.0.0.1/publish?id=’+channel).post :body => “Hello @ #{time}”

    publisher.callback {

    puts “Published message @ #{time}”

    puts “Response code: ” + publisher.response_header.status.to_s

    puts “Headers: ” + publisher.response_header.inspect

    puts “Body: \\n” + publisher.response

    puts “\\n”

    }

    end

    打开两个客户端

    subscribe(:channel => channel)

    subscribe(:channel => channel)

    }

    nginx-push.zip (完整的Nginx配置和Ruby代码)

    在上面的代码中,每5秒钟数据发布端向Nginx服务器发出新的事件,服务器将数据通过长连接转发给两个订阅的客户端。当消息发送到客户端,服务器会断开他们的连接,客户端会立即重连并等待下一次数据的到来。结果就是使用Nginx实现了一个数据发布端到客户端的实时消息推送机制!

    期待生产环境下的长连接服务

    Leo的模块还在开发期,还需要时间来稳定下来,但它是一个需要关注的项目。最近的更新计划都着重于bug修复,未来的计划里有描述要加入流的模式:代替现在每次数据获取后都要重连的情况(long polling),Nginx会保持连接,将数据一段段的实时传送给客户端。拥有这个功能后你能很方便的部署你自己的信息触发式API(例如:Twitter流)。

    最后,不要忘记数字不断增长的其它Nginx模块,或者如果你感兴趣的话,可以参考Evan Miller编写的指引来开发自己的Nginx模块。

  • 相关阅读:
    使用IDEA创建SpringMVC项目
    Spring基于注解的配置——@Required、@Autowired、@Qualifier示例及与传统注入方法的对比
    Spring基于构造函数和设值函数的依赖注入
    Mysql——通配符和正则表达式的使用
    Spring Bean的生命周期、后置处理器、定义继承
    Spring Bean的定义及作用域
    MySql——使用where子句过滤数据
    MySql——创建数据表,查询数据,排序查询数据
    MySQL的安装+可视化工具+JDBC的增删改查
    slave_master_info和slave_relay_log_info中的Master_log_pos不一致
  • 原文地址:https://www.cnblogs.com/rywx/p/2489184.html
Copyright © 2020-2023  润新知