高CPU业务场景下的任务分发方案Gearman搭建一览

时间:2023-02-21 14:43:23

  

    Gearman是当年LiveJournal用来做图片resize的,大家也明白图片resize是一个高CPU的操作,如果让web网站去做这个高CPU的功能,有可能会拖垮你的

web应用,那本篇我们来看看gearman是如何解决这个问题的,它的架构图类似下面这样:

高CPU业务场景下的任务分发方案Gearman搭建一览

从上面这张图,你应该会看到,Gearman是由三个部分组成:

1. Job Server

这个就是Gearman的Job Server,通过它对Client 和 jobwork 进行桥接,是不是想起来了中介者模式。。。

2. Client

Gearman提供了Client API 给客户端调用,Client只需要将一个高CPU的业务函数名丢给Job Server,然后等待JobServer的返回执行结果。

3. jobwork

Gearman提供了work API 给work客户端进行调用。jobserver会根据后端的work集群的负载情况,分发给一个合适的work去执行,并等待结果。

说到这里,你应该就明白了,本质上它属于那种分布式的RPC调用,而且非常牛逼的地方在于Client 和 Work 可以用不同的语言实现。

一:安装部署

1.  下载地址:https://github.com/gearman/gearmand/releases

目前gearman的JobServer 有C,JAVA,Perl三种语言实现,由于C版本的JobServer是最活跃的,所以这里采用目前最新的1.1.17版本的gearmand在CentOS

上进行安装部署。

高CPU业务场景下的任务分发方案Gearman搭建一览

2.  快速安装

可以通过官网http://gearman.org/getting-started/中的getting-started进行快速安装。

<1> 基础依赖库安装和gearmand下载

 yum -y install boost-devel gperf libevent-devel libuuid-devel gcc44 gcc-c++
wget https://github.com/gearman/gearmand/releases/download/1.1.17/gearmand-1.1.17.tar.gz
cd gearmand-1.1..tar.gz
tar xzvf gearmand-1.1..tar.gz
cd gearmand-1.1.
[root@localhost gearmand-1.1.]# ls
aclocal.m4 build-aux configure.ac gear_config.in libgearman-1.0 libhashkit-1.0 Makefile.am rpm THANKS
AUTHORS ChangeLog COPYING gearmand libgearmancore libhostile Makefile.in scripts util
benchmark configmake.h docs HACKING libgearman-server libtest man support version.m4
bin configure examples libgearman libhashkit m4 NEWS tests

<2> 然后就是常规的./configure --prefix=/usr/myapp/gearman && make && make install  这个过程超级慢,可以出去抽跟烟,

顺便再去拉泡屎。。。

 ./configure --prefix=/usr/myapp/gearman && make && make install

<3> 若干年后,当你看到这个就算安装成功了。。。还是得恭喜一下。。。。至少没让你踩到缺少各种依赖包的界面。

 See any operating system documentation about shared libraries for
