-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FAQ(持续更新) #170
Comments
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1 similar comment
谢谢,这么简单,还担心中间异常了会不会中断了,所以想守护下 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@ybbetter 你好~感谢关注workflow~ 因为每个人的使用场景不同,源码阅读建议从自己需要的场景入手比较好,以下是一些小建议:
祝你能够获得更多的思路启发,有任何建设性的提议也欢迎随时与我们交流~ |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1. workflow与k8s的关系
组合场景: 2. workflow完全可以通过二次开发实现nginx的所有功能实际上网络通信只是workflow的其中一种应用场景,但用作web server的时候,我们有和nginx做过同场景下的性能压测。而且我们也自带了upstream模块,通过配置也可以使用多种负载均衡方式对下游发起请求。 nginx有许多我们暂时核心模块所不支持的功能,比如:
但workflow很多点做得比nginx要更通用友好,比如:
3. workflow的分布式、机器学习部署的使用场景感谢对workflow的认可!!!(敲开心 ♪───O(≧∇≦)O────♪ 最后~~~ @eatcosmos 如果你可以把这三个问题单独列到一个新issue就更好了,因为这些问题比较独立宽泛,思路可以分享给其他小伙伴,也有助于我后续号召workflow实际开发者场景的汇总~ |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
您好,心中有一些疑惑向您请教, |
@kernelai 你好呀,其实看看future或者用户态协程的概念就很好理解了。网上评测也有许多,可以到github上找找~具体思路我这里粗浅地帮你梳理一下,仅供参考: 具体问题:异步事件回来了得有个机制来通知我。 1. future 2. 用户态协程 3. callback 这个话题很大,以上仅抛砖引玉,不可能概括得很全面。欢迎动手尝试一下对比,或者再单独发issue追更~~~ |
您好。你是360的小伙伴吧?之前线下见过的。我也觉得这是个好问题可以单开issue讨论, |
感谢您的回答。 |
是的。^~^ |
欢迎把和seastar的对比新开个issue交流。 |
为什么源码里面一点注释都不写呢? |
确实注释有点少。我们希望大多数接口定义本身就能解释自己。有些我们也加了注释。 |
我想使用httpserver传输大文件,如果client建立一个http_task向server请求一个大文件 ,然后server chunked分块传输,client会接受完所有的chunk后再调用callback 吗? |
独立的问题重新发issue吧。 |
WaitGroup的注释较少,可以介绍一下WaitGroup两个函数done() 和wait()的使用方法么? |
你好。WaitGroup不是我们的一个核心组件,一般只在main函数里应用,用于防止程序退出。其它任何地方都是全异步的,不存在等待。 WaitGroup本身也只有wait和done两个操作,例如初始化时传3,那么3次done之后,wait的人就通过了,好像也没有太多需要描述的。 |
多谢回复!
另外,用workflow来处理计算或者计算密集型应用函数,是否可以替代类似OpenMP的多线程编程?
方法上可以把结果矩阵或者向量,通过均分的方法,把大任务划分成多个小任务组成的serial 来start ()完成么?
有数值计算或者高性能多核并行计算类应用,会采用此方法来做性能加速么?适合替代OpenMP么,有优势么?
WaitGroup的注释较少,可以介绍一下WaitGroup两个函数done() 和wait()的使用方法么?
你好。WaitGroup不是我们的一个核心组件,一般只在main函数里应用,用于防止程序退出。其它任何地方都是全异步的,不存在等待。
WaitGroup本身也只有wait和done两个操作,例如初始化时传3,那么3次done之后,wait的人就通过了,好像也没有太多需要描述的。
|
你好,具体问题重新发issue吧。workflow代替openMP应该是比较容易的,你的需求可能可以对应到某一类计算模式上。 |
请问想用workflow来对接 fast-dds,应该怎么入手? |
你好。这个fast-dds我不太了解。可以重新发个issue出来讨论。 |
大佬们好,我是一个正在找c++后端实习的大四生,我在做了几个基础的服务器项目之后想进一步学习高级点的项目,就是想问问这个项目应该从哪里入手,因为没有项目结构,所以好像看着有点困难QAQ。 |
你好。可以按照我们tutorial教程的顺序,把tutorial里的例子都运行一遍,大概就知道玩法了。 我们的文档大多数是使用文档,关于实现原理,可以直接看代码,如果有什么问题随时提issue就可以。 |
项目背景以及解决的问题
C++ Workflow项目起源于搜狗公司的分布式存储项目的通讯引擎,并且发展成为搜狗公司级C++标准,应用于搜狗大多数C++后端服务。项目将通讯与计算和谐统一,帮助用户建立通讯与计算关系非常复杂的高性能服务。但同时用户也可以只把它当成简易的异步网络引擎或并行计算框架来使用。
如何开始使用
以Linux系统为例:
然后就可以愉快的运行示例了。每个示例都有对应的文档讲解。如果需要用到kafka协议,请预先安装snappy和lz4,并且:
$ make KAFKA=y $ cd tutorial $ make KAFKA=y
另外,
make DEBUG=y
,可以编译调试版。通过make REDIS=n MYSQL=n UPSTREAM=n CONSUL=n
可以裁剪掉一个或多个功能,让库文件减小到最低400KB,更加适合嵌入式开发。与其它的网络引擎,RPC项目相比,有什么优势
与其它并行计算框架相比,有什么优势
项目原生包含哪些网络协议
目前我们实现了HTTP,Redis,MySQL和kafka协议。除kafka目前只支持客户端以外,其他协议都是client+server。也就是说,用户可以用于构建Redis或MySQL协议的代理服务器。kafka模块是插件,默认不编译。
为什么用callback
我们用C++11 std::function类型的callback和process来包装用户行为,因此用户需要知道自己是在编写异步程序。我们认为callback方式比future或用户态协程能给程序带来更高的效率,并且能很好的实现通信与计算的统一。由于我们的任务封装方式以及std::function带来的便利,在我们的框架里使用callback并没有太多心智负担,反而非常简单明了。
callback在什么线程里调用
项目的一个特点是由框架来管理线程,除了一些很特殊情况,callback的调用线程必然是处理网络收发和文件IO结果的handler线程(默认数量20)或者计算线程(默认数量等于CPU总核数)。但无论在哪个线程里执行,都不建议在callback里等待或执行特别复杂的计算。需要等待可以用counter任务进行不占线程的wait,复杂计算则应该包装成计算任务。
需要说明的是,框架里的一切资源都是使用时分配。如果用户没有用到网络通信,那么所有和通信相关的线程都不会被创建。
为什么我的任务启动之后没有反应
这是很多新用户都会遇到的问题。框架中几乎所有调用都是非阻塞的,上面的代码在task启动之后main函数立刻return,并不会等待task的执行结束。正确的做法应该是通过某种方式在唤醒主进程,例如:
任务对象的生命周期是什么
框架中任何任务(以及SeriesWork),都是以裸指针形式交给用户。所有任务对象的生命周期,是从对象被创建,到对象的callback完成。也就是说callback之后task指针也就失效了,同时被销毁的也包括task里的数据。如果你需要保留数据,可以用std::move()把数据移走,例如我们需要保留http任务中的resp:
某些情况下,如果用户创建完任务又不想启动了,那么需要调用task->dismiss()直接销毁任务。
需要特别强调,server的process函数不是callback,server任务的callback发生在回复完成之后,而且默认为nullptr。
为什么SeriesWork(串行)不是一种任务
我们关于串并联的定义是:
显然通过这三句话的定义我们可以递归出任意复杂的串并联结构。如果把串行也定义为一种任务,串行就可以由多个子串行组成,那么使用起来就很容易陷入混乱。同样并行只能是若干串行的并,也是为了避免混乱。其实使用中你会发现,串行本质上就是我们的协程。
我需要更一般的有向无环图怎么办
可以使用WFGraphTask,或自己用WFCounterTask来构造。
示例:https://github.com/sogou/workflow/blob/master/tutorial/tutorial-11-graph_task.cc
server是在process函数结束后回复请求吗
不是。server是在server task所在series没有别的任务之后回复请求。如果你不向这个series里添加任何任务,就相当于process结束之后回复。注意不要在process里等待任务的完成,而应该把这个任务添加到series里。
如何让server在收到请求后等一小段时间再回复
错误的方法是在process里直接sleep。正确做法,向server所在的series里添加一个timer任务。以http server为例:
以上代码实现一个100毫秒延迟的http server。一切都是异步执行,等待过程没有线程被占用。
怎么知道回复成功没有
首先回复成功的定义是成功把数据写入tcp缓冲,所以如果回复包很小而且client端没有因为超时等原因关闭了连接,几乎可以认为一定回复成功。需要查看回复结果,只需给server task设置一个callback,callback里状态码和错误码的定义与client task是一样的,但server task不会出现dns错误。
能不能不回复
可以。任何时候调用server task的noreply()方法,那么在原本回复的时机,连接直接关闭。
计算任务的调度规则是什么
我们发现包括WFGoTask在内的所有计算任务,在创建时都需要指定一个计算队列名,这个计算队列名可用于指导我们内部的调度策略。首先,只要有空闲计算线程可用,任务将实时调起,计算队列名不起作用。当计算线程无法实时调起每个任务的时候,那么同一队列名下的任务将按FIFO的顺序被调起,而队列与队列之间则是平等对待。例如,先连续启动n个队列名为A的任务,再连续启动n个队列名为B的任务。那么无论每个任务的cpu耗时分别是多少,也无论计算线程数多少,这两个队列将近倾向于同时执行完毕。这个规律可以扩展到任意队列数量以及任意启动顺序。
为什么使用redis client时无需先建立连接
首先看一下redis client任务的创建接口:
其中url的格式为:redis://:password@host:port/dbnum。port默认值为6379,dbnum默认值为0。
workflow的一个重要特点是由框架来管理连接,使用户接口可以极致的精简,并实现最有效的连接复用。框架根据任务的用户名密码以及dbnum,来查找一个可以复用的连接。如果找不到则发起新连接并进行用户登陆,数据库选择等操作。如果是一个新的host,还要进行DNS解析。请求出错还可能retry。这每一个步骤都是异步并且透明的,用户只需要填写自己的request,将任务启动,就可以在callback里得到请求的结果。唯一需要注意的是,每次任务的创建都需要带着password,因为可能随时有登陆的需要。
同样的方法我们可以用来创建mysql任务。但对于有事务需求的mysql,则需要通过我们的WFMySQLConnection来创建任务了,否则无法保证整个事务都在同一个连接上进行。WFMySQLConnection依然能做到连接和认证过程的异步性。
连接的复用规则是什么
大多数情况下,用户使用框架产生的client任务都是无法指定具体连接。框架会有连接的复用策略:
虽然我们的框架无法指定任务要使用的连接,但是我们支持连接上下文的功能。这个功能对于实现有连接状态的server非常重要。相关的内容可以参考关于连接上下文相关文档。
同一域名下如果有多个IP地址,是否有负载均衡
是的,我们会认为同一域名下的所有目标IP对等,服务能力也相同。因此任何一个请求都会寻找一个从本地看起来负载最轻的目标进行通信,同时也内置了熔断与恢复策略。同一域名下的负载均衡,目标都必须服务在同一端口,而且无法配置不同权重。负载均衡的优先级高于连接复用,也就是说会先选择好通信地址再考虑复用连接问题。
如何实现带权重或不同端口上的负载均衡
可以参考upstream相关文档。upstream还可以实现很多更复杂的服务管理需求。
chunked编码的http body如何最高效访问
很多情况下我们使用HttpMessage::get_parsed_body()来获得http消息体。但从效率角度上考虑,我们并不自动为用户解码chunked编码,而是返回原始body。解码chunked编码可以用HttpChunkCursor,例如:
cursor.next操作每次返回一个chunk的起始位置指针和chunk大小,不进行内存拷贝。使用HttpChunkCursor之前无需判断消息是不是chunk编码,因为非chunk编码也可以认为整体就是一个chunk。
能不能在callback或process里同步等待一个任务完成
我们不推荐这个做法,因为任何任务都可以串进任务流,无需占用线程等待。如果一定要这样做,可以用我们提供的WFFuture来实现。请不要直接使用std::future,因为我们所有通信的callback和process都在一组线程里完成,使用std::future可能会导致所有线程都陷入等待,引发整体死锁。WFFuture通过动态增加线程的方式来解决这个问题。使用WFFuture还需要注意在任务的callback里把要保留的数据(一般是resp)通过std::move移动到结果里,否则callback之后数据会随着任务一起被销毁。
数据如何在task之间传递
最常见的,同一个series里的任务共享series上下文,通过series的get_context()和set_context()的方法来读取和修改。而parallel在它的callback里,也可以通过series_at()获到它所包含的各个series(这些series的callback已经被调用,但会在parallel callback之后才被销毁),从而获取它们的上下文。由于parallel也是一种任务,所以它可以把汇总的结果通过它所在的series context继续传递。
总之,series是协程,series context就是协程的局部变量。parallel是协程的并行,可汇总所有协程的运行结果。
Workflow和rpc的关系
在我们的架构里,rpc是workflow上的应用,或者说rpc是workflow上的一组协议实现。如果你有接口描述,远程接口调用的需求,一定要试用一下srpc,这是一个把workflow的功能发挥到极致又和workflow完美融合的rpc系统,同时兼容brpc和thrift协议且更快更易用,满足你的任何rpc需求。地址:https://github.com/sogou/srpc
Server的stop()操作完成时机
Server的stop()操作是优雅关闭,程序结束之前必须关闭所有server。stop()由shutdown()和wait_finish()组成,wait_finish会等待所有运行中server task所在series结束。也就是说,你可以在server task回复完成的callback里,继续向series追加任务。stop()操作会等待这些任务的结束。另外,如果你同时开多个server,最好的关闭方法是:
如何在收到某个特定请求时,结束server
因为server的结束由shutdown()和wait_finish()组成,显然就可以在process里shutdown,在main()里wait_finish,例如:
以上代码实现一个http server,在收到/stop的请求时结束程序。process中的flag是必须的,因为process并发执行,只能有一个线程来调用shutdown操作。
Server里需要调用非Workflow框架的异步操作怎么办
还是使用counter。在其它异步框架的回调里,对counter进行count操作。
注意以上代码里,counter->count()的调用可能先于counter的启动。但无论什么时序,程序都是完全正确的。
个别https站点抓取失败是什么原因
如果浏览器可以访问,但用workflow抓取失败,很大概率是因为站点使用了TLS扩展功能的SNI。可以通过全局配置打开workflow的客户端SNI功能:
开启这个功能是有一定代价的,所有https站点都会启动SNI,相同IP地址但不同域名的访问,将无法复用SSL连接。
因此用户也可以通过upstream功能,只打开对某个确定域名的SNI功能:
上面的代码把www.sogou.com设置为upstream名,并且加入一个同名的server,同时打开SNI功能。
怎么通过代理服务器访问http资源
方法一(只适用于http任务且无法重定向):
可以通过代理服务器的地址创建http任务,并重新设置request_uri和Host头。假设我们想通过代理服务器www.proxy.com:8080访问http://www.sogou.com/ ,方法如下:
方法二(通用。但有些代理服务器只支持HTTPS。HTTP还是推荐用方法一):
通过带proxy_url的接口创建http任务:
其中proxy_url的格式为:http://user:passwd@your.proxy.com:port/
proxy只能是"http://"开头,而不能是"https://"。port默认值为80。
这个方法适用于http和https URL的代理,可以重定向,重定向时继续使用该代理服务器。
http server是否支持RESTful接口
推荐使用wfrest项目,这是基于workflow的一套RESTful API开发框架,项目地址:https://github.com/wfrest/wfrest
The text was updated successfully, but these errors were encountered: