Mavuto a batch query processing ndi mayankho awo (Gawo 1)

Mavuto a batch query processing ndi mayankho awo (Gawo 1)Pafupifupi mapulogalamu onse amakono amakhala ndi mautumiki angapo. Nthawi zambiri, kuyankha kwanthawi yayitali kwa njira za interservice kumakhala magwero a zovuta zogwirira ntchito. Njira yothetsera vutoli ndi kunyamula zopempha zingapo za interservice mu phukusi limodzi, lomwe limatchedwa batching.

Ngati mugwiritsa ntchito batch processing, simungasangalale ndi zotsatira zake malinga ndi magwiridwe antchito kapena kumveka bwino kwa ma code. Njira iyi si yosavuta kwa woyimbirayo momwe mungaganizire. Pazifukwa zosiyanasiyana komanso pamikhalidwe yosiyanasiyana, mayankho amatha kukhala osiyana kwambiri. Pogwiritsa ntchito zitsanzo zenizeni, ndikuwonetsa zabwino ndi zoyipa za njira zingapo.

Ntchito yowonetsera

Kuti timveke bwino, tiyeni tiwone chitsanzo cha imodzi mwazinthu zomwe ndikugwiritsa ntchito pano.

Kufotokozera za kusankha nsanja kwa zitsanzoVuto la kusagwira bwino ntchito ndilambiri ndipo silikhudza zilankhulo kapena nsanja. Nkhaniyi igwiritsa ntchito zitsanzo za Spring + Kotlin kuti ziwonetse mavuto ndi mayankho. Kotlin imamvekanso chimodzimodzi (kapena yosamvetsetseka) kwa Java ndi C # opanga, kuwonjezera apo, codeyo ndi yowonjezereka komanso yomveka kuposa Java. Kuti zikhale zosavuta kumvetsetsa kwa opanga Java oyera, ndidzapewa matsenga akuda a Kotlin ndikungogwiritsa ntchito matsenga oyera (mumzimu wa Lombok). Padzakhala njira zowonjezera zochepa, koma ndizodziwika bwino kwa onse opanga mapulogalamu a Java monga njira zosasunthika, kotero izi zidzakhala shuga waung'ono umene sudzawononga kukoma kwa mbale.
Pali ntchito yovomereza zikalata. Winawake amapanga chikalata ndikuchipereka kuti chikakambidwe, pomwe zosintha zimakonzedwa, ndipo pamapeto pake chikalatacho chimagwirizana. Ntchito yovomerezeka palokha sadziwa chilichonse chokhudza zolemba: ndi macheza chabe a ovomereza omwe ali ndi ntchito zina zazing'ono zomwe sitingaganizire pano.

Chifukwa chake, pali zipinda zochezera (zogwirizana ndi zolemba) zomwe zili ndi gulu lodziwikiratu la omwe atenga nawo mbali mu chilichonse mwaiwo. Monga mumacheza wamba, mauthenga amakhala ndi zolemba ndi mafayilo ndipo amatha kukhala mayankho kapena kutumiza:

data class ChatMessage(
  // nullable так как появляется только после persist
  val id: Long? = null,
  /** Ссылка на автора */
  val author: UserReference,
  /** Сообщение */
  val message: String,
  /** Ссылки на аттачи */
  // из-за особенностей связки JPA+СУБД проще поддерживать и null, и пустые списки
  val files: List<FileReference>? = null,
  /** Если является ответом, то здесь будет оригинал */
  val replyTo: ChatMessage? = null,
  /** Если является пересылкой, то здесь будет оригинал */
  val forwardFrom: ChatMessage? = null
)

Fayilo ndi maulalo ogwiritsa ntchito ndi maulalo amadomeni ena. Apa tikukhala motere:

typealias FileReference Long
typealias UserReference Long

Zambiri za ogwiritsa ntchito zimasungidwa ku Keycloak ndikubwezedwa kudzera pa REST. Zomwezo zimapitanso ndi mafayilo: mafayilo ndi chidziwitso chokhudza iwo amakhala muutumiki wosiyana wosungira mafayilo.

Mafoni onse ku mautumikiwa ali zopempha zolemera. Izi zikutanthauza kuti ntchito yonyamula zopemphazi ndi yayikulu kwambiri kuposa nthawi yomwe imayenera kukonzedwa ndi gulu lachitatu. Pamabenchi athu oyesa, nthawi yoyimba foni pazithandizo zotere ndi 100 ms, ndiye tidzagwiritsa ntchito manambalawa mtsogolo.

Tiyenera kupanga chowongolera cha REST chosavuta kuti tilandire mauthenga omaliza a N okhala ndi zofunikira zonse. Ndiko kuti, timakhulupirira kuti chitsanzo cha uthenga chomwe chili kutsogolo chimakhala chofanana ndipo deta yonse iyenera kutumizidwa. Kusiyana pakati pa mtundu wakutsogolo ndikuti fayiloyo ndi wogwiritsa ntchitoyo ayenera kuwonetseredwa mu mawonekedwe osasinthika pang'ono kuti apange maulalo:

/** В таком виде отдаются ссылки на сущности для фронта */
data class ReferenceUI(
  /** Идентификатор для url */
  val ref: String,
  /** Видимое пользователю название ссылки */
  val name: String
)
data class ChatMessageUI(
  val id: Long,
  /** Ссылка на автора */
  val author: ReferenceUI,
  /** Сообщение */
  val message: String,
  /** Ссылки на аттачи */
  val files: List<ReferenceUI>,
  /** Если являтся ответом, то здесь будет оригинал */
  val replyTo: ChatMessageUI? = null,
  /** Если являтся пересылкой, то здесь будет оригинал */
  val forwardFrom: ChatMessageUI? = null
)

Tiyenera kukhazikitsa zotsatirazi:

interface ChatRestApi {
  fun getLast(nInt): List<ChatMessageUI>
}

UI postfix imatanthawuza mitundu ya DTO yakutsogolo, ndiye kuti, zomwe tiyenera kugwiritsa ntchito kudzera pa REST.

Chomwe chingakhale chodabwitsa apa ndikuti sitikudutsa ID iliyonse yochezera ndipo ngakhale mtundu wa ChatMessage/ChatMessageUI ulibe. Ndidachita izi mwadala kuti ndisasokoneze ma code a zitsanzo (macheza ali okha, kotero titha kuganiza kuti tili ndi imodzi yokha).

Kupatuka kwa filosofiMakalasi onse a ChatMessageUI ndi ChatRestApi.getLast amagwiritsa ntchito mtundu wa data wa List pomwe ndi Seti yolamulidwa. Izi ndizoyipa mu JDK, kotero kulengeza dongosolo la zinthu pamlingo wa mawonekedwe (kusunga dongosolo powonjezera ndi kuchotsa) sikungagwire ntchito. Chifukwa chake chakhala chizoloŵezi chogwiritsa ntchito Mndandanda pazochitika zomwe Zokonzedweratu zimafunikira (palinso LinkedHashSet, koma iyi si mawonekedwe).
Zoletsa zofunika: Tidzaganiza kuti palibe unyolo wautali wa mayankho kapena kusamutsa. Ndiko kuti, alipo, koma kutalika kwake sikudutsa mauthenga atatu. Mndandanda wonse wa mauthenga uyenera kutumizidwa kutsogolo.

Kuti mulandire deta kuchokera kuzinthu zakunja pali ma API awa:

interface ChatMessageRepository {
  fun findLast(nInt): List<ChatMessage>
}
data class FileHeadRemote(
  val id: FileReference,
  val name: String
)
interface FileRemoteApi {
  fun getHeadById(idFileReference): FileHeadRemote
  fun getHeadsByIds(idSet<FileReference>): Set<FileHeadRemote>
  fun getHeadsByIds(idList<FileReference>): List<FileHeadRemote>
  fun getHeadsByChat(): List<FileHeadRemote>
}
data class UserRemote(
  val id: UserReference,
  val name: String
)
interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote>
  fun getUsersByIds(idList<UserReference>): List<UserRemote>
}

