首页 文章 精选 留言 我的

精选列表

搜索[分布式锁],共10000篇文章
优秀的个人博客,低调大师

分布式--ActiveMQ 消息中间件(一)

1. ActiveMQ 1). ActiveMQ ActiveMQ是Apache所提供的一个开源的消息系统,完全采用Java来实现,因此,它能很好地支持J2EE提出的JMS(Java Message Service,即Java消息服务)规范。JMS是一组Java应用程序接口,它提供消息的创建、发送、读取等一系列服务。JMS提供了一组公共应用程序接口和响应的语法,类似于Java数据库的统一访问接口JDBC,它是一种与厂商无关的API,使得Java程序能够与不同厂商的消息组件很好地进行通信。 2). Java Message Service(JMS) JMS支持两种消息发送和接收模型。 一种称为P2P(Ponit to Point)模型,即采用点对点的方式发送消息。P2P模型是基于队列的,消息生产者发送消息到队列,消息消费者从队列中接收消息,队列的存在使得消息的异步传输称为可能,P2P模型在点对点的情况下进行消息传递时采用。 图1.png 另一种称为Pub/Sub(Publish/Subscribe,即发布-订阅)模型,发布-订阅模型定义了如何向一个内容节点发布和订阅消息,这个内容节点称为topic(主题)。主题可以认为是消息传递的中介,消息发布这将消息发布到某个主题,而消息订阅者则从主题订阅消息。主题使得消息的订阅者与消息的发布者互相保持独立,不需要进行接触即可保证消息的传递,发布-订阅模型在消息的一对多广播时采用。 图2.png 3). JMS术语 Provider/MessageProvider:生产者 Consumer/MessageConsumer:消费者 PTP:Point To Point,点对点通信消息模型 Pub/Sub:Publish/Subscribe,发布订阅消息模型 Queue:队列,目标类型之一,和PTP结合 Topic:主题,目标类型之一,和Pub/Sub结合 ConnectionFactory:连接工厂,JMS用它创建连接 Connnection:JMS Client到JMS Provider的连接 Destination:消息目的地,由Session创建 Session:会话,由Connection创建,实质上就是发送、接受消息的一个线程,因此生产者、消费者都是Session创建的 4). ActiveMQ下载 图3.png bin (windows下面的bat(分32、64位)和unix/linux下面的sh) conf (activeMQ配置目录,包含最基本的activeMQ配置文件) data (默认是空的) docs (index,replease版本里面没有文档,-.-b不知道为啥不带) example (几个例子) lib (activemMQ使用到的lib) webapps 注意ActiveMQ自带Jetty提供Web管控台 webapps-demo 示例 activemq-all-5.15.3.jar LICENSE.txt README.txt 5). 配置 Web控制台账号和密码(apache-activemq-5.15.3\conf) 图4.png 网络端口(apache-activemq-5.15.3\conf)--默认为8161 图5.png 6). 启动 \apache-activemq-5.15.3\bin\win64\目录下双击activemq.bat文件,在浏览器中输入http://localhost:8161/admin/, 用户名和密码输入admin即可 图6.png 7). 消息中间件(MOM:Message Orient middleware) 消息中间件有很多的用途和优点: 1 将数据从一个应用程序传送到另一个应用程序,或者从软件的一个模块传送到另外一个模块; 负责建立网络通信的通道,进行数据的可靠传送。 保证数据不重发,不丢失 能够实现跨平台操作,能够为不同操作系统上的软件集成技工数据传送服务 8).什么情况下使用ActiveMQ? 多个项目之间集成 (1) 跨平台 (2) 多语言 (3) 多项目 降低系统间模块的耦合度,解耦 (1) 软件扩展性 系统前后端隔离 (1) 前后端隔离,屏蔽高安全区 2. ActiveMQ 示例 1). P2P 示例 I. 导包--activemq-all-5.15.3.jar II. Producer /** * 定义消息的生产者 * @author mazaiting */ public class Producer { // 用户名 private static final String USERNAME = ActiveMQConnection.DEFAULT_USER; // 密码 private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD; // 链接 private static final String BROKENURL = ActiveMQConnection.DEFAULT_BROKER_URL; /** * 定义消息并发送,等待消息的接收者(消费者)消费此消息 * @param args * @throws JMSException */ public static void main(String[] args) throws JMSException { // 消息中间件的链接工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( USERNAME, PASSWORD, BROKENURL); // 连接 Connection connection = null; // 会话 Session session = null; // 消息的目的地 Destination destination = null; // 消息生产者 MessageProducer messageProducer = null; try { // 通过连接工厂获取链接 connection = connectionFactory.createConnection(); // 创建会话,进行消息的发送 // 参数一:是否启用事务 // 参数二:设置自动签收 session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); // 创建消息队列 destination = session.createQueue("talkWithMo"); // 创建一个消息生产者 messageProducer = session.createProducer(destination); // 设置持久化/非持久化, 如果非持久化,MQ重启后可能后导致消息丢失 messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // 模拟发送消息 for (int i = 0; i < 5; i++) { TextMessage textMessage = session.createTextMessage("给妈妈发送的消息:"+i); System.out.println("textMessage: " + textMessage); messageProducer.send(textMessage); } // 如果设置了事务,会话就必须提交 session.commit(); } catch (JMSException e) { e.printStackTrace(); } finally { if (null != connection) { connection.close(); } } } } III. Consumer /** * 定义消息的消费者 * @author mazaiting */ public class Consumer { // 用户名 private static final String USERNAME = ActiveMQConnection.DEFAULT_USER; // 密码 private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD; // 链接 private static final String BROKENURL = ActiveMQConnection.DEFAULT_BROKER_URL; /** * 接收消息 * @param args * @throws JMSException */ public static void main(String[] args) throws JMSException { // 消息中间件的链接工厂 ConnectionFactory connectionFactory = null; // 链接 Connection connection = null; // 会话 Session session = null; // 消息的目的地 Destination destination = null; // 消息的消费者 MessageConsumer messageConsumer = null; // 实例化链接工厂,创建一个链接 connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKENURL); try { // 通过工厂获取链接 connection = connectionFactory.createConnection(); // 启动链接 connection.start(); // 创建会话,进行消息的接收 session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); // 创建消息队列 destination = session.createQueue("talkWithMo"); // 创建一个消息的消费者 messageConsumer = session.createConsumer(destination); // 模拟接收消息 while (true) { TextMessage textMessage = (TextMessage) messageConsumer.receive(10000); if (null != textMessage) { System.out.println("收到消息: " + textMessage); } else { break; } } // 提交 session.commit(); } catch (JMSException e) { e.printStackTrace(); } finally { if (null != connection) { connection.close(); } } } } IV. 测试 先运行生产者Producer 图7.png ActiveMQ控制台 图8.png 再运行消费者Consumer 图9.png ActiveMQ控制台 图10.png V. 消息类型 StreamMessage Java原始值的数据流 MapMessage 一套名称-键值对 TextMessage 一个字符串对象 ObjectMessage 一个序列号的Java对象 BytesMessage 一个未解释字节的数据流 VI. 控制台 Queue Messages Enqueued:表示生产了多少条消息,记做P Messages Dequeued:表示消费了多少条消息,记做C Number Of Consumers:表示在该队列上还有多少消费者在等待接受消息 Number Of Pending Messages:表示还有多少条消息没有被消费,实际上是表示消息的积压程度,就是P-C VII. 签收 签收就是消费者接受到消息后,需要告诉消息服务器,我收到消息了。当消息服务器收到回执后,本条消息将失效。因此签收将对PTP模式产生很大影响。如果消费者收到消息后,并不签收,那么本条消息继续有效,很可能会被其他消费者消费掉! AUTO_ACKNOWLEDGE:表示在消费者receive消息的时候自动的签收 CLIENT_ACKNOWLEDGE:表示消费者receive消息后必须手动的调用acknowledge()方法进行签收 DUPS_OK_ACKNOWLEDGE:签不签收无所谓了,只要消费者能够容忍重复的消息接受,当然这样会降低Session的开销 2). request/reply模型 I. 实现思路 图11.png Client的Producer发出一个JMS message形式的request,request上附加了一些额外的属性: correlation ID(用来和返回的correlation ID对比进行验证), JMSReplyTo属性(放置jms message的destination,这样worker的Consumer获得jms message就能得到destination) Worker的consumer收到requset,处理request并用producer发出reply,destination就从requset的JMSReplyTo属性中得到。 II. Server代码 public class Server implements MessageListener { // 经纪人链接 private static final String BROKER_URL = "tcp://localhost:61616"; // 请求队列 private static final String REQUEST_QUEUE = "requestQueue"; // 经纪人服务 private BrokerService brokerService; // 会话 private Session session; // 生产者 private MessageProducer producer; // 消费者 private MessageConsumer consumer; private void start() throws Exception { createBroker(); setUpConsumer(); } /** * 创建经纪人 * @throws Exception */ private void createBroker() throws Exception { // 创建经纪人服务 brokerService = new BrokerService(); // 设置是否持久化 brokerService.setPersistent(false); // 设置是否使用JMX brokerService.setUseJmx(false); // 添加链接 brokerService.addConnector(BROKER_URL); // 启动 brokerService.start(); } /** * 设置消费者 * @throws JMSException */ private void setUpConsumer() throws JMSException { // 创建连接工厂 ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL); // 创建连接 Connection connection = connectionFactory.createConnection(); // 启动连接 connection.start(); // 创建Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 创建队列 Destination adminQueue = session.createQueue(REQUEST_QUEUE); // 创建生产者 producer = session.createProducer(null); // 设置持久化模式 producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // 创建消费者 consumer = session.createConsumer(adminQueue); // 消费者设置消息监听 consumer.setMessageListener(this); } public void stop() throws Exception { producer.close(); consumer.close(); session.close(); brokerService.stop(); } @Override public void onMessage(Message message) { try { // 创建新消息 TextMessage response = this.session.createTextMessage(); // 判断消息是否是文本消息 if (message instanceof TextMessage) { // 强转为文本消息 TextMessage textMessage = (TextMessage) message; // 获取消息内容 String text = textMessage.getText(); // 设置消息 response.setText(handleRequest(text)); } response.setJMSCorrelationID(message.getJMSCorrelationID()); producer.send(message.getJMSReplyTo(), response); } catch (JMSException e) { e.printStackTrace(); } } /** * 构建消息内容 * @param text 文本 * @return */ private String handleRequest(String text) { return "Response to '" + text + "'"; } public static void main(String[] args) throws Exception { Server server = new Server(); // 启动 server.start(); System.out.println(); System.out.println("Press any key to stop the server"); System.out.println(); System.in.read(); server.stop(); } } III. Client代码 public class Client implements MessageListener { // 经纪人链接 private static final String BROKER_URL = "tcp://localhost:61616"; // 请求队列 private static final String REQUEST_QUEUE = "requestQueue"; // 连接 private Connection connection; // 会话 private Session session; // 生产者 private MessageProducer producer; // 消费者 private MessageConsumer consumer; // 请求队列 private Queue tempDest; public void start() throws JMSException { // 连接工厂 ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(BROKER_URL); // 创建连接 connection = activeMQConnectionFactory.createConnection(); // 开启连接 connection.start(); // 创建会话 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 创建队列 Destination adminQueue = session.createQueue(REQUEST_QUEUE); // 创建生产者 producer = session.createProducer(adminQueue); // 设置持久化模式 producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // 创建模板队列 tempDest = session.createTemporaryQueue(); // 创建消费者 consumer = session.createConsumer(tempDest); // 设置消息监听 consumer.setMessageListener(this); } /** * 停止 * @throws JMSException */ public void stop() throws JMSException { producer.close(); consumer.close(); session.close(); } /** * 请求 * @param request * @throws JMSException */ public void request(String request) throws JMSException { System.out.println("Request: " + request); // 创建文本消息 TextMessage textMessage = session.createTextMessage(); // 设置文本内容 textMessage.setText(request); // 设置回复 textMessage.setJMSReplyTo(tempDest); // 获取UUID String correlationId = UUID.randomUUID().toString(); // 设置JMS id textMessage.setJMSCorrelationID(correlationId); // 发送消息 this.producer.send(textMessage); } @Override public void onMessage(Message message) { try { System.out.println("Received response for: " + ((TextMessage)message).getText()); } catch (JMSException e) { e.printStackTrace(); } } public static void main(String[] args) throws JMSException, InterruptedException { Client client = new Client(); // 启动 client.start(); int i = 0; while(i++ < 10) { client.request("REQUEST- " + i); } Thread.sleep(3000); client.stop(); } } IV. 测试 启动Server 图12.png 启动Client 图13.png 代码下载

