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

web应用,那本篇我们来看看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

上进行安装部署。

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。

<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,如下图:

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

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

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

高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.NET SOA 负载均衡介绍与实践

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

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

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

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

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

  7. 各业务场景下的技术推荐 【.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. laravel+vue组合的项目中引入ueditor(打包成组件形式)

    前言:最近写东西需要用到ueditor,并且需要是在vue组件中引入. (本博客默认你已经配置了laravel+vue的项目环境,如果还没有配置好的的小伙伴,可以看看我的另一篇博客,链接: http: ...

  2. python全栈阶段测试(一)

    1.执行Python脚本的两种方式 如果想要永久保存代码,就要用文件的方式 如果想要调试代码,就要用交互式的方式 2.Pyhton单行注释和多行注释分别用什么? 单行注释:# 多行注释: '' &qu ...

  3. nyoj_6:喷水装置(一)

    要让总的使用到的装置数尽可能少,则可以贪心每次选取未使用的半径最大的装置 题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=6 #inclu ...

  4. 由于用mpu6050模块,所以要用上i2c通信原理。

    i2c通信原理 i2c总线只有两根双向信号线,一根是数据线SDA,一根是时钟线SCL. 每个接到i2c总线上的器件都有唯一的地址,主机与其他器件之间的数据传送可以是由主机发送给其他器件.主机为发送器, ...

  5. javac.exe、 java.exe、 java虚拟机三者之间的区别与联系

    JDK中 javac:Java编译器,将Java源代码换成字节代: java:Java解释器,直接从类文件执行Java应用程序代码: 先编译  *.java文件――――>*.class文件 运行 ...

  6. iOS开发实战-基于SpriteKit的FlappyBird小游戏

    写在前面 最近一直在忙自己的维P恩的事情 公司项目也是一团乱 于是...随手找了个游戏项目改了改就上线了,就当充数了. SpriteKit简介 SpriteKit是iOS 7之后苹果推出的2D游戏框架 ...

  7. Spring源码情操陶冶-AbstractApplicationContext

    前言-阅读源码有利于陶冶情操,本文承接前文Spring源码情操陶冶-ContextLoader 约束:本文指定contextClass为默认的XmlWebApplicationContext Abst ...

  8. 关于position

    一.position 一)语法: 看了那么久的语法,终于到了讲正题的时间了. 二)定位 1.相对定位:相对元素自己在没有定位之前的位置进行位移,元素仍然保留还没有原来的位置. 特性: 1)不脱离文档流 ...

  9. 小程序server-3-搭建WebSocket 服务

    小程序server-3-搭建WebSocket 服务: 1.安装 Node 模块 使用 ws 模块来在服务器上支持 WebSocket 协议,下面使用 NPM 来安装: cd /var/www/wxp ...

  10. Eclipse中将hadoop项目放在集群中运行

    1.加入配置文件到项目源码目录下(src) <configuration> <property> <name>mapreduce.framework.name< ...