Zitha kuwoneka kuti mautumiki akunja poyambilira amapereka makonzedwe a batch, komanso m'mitundu yonse iwiri: kudzera mu Seti (popanda kusunga dongosolo la zinthu, ndi makiyi apadera) komanso kudzera mu List (pakhoza kukhala zobwereza - dongosolo lasungidwa).

Kukhazikitsa kosavuta

Kukhazikitsa kwa Naive

Kukhazikitsa koyamba kopanda nzeru kwa wowongolera wathu wa REST kudzawoneka motere nthawi zambiri:

class ChatRestController(
  private val messageRepository: ChatMessageRepository,
  private val userRepository: UserRemoteApi,
  private val fileRepository: FileRemoteApi
) : ChatRestApi {
  override fun getLast(nInt) =
    messageRepository.findLast(n)
      .map it.toFrontModel() }
  
  private fun ChatMessage.toFrontModel(): ChatMessageUI =
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = userRepository.getUserById(author).toFrontReference(),
      message = message,
      files = files?.let files ->
        fileRepository.getHeadsByIds(files)
          .map it.toFrontReference() }
      } ?: listOf(),
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
}

Chilichonse ndi chomveka bwino, ndipo ichi ndi chophatikiza chachikulu.

Timagwiritsa ntchito batch processing ndi kulandira deta kuchokera ku ntchito zakunja m'magulu. Koma chimachitika ndi chiyani pa zokolola zathu?

Pa uthenga uliwonse, kuyitana kumodzi kwa UserRemoteApi kudzapangidwa kuti mupeze deta pamunda wa olemba ndi kuyitana ku FileRemoteApi kuti mutenge mafayilo onse ophatikizidwa. Zikuoneka ngati ndi choncho. Tinene kuti minda ya forwardFrom ndi replyTo ya ChatMessage imapezeka m'njira yoti izi sizikufuna kuyimba foni kosafunikira. Koma kuwasandutsa ChatMessageUI kumabweretsa kubwereza, ndiko kuti, zowerengera zoyimbira zitha kuchuluka kwambiri. Monga taonera kale, tiyeni tiyerekeze kuti tilibe zisa zambiri ndipo unyolo umangokhala ndi mauthenga atatu.

Zotsatira zake, tipeza mafoni awiri mpaka asanu ndi limodzi kupita ku mautumiki akunja pa uthenga uliwonse ndi kuyimba kumodzi kwa JPA kwa phukusi lonse la mauthenga. Chiwerengero chonse cha mafoni chidzasiyana kuchokera ku 2*N+1 mpaka 6*N+1. Kodi izi ndi ndalama zingati m'mayunitsi enieni? Tinene kuti pamafunika mauthenga 20 kuti apereke tsamba. Kuti muwalandire, zidzatenga kuchokera ku 4 mpaka 10 s. Zowopsa! Ndikufuna kuyisunga mkati mwa 500 ms. Ndipo popeza amalota kupanga kupukuta kopanda msoko kutsogolo, zofunikira pakumaliza izi zitha kuwirikiza kawiri.

Zotsatira:

  1. Khodiyo ndi yachidule komanso yodzilemba yokha (maloto a gulu lothandizira).
  2. Khodiyo ndi yosavuta, kotero palibe pafupifupi mwayi wodziwombera pamapazi.
  3. Kusintha kwa batch sikuwoneka ngati kwachilendo ndipo kumaphatikizidwa mumalingaliro.
  4. Kusintha kwamalingaliro kudzapangidwa mosavuta ndipo kudzakhala komweko.

Kuchotsa:

Kuchita koyipa chifukwa cha mapaketi ang'onoang'ono.

Njirayi imatha kuwoneka nthawi zambiri m'mautumiki osavuta kapena ma prototypes. Ngati kufulumira kwa kusintha kuli kofunikira, sikoyenera kusokoneza dongosolo. Panthawi imodzimodziyo, pa ntchito yathu yosavuta kwambiri ntchitoyo ndi yowopsya, kotero kukula kwa njira iyi ndi yopapatiza kwambiri.

