我们有2个服务,先呼叫S和G。S有一系列步骤,例如a,b,c,d,e,f,在步骤d,它呼叫服务G。G通常花费很多时间(跨分钟)以处理呼叫,从而导致大量超时问题。为了解决这个问题,我们计划使G的API异步。 G有将近20个需要异步创建的API。在设计时,我有两个问题:
使这些异步的理想方法是使用SQS或SNS主题,并使S监听它们。但这是一项侵入性的更改,需要大量代码重构,在这种情况下,请拆分步骤a,b,c,d,e,f。我们正在寻找快速的东西。因此,我们计划将请求ID存储在某个键值存储中,并让G的API在进行基本健全性检查后返回成功,并在后台继续处理请求。完成后,结果将在键值存储中更新,同时G会定期轮询存储。这看起来像是正确的方法吗?
要使G的API异步,我们必须为所有20个API更改/编写大量代码。我当时正在考虑公开一个使用反射来标识在运行时调用哪种方法的API。我知道与反射相关的问题,例如没有编译时错误检测,难以重构,性能降低,并且由于我们在面向外部客户端的API中引入反射,因此在对通过的方法名进行完整性检查时会遇到很多问题。唯一的优点是,它使我的代码更简洁,干扰最小。
我想知道我应该如何解决上述问题。
谢谢
答案 0 :(得分:0)
使G的API异步并不能使其变快。它仅允许与步骤e和f并行运行。如果这些步骤不需要花费太多时间,那么总时间将不会显着减少。
因此,您需要回答的第一个问题是并行化是否完全有帮助。如果您的任务主要是顺序的,那么并行化将无济于事,甚至会使事情变慢。如果您的任务可以并行化,则可以将其表示为执行图。
当您确定并行化有意义时,则可以为每个并行分支选择将其实现为线程还是异步过程调用(APC)。线程更容易编程,但是会消耗一些内存(每个线程0.5-1.0 MB)。通常,如果执行图中有成千上万的并行分支,则值得应用异步编程。我在您的任务中看不到太多的parallelizm,因此我建议使用线程而不是异步过程。
永远不要使用轮询-多线程和异步编程都具有足够的手段来及时响应事件。
对于第二个问题,还是需要一些手工工作。假设您有API:
interface SyncApi {
boolean isPositive(int v1);
int sum(int v1, int v2);
}
那你得写
interface AsyncApi {
Future<Boolean> isPositive(int v1);
Future <Integer> sum(int v1, int v2);
}
您可以制作一个在受SyncApi.java干扰后创建AsyncApi.java的工具,但是无论如何,您都需要在编译时使用AsyncApi接口,以便能够对该接口进行调用。
在给定SyncApi实例的情况下,可以在运行时使用Java Proxy机制来创建用于创建AsyncApi实例的适配器。