发明内容
本发明的目的是:针对现有技术的上的缺陷,提供一种基于Websocket实现消息推送的方法,实现消息的统一快速发送,以克服现有技术的不足。
本发明的技术方案
一种基于Websocket实现消息推送的方法,其特征在于:该方法采用redis实现消息存储,消息队列管理,通过websocket实现服务端与客户端的通讯,从而实现消息统一管理,统一发送渠道。
前述的一种基于Websocket实现消息推送的方法中,具体步骤为:
一、客户端client调用Login中的登录接口实现登录,login服务端通过人员Map查询得到登录人员分配的send消息服务器,并返回给登录人员;
二、登录人员得到分配的send服务器后,通过websocket技术与send服务器第一次握手,打开消息通道;
三、业务系统服务端调用线程池中的write接口,将消息写入redis中,同时将消息调用各个send服务器的send接口将消息发送到client端;
四、当send服务的send接口被调用时,触发send服务,将消息发送予已与send握手的客户端client。
由于采用了上述技术方案,与现有技术相比,本发明通过redis实现消息存储,消息队列管理,通过websocket实现服务端与客户端的通讯,从而实现消息统一管理,统一发送渠道。
redis是一个key-value存储系统,和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合),这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序,与memcached一样,为了保证效率,数据都是缓存在内存中,区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
redis 是一个高性能的key-value数据库, redis的出现,很大程度补偿了memcached这类keyvalue存储的不足,在部 分场合可以对关系数据库起到很好的补充作用,它提供了Python,Ruby,Erlang,PHP, java客户端,使用很方便。
WebSocket 规范的目标是在浏览器中实现和服务器端双向通信,双向通信可以拓展浏览器上的应用类型,例如实时的数据推送(股票行情)、游戏、聊天等,Redis实现消息存储,消息队列,websocket实现客户端与服务端的通讯。
具体实施过程
一、如附图1所示,整体解决方案;
1、客户端client调用Login中的登录接口实现登录,login服务端通过人员Map查询得到登录人员分配的send消息服务器。并返回给登录人员。
2、登录人员得到分配的send服务器后,通过websocket技术与send服务器第一次握手,打开消息通道。
3、业务系统服务端调用线程池中的write接口,将消息写入redis中,同时将消息调用各个send服务器的send接口将消息发送到client端。
4、当send服务的send接口被调用时,触发send服务,将消息发送予已与send握手的客户端client。
二、关键技术实现方案
1、Query实现技术:
方便消息数据的读写操作,有两种技术方案,一下是关于两种的比较以及最终选型。
java客户端调用测试
要建立java客户端测试环境,首先需要redis客户端调用所依赖的java包,我用了两种进行测试,1、jredis 2、jedis
对上述两种客户端都做了测试代码的编写,有如下直观的区别:
Redis版本:2.5.5
Jredis: jredis直接抛出异常。
Jedis: 可以存入数据到服务器,但是不支持集合以及对象作为值保存。
Redis版本:1.6
Jredis: 可以正常的存取,也可以把对象和集合作为值进行存储。
Jedis: 可以存入数据到服务器,但是不支持集合以及对象作为值保存。
上述两种的共同的缺陷:不能保证高并发(我启动超过70个线程就开始有异常抛出,因此需要使用JedisPool和JedisPoolConfig实例,进行池化,否则难以支持大数据量的高并发)、大数据量的稳定性。
2、线程池实现技术:
线程池作用就是限制系统中执行线程的数量。 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。
为什么要用线程池:
减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。
要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。
1). newSingleThreadExecutor
创建一个单线程的线程池,这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2). newFixedThreadPool
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
3). newCachedThreadPool
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
4). newScheduledThreadPool
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
综上述技术表现这里使用newFixedThreadPool线程管理。解决资源的合理利用,同时又不影响多操作的性能。
3、websocket实现技术
WebSocket protocol 是HTML5一种新的协议(protocol)。它是实现了浏览器与服务器全双工通信(full-duplex)。
现很多网站为了实现即时通讯(real-time),所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(time interval)(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request d的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求(request),然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽。
而最比较新的技术去做轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通信,但依然需要发出请求(reuqest)。
在 WebSocket API,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket 协议中,为我们实现即时服务带来了两大好处:
1). Header
互相沟通的Header是很小的-大概只有 2 Bytes
2). Server Push
服务器可以主动传送数据给客户端
3).编辑本段握手协议
在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为“握手” (handshaking)。
PS1:握手协议在后期的版本中,会标明版本编号,下面的例子属于早期的协定之一,对于新版的 chrome 和 Firefox 皆不适用。
PS2:后期的版本大多属于功能上的扩充,例如使用第7版的握手协议同样也适用于第8版的握手协议。
三、研究基础
1、如附图2所示,成熟的消息存储机制
下面是官方的bench-mark数据:
测试完成了50个并发执行100000个请求。
设置和获取的值是一个256字节字符串。
Linux box是运行Linux 2.6,这是X3320 Xeon 2.5 ghz。
文本执行使用loopback接口(127.0.0.1)。
结果:每秒约110000套,每秒约81000得到。
2、如附图3所示,成熟的消息通道
浏览器与WEB服务对websocket的支持
浏览器
实现了websocket的浏览器:
Chrome Supported in version 4+
Firefox Supported in version 4+
Internet Explorer Supported in version 10+
Opera Supported in version 10+
Safari Supported in version 5+
服务器
在服务器端,也出现了一些实现websocket协议的项目:
jetty 7.0.1 包含了一个初步的实现;
resin 包含有websocket 实现;
pywebsocket, apache http server 扩展;
apache tomcat 7.0.27 版本;
Nginx 1.3.13 版本。