Naive parallel processing

Mukhoza kuyamba kukonza mauthenga onse mofanana - izi zidzakuthandizani kuchotsa kuwonjezereka kwa nthawi kutengera kuchuluka kwa mauthenga. Iyi si njira yabwino kwambiri chifukwa idzabweretsa chiwongola dzanja chachikulu pa ntchito yakunja.

Kukhazikitsa parallel processing ndikosavuta:

override fun getLast(nInt) =
  messageRepository.findLast(n).parallelStream()
    .map it.toFrontModel() }
    .collect(toList())

Pogwiritsa ntchito kukonzanso uthenga wofananira, timapeza 300-700 ms moyenera, zomwe zili bwino kuposa kugwiritsa ntchito mosadziwa, koma osathamanga mokwanira.

Ndi njirayi, zopempha kwa userRepository ndi fileRepository zidzachitidwa synchronously, zomwe sizothandiza kwambiri. Kuti mukonze izi, muyenera kusintha logic yoyimbira kwambiri. Mwachitsanzo, kudzera pa CompletionStage (aka CompletableFuture):

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  CompletableFuture.supplyAsync {
    userRepository.getUserById(author).toFrontReference()
  }.thenCombine(
    files?.let {
      CompletableFuture.supplyAsync {
        fileRepository.getHeadsByIds(files).map it.toFrontReference() }
      }
    } ?: CompletableFuture.completedFuture(listOf())
  ) authorfiles ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }.get()!!

Zitha kuwoneka kuti manambala osavuta a mapu sakhala omveka bwino. Izi ndichifukwa choti tidayenera kulekanitsa mafoni ku mautumiki akunja kuchokera komwe zotsatira zake zimagwiritsidwa ntchito. Izi mwazokha sizoyipa. Koma kuphatikiza mafoni sikuwoneka kokongola kwambiri ndipo kumafanana ndi "Noodle" wamba.

Mukamagwiritsa ntchito coroutines, zonse zidzawoneka bwino:

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  join(
    userRepository.getUserById(author).toFrontReference() },
    files?.let fileRepository.getHeadsByIds(files)
      .map it.toFrontReference() } } ?: listOf() }
  ).let (author, files) ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }

Kumeneko:

fun <ABjoin(a: () -> Ab: () -> B) =
  runBlocking(IO{
    awaitAll(async a() }async b() })
  }.let {
    it[0as to it[1as B
  }

Mwachidziwitso, pogwiritsa ntchito njira zofananazi, tidzapeza 200-400 ms, yomwe ili pafupi ndi zomwe tikuyembekezera.

Tsoka ilo, kufanana kwabwino kotereku kulibe, ndipo mtengo wolipirira ndi wankhanza kwambiri: ndi ogwiritsa ntchito ochepa okha omwe amagwira ntchito nthawi yomweyo, zopempha zambiri zidzagwera pazithandizo, zomwe sizingasinthidwe mofanana, kotero ife adzabwerera ku zachisoni zathu 4 s.

Chotsatira changa mukamagwiritsa ntchito ntchitoyi ndi 1300-1700 ms pokonza mauthenga 20. Izi ndizofulumira kuposa momwe zimakhalira poyamba, komabe sizithetsa vutoli.

Njira zina zogwiritsira ntchito mafunso ofananaNanga bwanji ngati ntchito za chipani chachitatu sizipereka ma batch processing? Mwachitsanzo, mutha kubisa kusowa kwa batch processing kukhazikitsa mkati mwa njira zolumikizirana:

interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toSet())
  fun getUsersByIds(idList<UserReference>): List<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toList())
}

Izi ndizomveka ngati mukuyembekeza kuwona kusintha kwa batch mumitundu yamtsogolo.
Zotsatira:

  1. Yesetsani kugwiritsa ntchito mawu ofananira mosavuta.
  2. scalability wabwino.

Wotsatsa:

  1. Kufunika kolekanitsa kupeza kwa data kuchokera pakukonza kwake pokonza zopempha kuzinthu zosiyanasiyana mofanana.
  2. Kuchulukirachulukira pa ntchito za chipani chachitatu.