more information, such as the ld() and ld.so() manual pages.
----------------------------------------------------------------------
/usr/bin/mkdir -p '/usr/myapp/gearman/sbin'
/usr/bin/install -c -m man/gearman_worker_create. man/gearman_worker_define_function. man/gearman_worker_echo. man/gearman_worker_errno. man/gearman_worker_error. man/gearman_worker_free. man/gearman_worker_function_exist. man/gearman_worker_grab_job. man/gearman_worker_options. man/gearman_worker_register. man/gearman_worker_remove_options. man/gearman_worker_remove_servers. man/gearman_worker_set_context. man/gearman_worker_set_log_fn. man/gearman_worker_set_namespace. man/gearman_worker_set_options. man/gearman_worker_set_timeout. man/gearman_client_has_option. man/gearman_client_options_t. man/gearman_task_attr_init. man/gearman_task_attr_init_background. man/gearman_task_attr_init_epoch. man/gearman_task_attr_t. man/gearman_worker_set_identifier. man/gearman_worker_set_workload_free_fn. man/gearman_worker_set_workload_malloc_fn. man/gearman_worker_st. man/gearman_worker_timeout. man/gearman_worker_unregister. man/gearman_worker_unregister_all. man/gearman_worker_wait. man/gearman_worker_work. man/libgearman. '/usr/myapp/gearman/share/man/man3'
/bin/sh ./libtool --mode=install /usr/bin/install -c gearmand/gearmand '/usr/myapp/gearman/sbin'
libtool: install: /usr/bin/install -c gearmand/gearmand /usr/myapp/gearman/sbin/gearmand
/usr/bin/mkdir -p '/usr/myapp/gearman/bin'
/bin/sh ./libtool --mode=install /usr/bin/install -c bin/gearman bin/gearadmin '/usr/myapp/gearman/bin'
libtool: install: /usr/bin/install -c bin/.libs/gearman /usr/myapp/gearman/bin/gearman
libtool: install: /usr/bin/install -c bin/gearadmin /usr/myapp/gearman/bin/gearadmin
make[]: Leaving directory `/usr/myapp/gearmand-1.1.'
make[]: Leaving directory `/usr/myapp/gearmand-1.1.'
make[]: Leaving directory `/usr/myapp/gearmand-1.1.'

<4> 启动gearmand,你也可以用 -d 开启后台运行的模式,这里加上DEBUG只是看一下实时的DEBUG信息,如下所示:

 [root@localhost myapp]# cd /usr/myapp/gearman
[root@localhost gearman]# ls
bin include lib sbin share
[root@localhost gearman]# cd bin
[root@localhost bin]# ls
gearadmin gearman
[root@localhost bin]# cd /usr/myapp/gearman
[root@localhost gearman]# cd sbin
[root@localhost sbin]# ls
gearmand
[root@localhost sbin]# ./gearmand --verbose DEBUG
./gearmand: Could not open log file "/usr/myapp/gearman/var/log/gearmand.log", from "/usr/myapp/gearman/sbin", switching to stderr. (No such file or directory)
DEBUG -- ::10.796259 [ main ] THREADS: -> libgearman-server/gearmand.cc:
INFO -- ::10.796374 [ main ] Initializing Gear on port with SSL: false
INFO -- ::10.796487 [ main ] Starting up with pid , verbose is set to DEBUG
DEBUG -- ::10.796637 [ main ] Method for libevent: epoll -> libgearman-server/gearmand.cc:
DEBUG -- ::10.798874 [ main ] Trying to listen on 0.0.0.0: -> libgearman-server/gearmand.cc:
INFO -- ::10.800151 [ main ] Listening on 0.0.0.0: ()
DEBUG -- ::10.800175 [ main ] Trying to listen on ::: -> libgearman-server/gearmand.cc:
INFO -- ::10.800307 [ main ] Listening on ::: ()
DEBUG -- ::10.800333 [ main ] Creating wakeup pipe -> libgearman-server/gearmand.cc:
DEBUG -- ::10.800344 [ main ] Creating threads -> libgearman-server/gearmand.cc:
DEBUG -- ::10.800357 [ main ] Initializing libevent for IO thread -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800406 [ main ] Creating IO thread wakeup pipe -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800467 [ main ] Thread created -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800507 [ main ] Initializing libevent for IO thread -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800550 [ main ] Creating IO thread wakeup pipe -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800585 [ main ] Thread created -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800594 [ main ] Initializing libevent for IO thread -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800632 [ main ] Creating IO thread wakeup pipe -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800669 [ main ] Thread created -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800677 [ main ] Initializing libevent for IO thread -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800714 [ main ] Creating IO thread wakeup pipe -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800753 [ main ] Thread created -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.800761 [ main ] replaying queue: begin -> libgearman-server/gearmand.cc:
DEBUG -- ::10.800766 [ main ] __replay -> libgearman-server/plugins/queue/default/queue.cc:
DEBUG -- ::10.800774 [ main ] replaying queue: end -> libgearman-server/gearmand.cc:
INFO -- ::10.800780 [ main ] Adding event for listening socket ()
INFO -- ::10.800787 [ main ] Adding event for listening socket ()
DEBUG -- ::10.800794 [ main ] Adding event for wakeup pipe -> libgearman-server/gearmand.cc:
DEBUG -- ::10.800801 [ main ] Entering main event loop -> libgearman-server/gearmand.cc:
DEBUG -- ::10.801186 [ ] Entering thread event loop -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.801277 [ ] Entering thread event loop -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.801507 [ main ] staring up Epoch thread -> libgearman-server/timer.cc:
DEBUG -- ::10.801635 [ ] Entering thread event loop -> libgearman-server/gearmand_thread.cc:
DEBUG -- ::10.802426 [ ] Entering thread event loop -> libgearman-server/gearmand_thread.cc:

<5> 最后通过netstat,lsof, ps -ef 三板斧可以找出来gearmand大概占用的端口号,就如你看到的默认占用的4370端口,

当然你也可以在启动的时候用help命令也是能够知道的。

 [root@localhost ~]# netstat -tln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 192.168.122.1: 0.0.0.0:* LISTEN
tcp 0.0.0.0: 0.0.0.0:* LISTEN
tcp 127.0.0.1: 0.0.0.0:* LISTEN
tcp 127.0.0.1: 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:4730 0.0.0.0:* LISTEN
tcp6 ::: :::* LISTEN
tcp6 ::: :::* LISTEN
tcp6 ::: :::* LISTEN
tcp6 ::: :::* LISTEN
tcp6 ::: :::* LISTEN
tcp6 ::: :::* LISTEN
tcp6 127.0.0.1: :::* LISTEN
[root@localhost ~]# ps -ef | grep gearmand
root 40299 15869 0 02:31 pts/1 00:00:00 ./gearmand --verbose DEBUG
root : pts/ :: grep --color=auto gearmand
[root@localhost ~]# lsof -i :
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
gearmand 40299 root 8u IPv4 322550 0t0 TCP *:gearman (LISTEN)
gearmand root 9u IPv6 0t0 TCP *:gearman (LISTEN)
[root@localhost ~]#

二:Java Driver 在 Gearman上的使用

为了演示,我可以做一个简单的 “字符串.ToUpper”的业务逻辑来验证一下这个架构是否可以跑的起来。

1. java 充当 Gearman 的 work

首先需要在mvn仓库中拉一下jar包:http://www.mvnrepository.com/artifact/org.gearman/gearman-java/0.6。

高CPU业务场景下的任务分发方案Gearman搭建一览

<1> UpperFunction类,这个类用于定义work具体的业务逻辑:

 package com.datamip.gearmanwork;

 import java.text.SimpleDateFormat;
import java.util.Date; import org.gearman.client.GearmanJobResult;
import org.gearman.client.GearmanJobResultImpl;
import org.gearman.util.ByteUtils;
import org.gearman.worker.AbstractGearmanFunction; //字符串大写的业务Function
public class UpperFunction extends AbstractGearmanFunction { @Override
public GearmanJobResult executeFunction() { String param = ByteUtils.fromUTF8Bytes((byte[]) this.data); byte[] mybytes = param.toUpperCase().getBytes(); GearmanJobResultImpl result = new GearmanJobResultImpl(mybytes, true, mybytes, null, null, -1, -1); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateString = formatter.format(new Date()); System.out.println(String.format("当前时间:%s, 过来的字符串:%s,返回的字符串:%s", dateString, param,new String(mybytes))); return result;
}
}

<2>  将UpperFunction注册到gearmand中,从红色代码可以看到,其实是一个kv模式,这里的key="myUpperFunc”的对应执行业务就是new UpperFunction。

这样Client只需要传递一个"myUpperFunc",Gearmand就知道这个“字符串”对应是哪一个处理函数。。。

 public class App {
public static void main(String[] args) { GearmanWorker worker = new GearmanWorkerImpl(); GearmanNIOJobServerConnection conn = new GearmanNIOJobServerConnection("192.168.23.170", 4730);
worker.addServer(conn); // 将‘将转大写的函数注册’ 到gearmand中
10 worker.registerFunctionFactory(new GearmanFunctionFactory() {
11
12 public String getFunctionName() {
13 return "myUpperFunc";
14 }
15
16 public GearmanFunction getFunction() {
17 return new UpperFunction();
18 }
19 }); System.out.println("启动服务。。。。"); worker.work();
}
}

2. java 充当 Gearman 的 client

<1> GearSubmit类【简单的一个包装类,随便定义】

 package com.datamip.gearmanclient;

 import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; import org.gearman.client.GearmanClient;
import org.gearman.client.GearmanClientImpl;
import org.gearman.client.GearmanJob;
import org.gearman.client.GearmanJobImpl;
import org.gearman.client.GearmanJobResult;
import org.gearman.common.GearmanJobServerConnection;
import org.gearman.common.GearmanNIOJobServerConnection;
import org.gearman.util.ByteUtils; public class Gearsubmit { public void process() throws InterruptedException, ExecutionException { GearmanJobServerConnection conn = new GearmanNIOJobServerConnection("192.168.23.170", 4730); GearmanClient client = new GearmanClientImpl(); client.addJobServer(conn); // 添加连接 String functionName = "myUpperFunc"; byte[] data = ByteUtils.toUTF8Bytes("hello,world"); // 创建后台任务
GearmanJob job = GearmanJobImpl.createJob(functionName, data, null); GearmanJobResult jobResult = null; Future<GearmanJobResult> gearmanJobResult = client.submit(job); jobResult = gearmanJobResult.get(); byte[] resultBytes = jobResult.getResults(); // 获取job的返回值
String value = ByteUtils.fromUTF8Bytes(resultBytes); System.out.println(value); System.out.println("执行结束"); client.shutdown();
}
}

<2> 主程序,开多线程并发的去执行。

 public class App {
public static void main(String[] args) throws InterruptedException, ExecutionException, IOException { ExecutorService executorService = Executors.newFixedThreadPool(100); for (int i = 0; i < 10000; i++) {
executorService.execute(new Runnable() { @Override
public void run() {
Gearsubmit submit=new Gearsubmit(); try {
submit.process();
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} System.in.read();
}
}

好了,一切都准备好了,接下来为了演示,演示就是解释,我用Jar2Exe把work程序导出成jar再转换成exe,如下图:

高CPU业务场景下的任务分发方案Gearman搭建一览

高CPU业务场景下的任务分发方案Gearman搭建一览

然后我把3.exe开成5个实例,client用100个线程的线程池并发调用,当然一切都是模拟。。。。可以看到,当我client启动的时候,5个work都在执行,

如果这个时候,你把某一个work停止了,jobserver也不再将任务丢给它,而是转给其他负载相对小的work继续执行。

高CPU业务场景下的任务分发方案Gearman搭建一览

好了,本篇就说到这里,希望对你有帮助。

高CPU业务场景下的任务分发方案Gearman搭建一览的更多相关文章

  1. 高CPU业务

    高CPU业务 Gearman是当年LiveJournal用来做图片resize的,大家也明白图片resize是一个高CPU的操作,如果让web网站去做这个高CPU的功能,有可能会拖垮你的 web应用, ...

  2. 【智能合约】编写复杂业务场景下的智能合约——可升级的智能合约设计模式(附Demo)

    智能合约的现状 以太坊在区块链上实现了智能合约的概念,用于:同质化通证发行(ERC-20).众筹.投票.存证取证等等,共同点是:合约逻辑简单,只是业务流程中的关键节点,而非整个业务流程.而智能合约想解 ...

  3. 不同场景下 MySQL 的迁移方案

    一 目录 一 目录 二 为什么要迁移 三 MySQL 迁移方案概览 四 MySQL 迁移实战 4.1 场景一 一主一从结构迁移从库 4.2 场景二 一主一从结构迁移指定库 4.3 场景三 一主一从结构 ...

  4. 高并发应用场景下的负载均衡与故障转移实践,AgileEAS&period;NET SOA 负载均衡介绍与实践

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  5. 高内存 高CPU 劣质网络下的测试

    内存 先把系统的虚拟内存去掉 (右键我的电脑属性里有的.选择那个无分页文件 虚拟内存在任务管理器就不显示了), 然后机子本身内存不高,开几个网页就满了       CPU cpu可以用鲁大师测试cpu ...

  6. MvcPager&period;js在特定业务场景下的问题解决

    用到了MvcPager.js,在一个常见的场景中出现了不能POST表单数据的问题,场景描述如下: 日期:2012-12-12 编号:*****                             ...

  7. 各业务场景下的技术推荐 【&period;net】

    后端: 1.webapi的token加密:  1)JWT验证算法,不推荐:2)RSA 2.集合的扩展:C5.dll 3.对象映射工具:AutoMapper .TinyMapper 4.任务调度框架:Q ...

  8. Automl基于超大数据下的数据分发方案探讨

    先定义几个关键字: 任务:用户一次上传的数据集并发起的automl任务,比如一次ocr任务,一次图像分类任务. 模型:一次任务中,需要运行的多个模型,比如ocr任务,需要ctpn模型,需要crnn模型 ...

  9. Alibaba高并发业务秒杀系统落地实战文档,已实践某大型秒杀场景

    前言: 高并发,几乎是每个程序员都想拥有的经验.原因很简单:随着流量变大,会遇到各种各样的技术问题,比如接口响应超时.CPU load升高.GC频繁.死锁.大数据量存储等等,这些问题能推动我们在技术深 ...

随机推荐

  1. LeetCode&colon;LRU Cache

    题目大意:设计一个用于LRU cache算法的数据结构. 题目链接.关于LRU的基本知识可参考here 分析:为了保持cache的性能,使查找,插入,删除都有较高的性能,我们使用双向链表(std::l ...

  2. Maven常用插件参数

    1.clean: 清理默认路径以外的文件 <build> [...] <plugin> <artifactId>maven-clean-plugin</art ...

  3. CentOS6 配置

    1.CentOS6 Minimal 安装的情况下,默认网卡不启动,并且默认设置了依赖 NetworkManager 的选项.又因为 Minimal 安装并不会安装系统默认提供的网络管理工具  Netw ...

  4. IE浏览器兼容性的痛苦

    做了一个弹出框的demo,在狐火,chrome,IE11中运行得好好的. 但是在IE8中死活不显示对话框,感觉IE8根本没有执行下面的javascript代码. 甚至,我简单的写alert(123), ...

  5. TControl&period;WMLButtonUp的inherited的作用——是为了给子类控件新的处理消息的机会

    意外注意到这个小细节: procedure TControl.WMLButtonUp(var Message: TWMLButtonUp); begin inherited; // 注意,如果是直接点 ...

  6. 【POJ】3283 Card Hands

    字典树. #include <iostream> #include <cstdio> #include <cstring> #include <string& ...

  7. 神经网络与深度学习笔记 Chapter 1&period;

    转载请注明出处:http://www.cnblogs.com/zhangcaiwang/p/6875533.html sigmoid neuron 微小的输入变化导致微小的输出变化,这种特性将会使得学 ...

  8. Java代码输出是&OpenCurlyDoubleQuote;father”还是&OpenCurlyDoubleQuote;child”(一)

    1.实例 /** * 以下代码输出的结果是 */ package com.you.model; /** * @author YouHaidong * 输出的结果 */ public class Fat ...

  9. UVa 11134 - Fabled Rooks 优先队列,贪心 难度&colon; 0

    题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...

  10. 浅谈postMessage跨域通信与localStorage实现跨域共享

    https://www.cnblogs.com/tyrion1990/p/8134384.html