优秀的个人博客,低调大师

TCPcopy:分布式TCP压力测试工具

线下的传统压力测试,难以模拟真实流量,尤其难以模拟正常流量混杂着各色异常流量。所以,线下压得好好的系统,上线后可能某天突然雪崩,说好能支撑 5 倍流量的系统重构,也许流量一翻倍就彻底挂了。 但办法总比问题多。 系统重构或重要变更上线前,可以拷贝线上真实流量,实时模拟线上流量,甚至可以放大真实流量,进行压力测试,以评估系统承载能力。 反过来也可以这样,如果线上跑着跑着发现有性能瓶颈,但线下环境难以复现,还不如把真实流量拷贝到线下重放,毕竟线下环境便于上各种排查手段,重放几遍都行,直到找到问题。 如何实时拷贝线上真实流量呢?TCPCopy 2010年,网易技术部的王斌在王波的工作基础上开发了 TCPCopy - A TCP Stream Replay Tool。2011年9月开源。当前版本号是 1.0.0。很多公司的模拟在线测试都是基于 TCPCopy 做的,如一淘。 TCPCopy 是一种请求复制(复制基于 TCP 的 packets)工具 ,通过复制在线数据包,修改 TCP/IP 头部信息,发送给测试服务器,达到欺骗测试服务器的TCP 程序的目的,从而为欺骗上层应用打下坚实基础。 TCPCopy是如何工作的 基于 Server 的请求回放领域,一般分为离线回放和在线实时复制两种。 其中请求实时复制,一般可以分为两类: 1)基于应用层的请求复制 , 2)基于底层数据包的请求复制。 如果从应用层面进行复制,比如基于服务器的请求复制,实现起来相对简单,但也存在着若干缺点: 1)请求复制从应用层出发,穿透整个协议栈,这样就容易挤占应用的资源,比如宝贵的连接资源 2)测试跟实际应用耦合在一起,容易影响在线系统, 3)也因此很难支撑压力大的请求复制, 4)很难控制网络延迟。 而基于底层数据包的请求复制,可以做到无需穿透整个协议栈,路程最短的,可以从数据链路层抓请求包,从数据链路层发包,路程一般的,可以在IP层抓请求包,从IP层发出去,不管怎么走,只要不走TCP,对在线的影响就会小得多。这也就是 TCPCopy 的基本思路。 从传统架构的 rawsocket+iptable+netlink,到新架构的 pacp+route,它经历了三次架构调整,现如今的 TCPCopy 分为三个角色: Online Server(OS):上面要部署 TCPCopy,从数据链路层(pcap 接口)抓请求数据包,发包是从IP层发出去; Test Server(TS):最新的架构调整把 intercept 的工作从 TS 中 offload 出来。TS 设置路由信息,把 被测应用 的需要被捕获的响应数据包信息路由到 AS; Assistant Server(AS):这是一台独立的辅助服务器,原则上一定要用同网段的一台闲置服务器来充当辅助服务器。AS 在数据链路层截获到响应包,从中抽取出有用的信息,再返回给相应的 OS 上的 tcpcopy 进程。 tcpcopy项目地址:https://github.com/session-replay-tools/tcpcopy Online Server 上的抓包: tcpcopy 的新架构在 OS 上抓请求数据包默认采用 raw socket input 接口抓包。王斌则推荐采用 pcap 抓包,安装命令如下: yum install libpcap-devel git clone git://github.com/session-replay-tools/tcpcopy.git cd tcpcopy ./configure make make install 这样就可以在内核态进行过滤,否则只能在用户态进行包的过滤,而且在 intercept 端或者 tcpcopy 端设置 filter(通过 -F 参数,类似 tcpdump 的 filter),达到起多个实例来共同完成抓包的工作,这样可扩展性就更强,适合于超级高并发的场合。 为了便于理解 pcap 抓包,下面简单描述一下 libpcap 的工作原理。 一个包的捕捉分为三个主要部分: 面向底层包捕获, 面向中间层的数据包过滤, 面向应用层的用户接口。 这与 Linux 操作系统对数据包的处理流程是相同的(网卡->网卡驱动->数据链路层->IP层->传输层->应用程序)。包捕获机制是在数据链路层增加一个旁路处理(并不干扰系统自身的网络协议栈的处理),对发送和接收的数据包通过Linux内核做过滤和缓冲处理,最后直接传递给上层应用程序。如下图2所示: Online Server 上的发包: 如图1所示,新架构和传统架构一样,OS 默认使用 raw socket output 接口发包,此时发包命令如下: ./tcpcopy -x 80-测试机IP:测试机应用端口 -s 服务器IP -i eth0 其中 -i 参数指定 pcap 从哪个网卡抓取请求包。 此外,新架构还支持通过 pcap_inject(编译时候增加--enable-dlinject)来发包。 Test Server 上的响应包路由: 需要在 Test Server 上添加静态路由,确保被测试应用程序的响应包路由到辅助测试服务器,而不是回包给 Online Server。 Assistant Server 上的捕获响应包: 辅助服务器要确保没有开启路由模式 cat /proc/sys/net/ipv4/ip_forward,为0表示没有开启。 辅助服务器上的 intercept 进程通过 pcap 抓取测试机应用程序的响应包,将头部抽取后发送给 Online Server 上的 tcpcopy 进程,从而完成一次请求的复制。 实验 1.机器别表 192.168.0.11 -- onlie server 192.168.0.12 -- test server 192.168.0.13 -- Assistant server 2.online server操作 安装tcpcopy yum install libpcap-devel git clone git://github.com/session-replay-tools/tcpcopy.git cd tcpcopy ./configure make make install 启动TCPCOPY ./sbin/tcpcopy -x 80-192.168.0.12:80 -s 192.168.0.13 -c 192.168.0.11 -x 参数指定本机哪个端口的流量转发到哪台机器的哪个端口,格式为localip:80-targetip:port -s 参数指定Assistant server -c 指定本机 可以添加-n参数来放大流量,比如说 -n 2 代表放大2倍流量 可以添加-r参数来复制一部分流量。比如说,-r 20 代表复制20%的流量 可以添加-d参数来让tcpcopy后台运行 3.test server操作 route add host 192.168.0.11 gw 192.168.0.13 这一步很重要,之前我就是因为这个路由设置不正确,一直没搭建成功 4.Assistant server操作 安装intercept yum install libpcap-devel git clone git://github.com/session-replay-tools/intercept.git cd intercept ./configure make make install 启动intercept ./sbin/intercept -i eth0 -F tcp and src port 80 -d -i 指定网卡 -F 指定copy的是tcp还是udp -d 代表后台运行 我这里默认online server还有test server都启动了nginx。当你访问online server上的http服务的时候。你会发现test server上也有访问log存在。可以通过监控test server上的负载,来判断机器的运行情况 转自:路飞 PHP后端学习https://mp.weixin.qq.com/s/ycx5XhehhdDVWCgVnROVOg

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册