Zitha kuwoneka kuti kuchuluka kwa kugwiritsiridwa ntchito kuli pafupifupi kofanana ndi kwa njira yopanda nzeru. Ndizomveka kugwiritsa ntchito njira yofunsira yofananira ngati mukufuna kuwonjezera magwiridwe antchito anu kangapo chifukwa cha nkhanza za ena. Mu chitsanzo chathu, magwiridwe antchito adakula ndi nthawi 2,5, koma izi sizokwanira.

posungira

Mutha kuchita caching mu mzimu wa JPA pazantchito zakunja, ndiye kuti, sitolo idalandira zinthu mkati mwa gawo kuti musazilandirenso (kuphatikiza pakukonza batch). Mutha kupanga cache zotere nokha, mutha kugwiritsa ntchito Spring ndi @Cacheable, kuphatikiza mutha kugwiritsa ntchito posungira okonzeka ngati EhCache pamanja.

Vuto lofala lingakhale loti ma cache ndi othandiza ngati ali ndi kugunda. Kwa ife, kugunda kwa olemba ndizotheka kwambiri (tinene, 50%), koma sipadzakhala kugunda pamafayilo konse. Njira iyi ipereka zosintha zina, koma sizisintha kwambiri magwiridwe antchito (ndipo tikufunika kuwongolera).

Ma cache a intersession (aatali) amafunikira zovuta zolepheretsa. Nthawi zambiri, mukadzafika kumapeto kuti muthane ndi vuto la magwiridwe antchito pogwiritsa ntchito ma intersession cache, ndibwino.

Zotsatira:

  1. Gwiritsani ntchito caching popanda kusintha code.
  2. Kuchulukitsa zokolola kangapo (nthawi zina).

Wotsatsa:

  1. Kuthekera kwa kuchepa kwa magwiridwe antchito ngati kugwiritsidwa ntchito molakwika.
  2. Kukumbukira kwakukulu, makamaka ndi ma cache aatali.
  3. Kusavomerezeka kovutirapo, zolakwika zomwe zingayambitse zovuta kutulutsanso nthawi yothamanga.

Nthawi zambiri, ma cache amagwiritsidwa ntchito kuti athetse msanga zovuta zamapangidwe. Izi sizikutanthauza kuti sayenera kugwiritsidwa ntchito. Komabe, nthawi zonse muyenera kuwasamalira mosamala ndikuwunika kaye kuchuluka kwa magwiridwe antchito, kenako ndikupanga chisankho.

Mu chitsanzo chathu, ma cache apereka chiwonjezeko cha ntchito pafupifupi 25%. Nthawi yomweyo, ma cache amakhala ndi zovuta zambiri, chifukwa chake sindingawagwiritse ntchito pano.

Zotsatira

Chifukwa chake, tidayang'ana pakukhazikitsa kopanda nzeru kwa ntchito yomwe imagwiritsa ntchito ma batch processing, ndi njira zina zosavuta zofulumizitsa.

Ubwino waukulu wa njira zonsezi ndi kuphweka, komwe kuli zotsatira zambiri zosangalatsa.

Vuto lofala ndi njirazi ndi kusagwira bwino ntchito, makamaka chifukwa cha kukula kwa mapaketi. Choncho, ngati njirazi sizikugwirizana ndi inu, ndiye kuti ndi bwino kuganizira njira zowonjezereka.

Pali njira ziwiri zazikulu zomwe mungayang'anire mayankho:

  • Asynchronous ntchito ndi deta (imafuna kusintha kwa paradigm, kotero sikukukambidwa m'nkhaniyi);
  • kukulitsa ma batches ndikusunga ma synchronous processing.

Kukula kwa magulu kudzachepetsa kwambiri kuchuluka kwa mafoni akunja ndipo nthawi yomweyo kusunga kachidindo kofanana. Mbali yotsatira ya nkhaniyi ifotokoza za mutuwu.

Source: www.habr.com

Kuwonjezera ndemanga