微服务设计:一个调用还是两个单独的API?

时间:2019-10-30 09:38:59

标签: java api microservices

我有一个执行以下逻辑的单片应用程序:

naseem@naseem-Satellite-C850-B177:~/Desktop/hellodotty/src/main/scala$ dotc Main.scala 
Building Dotty...
[info] Loading settings for project global-plugins from idea.sbt ...
[info] Loading global plugins from /home/naseem/.sbt/1.0/plugins
[info] Loading settings for project dotty-build-build from build.sbt ...
[info] Loading project definition from /home/naseem/.sbt/1.0/staging/00a36f6d792ab07b62c5/dotty/project/project
[info] Updating ProjectRef(uri("file:/home/naseem/.sbt/1.0/staging/00a36f6d792ab07b62c5/dotty/project/project/"), "dotty-build-build")...
[info] Done updating.
[info] Compiling 1 Scala source to /home/naseem/.sbt/1.0/staging/00a36f6d792ab07b62c5/dotty/project/project/target/scala-2.12/sbt-1.0/classes ...
[info] Done compiling.
[info] Loading settings for project dotty-build from plugins.sbt,build.sbt ...
[info] Loading project definition from /home/naseem/.sbt/1.0/staging/00a36f6d792ab07b62c5/dotty/project
[info] Updating ProjectRef(uri("file:/home/naseem/.sbt/1.0/staging/00a36f6d792ab07b62c5/dotty/project/"), "dotty-build")...
[info] downloading https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/com.eed3si9n/sbt-buildinfo/scala_2.12/sbt_1.0/0.9.0/jars/sbt-buildinfo.jar ...
[info] downloading https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/com.jsuereth/sbt-pgp/scala_2.12/sbt_1.0/2.0.0/jars/sbt-pgp.jar ...
[info] downloading https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/pl.project13.scala/sbt-jmh/scala_2.12/sbt_1.0/0.3.2/jars/sbt-jmh.jar ...
[info]  [SUCCESSFUL ] pl.project13.scala#sbt-jmh;0.3.2!sbt-jmh.jar (3693ms)
[info]  [SUCCESSFUL ] com.eed3si9n#sbt-buildinfo;0.9.0!sbt-buildinfo.jar (4591ms)
[info]  [SUCCESSFUL ] com.jsuereth#sbt-pgp;2.0.0!sbt-pgp.jar (5110ms)
[info] Done updating.
[warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings.
[info] Compiling 8 Scala sources and 1 Java source to /home/naseem/.sbt/1.0/staging/00a36f6d792ab07b62c5/dotty/project/target/scala-2.12/sbt-1.0/classes ...
[info] Done compiling.
[info] Loading settings for project dotty from build.sbt ...
[info] Resolving key references (15750 settings) ...
[info] Set current project to dotty (in build file:/home/naseem/dotty/)
[error] java.lang.RuntimeException: Could not create directory .vscode
[error]     at scala.sys.package$.error(package.scala:26)
[error]     at sbt.io.IO$.createDirectory(IO.scala:326)
[error]     at sbt.io.IO$.copyImpl(IO.scala:763)
[error]     at sbt.io.IO$.$anonfun$copy$1(IO.scala:754)
[error]     at scala.Function$.$anonfun$tupled$1(Function.scala:77)
[error]     at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:233)
[error]     at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:58)
[error]     at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:51)
[error]     at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47)
[error]     at scala.collection.TraversableLike.map(TraversableLike.scala:233)
[error]     at scala.collection.TraversableLike.map$(TraversableLike.scala:226)
[error]     at scala.collection.AbstractTraversable.map(Traversable.scala:104)
[error]     at sbt.io.IO$.copy(IO.scala:754)
[error]     at sbt.io.IO$.copyDirectory(IO.scala:800)
[error]     at Build$.$anonfun$globalSettings$2(Build.scala:190)
[error]     at scala.Function1.$anonfun$andThen$1(Function1.scala:52)
[error]     at sbt.Project$.setProject(Project.scala:485)
[error]     at sbt.BuiltinCommands$.doLoadProject(Main.scala:840)
[error]     at sbt.BuiltinCommands$.$anonfun$loadProjectImpl$2(Main.scala:800)
[error]     at sbt.Command$.$anonfun$applyEffect$4(Command.scala:142)
[error]     at sbt.Command$.$anonfun$applyEffect$2(Command.scala:137)
[error]     at sbt.Command$.process(Command.scala:181)
[error]     at sbt.MainLoop$.processCommand(MainLoop.scala:151)
[error]     at sbt.MainLoop$.$anonfun$next$2(MainLoop.scala:139)
[error]     at sbt.State$$anon$1.runCmd$1(State.scala:246)
[error]     at sbt.State$$anon$1.process(State.scala:250)
[error]     at sbt.MainLoop$.$anonfun$next$1(MainLoop.scala:139)
[error]     at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error]     at sbt.MainLoop$.next(MainLoop.scala:139)
[error]     at sbt.MainLoop$.run(MainLoop.scala:132)
[error]     at sbt.MainLoop$.$anonfun$runWithNewLog$1(MainLoop.scala:110)
[error]     at sbt.io.Using.apply(Using.scala:22)
[error]     at sbt.MainLoop$.runWithNewLog(MainLoop.scala:104)
[error]     at sbt.MainLoop$.runAndClearLast(MainLoop.scala:59)
[error]     at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:44)
[error]     at sbt.MainLoop$.runLogged(MainLoop.scala:35)
[error]     at sbt.StandardMain$.runManaged(Main.scala:138)
[error]     at sbt.xMain.run(Main.scala:89)
[error]     at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:109)
[error]     at xsbt.boot.Launch$.withContextLoader(Launch.scala:128)
[error]     at xsbt.boot.Launch$.run(Launch.scala:109)
[error]     at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35)
[error]     at xsbt.boot.Launch$.launch(Launch.scala:117)
[error]     at xsbt.boot.Launch$.apply(Launch.scala:18)
[error]     at xsbt.boot.Boot$.runImpl(Boot.scala:56)
[error]     at xsbt.boot.Boot$.main(Boot.scala:18)
[error]     at xsbt.boot.Boot.main(Boot.scala)
[error] Could not create directory .vscode
[error] Use 'last' for the full log.
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? 

现在我正在使用微服务转换我的应用程序,但是在设计调用时遇到了麻烦。

由于可以完全从A推导出B,因此我只想制作一个返回所有数据集A的单个微服务Get a list A (Customer) from database Validate data in A using some criteria, if it's not validated, throw an error Do some operations on A to get a list B (e.g. Regional customers) Do sth with B 。这意味着需要单个数据库访问。这将是性能上的优势。

但是问题是,在A上检索列表B的操作也是商业代码的一部分。因此,如果我们遵循域驱动的设计,则将这些代码放在“客户”微服务端是更合乎逻辑的,而在微服务getCustomerA中,也许在Customer中。

所以我想知道,这种情况下的最佳实践是什么?我们应该优先处理单个数据库调用(第一种情况)还是进行两次调用(但在这种情况下,进行两次数据库调用)呢?

2 个答案:

答案 0 :(得分:3)

由于这主要是基于意见的,所以我只能给您:-)

根据我的经验,仅仅为了做到这一点而将应用程序拆分为微服务,这使技术条条框框于技术简单性之上,并且常常会带来很多不必要的开销。

关于数据库调用,我还可以从经验中告诉您,在执行两个简单的调用而不是执行一个过于复杂的调用时,您常常会赢得性能。特别是如果您开始在许多表上引入大型联接,或者在on子句中使用-ouch-子选择。

查看最简单的解决方案是否有效并保持代码整洁。不断提高质量,并在需要时进行优化。如果您有一条逻辑可以将其拆分为微服务(例如,因为您要使用其他语言,框架或希望卸载某些计算),那么请继续进行下去。

答案 1 :(得分:1)

域驱动设计并不能说明每个边界上下文只能包含一个实体,实际上,当这些实体明确相关时,换句话说,当它们需要关联时,一个边界上下文(或微服务)可以包含多个实体。保持事务性。

在您的情况下,由于两个实体之间的紧密关系,最好的方法是仅构建一个同时执行两项操作的微服务。