Ruka hadi kwenye maudhui kuu
OpenAI

22 Januari 2026

Uhandisi

Kuongeza PostgreSQL ili ihudumie watumiaji milioni 800 wa ChatGPT

Na Bohan Zhang, Mwanachama wa Wafanyakazi wa Kiufundi

Inapakia…

Kwa miaka mingi, PostgreSQL imekuwa mojawapo ya mifumo muhimu zaidi ya data inayofanya kazi nyuma ya pazia, ikiendesha bidhaa za msingi kama ChatGPT na API ya OpenAI. Kadiri idadi ya watumiaji wetu inavyoongezeka kwa kasi, ndivyo mahitaji kwenye hifadhidata zetu yameongezeka kwa kasi sana pia. Katika mwaka uliopita, mzigo wetu wa PostgreSQL umeongezeka zaidi ya mara 10, na unaendelea kuongezeka kwa haraka.

Juhudi zetu za kuendeleza miundombinu yetu ya uzalishaji ili kudumisha ukuaji huu zilifichua ufahamu mpya: PostgreSQL inaweza kupanuliwa ili kuhimili kwa uaminifu mizigo mikubwa zaidi ya kazi zinazotegemea usomaji kuliko wengi walivyodhani hapo awali. Mfumo (ulioundwa awali na timu ya wanasayansi katika Chuo Kikuu cha California, Berkeley) umetuwezesha kuhimili trafiki kubwa ya kimataifa kwa kutumia mfano nyumbufu wa sava moja ya msingi Azure PostgreSQL (fungua katika dirisha jipya) na karibu nakala 50 za kusoma zilizosambazwa katika maeneo mengi duniani kote. Hii ni hadithi ya jinsi tulivyopanua PostgreSQL katika OpenAI ili kuhimili mamilioni ya maswali kwa sekunde kwa watumiaji milioni 800 kupitia uboreshaji wa kina na uhandisi thabiti; pia tutashughulikia mambo muhimu tuliyojifunza njiani.

Nyufa katika muundo wetu wa awali

Baada ya uzinduzi wa ChatGPT, trafiki ilikua kwa kasi isiyo ya kawaida. Ili kuiunga mkono, tulitekeleza kwa haraka uboreshaji wa kina katika tabaka za programu na hifadhidata ya PostgreSQL, tukapanua kwa kuongeza ukubwa wa tukio, na tukapanua kwa kuongeza nakala zaidi za kusoma. Usanifu huu umetutumikia vizuri kwa muda mrefu. Kwa maboresho yanayoendelea, inaendelea kutoa nafasi ya kutosha kwa ukuaji wa baadaye.

Inaweza kusikika ya kushangaza kwamba usanifu mmoja wa msingi unaweza kukidhi mahitaji ya kiwango cha OpenAI; hata hivyo, kufanya hili lifanye kazi kwa vitendo si rahisi. Tumeona SEVs kadhaa zilisababishwa na mzigo wa ziada wa Postgres, na mara nyingi hufuata muundo uleule: tatizo la chanzo husababisha ongezeko ghafla la mzigo wa hifadhidata, kama vile matatizo yaliyoenea ya akiba kutokana na hitilafu ya safu ya akiba, ongezeko la majedwali zaidi ghali yanayojaza CPU, au uandishi bunifu unaotokana na uzinduzi wa kipengele kipya. Kadiri matumizi ya rasilimali yanavyoongezeka, muda wa kusubiri wa hoja huongezeka na muda wake wa maombi huanza kumalizika. Majaribio ya kurudia huongeza mzigo zaidi, na kusababisha mzunguko mbaya wenye uwezekano wa kudhoofisha huduma zote za ChatGPT na API.

Mchoro wa kiwango cha mzigo

Ingawa PostgreSQL inapanuka vizuri kwa mizigo yetu ya kazi inayotegemea zaidi usomaji, bado tunakumbana na changamoto wakati wa vipindi vya trafiki kubwa ya uandishi. Hii kwa kiasi kikubwa inatokana na utekelezaji wa PostgreSQL wa udhibiti wa mlingano wa matoleo mengi (MVCC), ambao huifanya isiwe na ufanisi kwa mizigo ya kazi yenye uandishi mwingi. Kwa mfano, wakati swali linasasisha tupli au hata uga mmoja, safu nzima hunakiliwa ili kuunda toleo jipya. Chini ya mizigo mikubwa ya uandishi, hii husababisha kuongezeka kwa kiasi kikubwa kwa uandishi. Pia huongeza ukuzaji wa usomaji, kwa kuwa maswali lazima yachanganue matoleo mengi ya tupli (tupli zilizokufa) ili kupata toleo la hivi karibuni. MVCC huleta changamoto za ziada kama vile kuongezeka kwa jedwali na faharisi, kuongezeka kwa mzigo wa matengenezo ya faharisi, na urekebishaji changamano wa kisafisha tupli. (Mnaweza kupata uchambuzi wa kina wa masuala haya katika blogu niliyoandika pamoja na Prof. Andy Pavlo katika Chuo Kikuu cha Carnegie Mellon inayoitwa Sehemu ya PostgreSQL Tunayoichukia Zaidi(fungua katika dirisha jipya), iliyotajwa(fungua katika dirisha jipya) katika ukurasa wa Wikipedia wa PostgreSQL.)

Kuongeza PostgreSQL kufikia mamilioni ya QPS

Ili kupunguza vikwazo hivi na kupunguza shinikizo la uandishi, tumehamisha, na tunaendelea kuhamisha, kugawanya (k.m. mizigo ya kazi inayoweza kugawanywa), mizigo ya kazi yenye uandishi mwingi kwa mifumo iliyogawanywa vipande kama Azure Cosmos DB, kuboresha mantiki ya programu ili kupunguza uandishi usio wa lazima. Pia haturuhusu tena kuongeza majedwali mapya kwenye utekelezaji wa sasa wa PostgreSQL. Mizigo mipya ya kazi kwa chaguomsingi huingia kwenye mifumo iliyogawanywa.

Huku miundombinu yetu ikiendelea kubadilika, PostgreSQL imeendelea kubaki bila kugawanywa, huku tukio moja la msingi likihudumia maandiko yote. Sababu kuu ni kwamba kugawanya mzigo wa kazi wa programu uliopo kuwa vipande kungekuwa changamano sana na kuchukua muda mwingi, hivyo kuhitaji mabadiliko kwenye mamia ya sehemu za mwisho za programu na huenda ikachukua miezi au hata miaka. Kwa kuwa mizigo yetu ya kazi kwa kiasi kikubwa inahusisha usomaji, na tumetekeleza uboreshaji wa kina, usanifu wa sasa bado unatoa nafasi ya kutosha ya ziada ili kuunga mkono ukuaji unaoendelea wa trafiki. Ingawa hatuondoi uwezekano wa kugawanya PostgreSQL katika siku zijazo, si kipaumbele cha hivi karibuni kwa kuzingatia nafasi ya kutosha tuliyo nayo ya ukuaji wa sasa na wa baadaye.

Katika sehemu zifuatazo, tutaingia kwa undani katika changamoto tulizokumbana nazo na uboreshaji wa kina tuliotekeleza ili kuzishughulikia na kuzuia kukatika kwa huduma siku zijazo, tukisukuma PostgreSQL hadi kwa upeo wake na kuiongeza hadi mamilioni ya maswali kwa sekunde (QPS).

Kupunguza mzigo kwenye sehemu msingi

Changamoto: Ukiwa na mwandishi mmoja tu, usanidi wa msingi mmoja hauwezi kupanua uandishi. Kuongozeka sana kwa uandishi kunaweza haraka kulemea mfumo wa msingi na kuathiri huduma kama vile ChatGPT na API yetu.

Suluhisho: Tunapunguza mzigo kwenye msingi kadri iwezekanavyo—kusoma na kuandika—ili kuhakikisha una uwezo wa kutosha kushughulikia ongezeko la ghafla la uandishi. Trafiki ya usomaji inahamishiwa kwa nakala rudufu inapowezekana. Hata hivyo, baadhi ya maswali ya kusoma lazima yabaki kwenye msingi kwa sababu ni sehemu ya miamala ya uandishi. Kwa hizo, tunalenga kuhakikisha zina ufanisi na kuepuka maswali ya polepole. Kwa trafiki ya kuandika, tumehamisha mizigo ya kazi inayoweza kugawanywa na yenye uandishi mwingi hadi kwenye mifumo iliyogawanywa kama Azure CosmosDB. Mizigo ya kazi ambayo ni ngumu zaidi kugawanya lakini bado huzalisha kiasi kikubwa cha uandishi huchukua muda mrefu zaidi kuhamishwa, na mchakato huo bado unaendelea. Pia tuliimarisha kwa nguvu programu zetu ili kupunguza mzigo wa uandishi; kwa mfano, tumerekebisha hitilafu za programu zilizosababisha uandishi wa ziada na kuanzisha uandishi wa uvivu, inapofaa, ili kulainisha miinuko ya trafiki. Aidha, tunapojaza upya sehemu za jedwali, tunatekeleza vikomo vikali vya kiwango ili kuzuia shinikizo la kuandika kupita kiasi.

Uboreshaji wa maswali

Changamoto: Tulibaini maswali kadhaa yenye gharama kubwa katika PostgreSQL. Hapo awali, ongezeko la ghafla la idadi ya maswali haya lingetumia kiasi kikubwa cha CPU, na kupunguza kasi ya ChatGPT na maombi ya API.

Suluhisho: Maswali machache ya gharama kubwa, kama vile yale yanayounganisha majedwali mengi pamoja, yanaweza kudhoofisha kwa kiasi kikubwa au hata kusababisha huduma nzima kuanguka. Tunahitaji kuendelea kuboresha maswali ya PostgreSQL ili kuhakikisha yana ufanisi na kuepuka mifumo isiyofaa ya kawaida ya Usindikaji wa Muamala Mtandaoni (OLTP). Kwa mfano, wakati mmoja tuligundua swali lenye gharama kubwa sana lililounganisha jedwali 12, ambapo ongezeko la matumizi katika swali hili lilisababisha SEVs zilizozidi ubaya wa juu. Tunapaswa kuepuka miunganisho changamano ya jedwali nyingi inapowezekana. Iwapo unganisho ni lazima, tulijifunza kuzingatia kugawanya swali na kuhamisha mantiki changamano ya unganisho hadi kwenye safu ya programu badala yake. Maswali mengi kati ya haya yenye matatizo huzalishwa na mifumo ya Object-Relational Mapping (ORMs), kwa hivyo ni muhimu kukagua kwa makini SQL zinazozalisha na kuhakikisha inafanya kazi kama inavyotarajiwa. Pia ni kawaida kupata maswali yasiyotumika yanayoendelea kwa muda mrefu katika PostgreSQL. Kusanidi muda wa kusubiri kama idle_in_transaction_session_timeout ni muhimu ili kuzuia autovacuum kuzuiwa.

Kupunguza kushindwa kwa sehemu moja

Changamoto: Ikiwa nakala ya kusoma itashindwa, bado trafiki inaweza kuelekezwa kwa nakala nyingine. Hata hivyo, kutegemea mwandishi mmoja kunamaanisha kuwa na sehemu moja ya kushindwa—ikiwa itashindwa, huduma nzima itaathirika.

Suluhisho: Maombi muhimu zaidi yanahusisha tu maswali ya kusoma. Ili kupunguza hatari ya sehemu moja ya kushindwa kwenye sehemu msingi, tulihamisha usomaji huo kutoka kwa mwandishi kwenda kwa nakala, tukihakikisha maombi hayo yanaweza kuendelea kuhudumiwa hata sehemu msingi itashindwa. Ingawa shughuli za kuandika bado zingeshindwa, athari imepunguzwa; si SEV0 tena kwa kuwa usomaji bado unapatikana.

Ili kupunguza hitilafu za msingi, tunaendesha mfumo wa msingi katika hali ya Upatikanaji wa Juu (HA) na kwa kutumia mfumo mbadala, nakala inayosawazishwa kwa mfululizo ambayo iko tayari kila wakati kuchukua nafasi ya kuhudumia trafiki. Ikiwa mfumo wa msingi utashindwa au unahitaji kuondolewa mtandaoni kwa ajili ya matengenezo, tunaweza kukuza kwa haraka mfumo wa kusubiri ili kupunguza muda wa kukatika. Timu ya Azure PostgreSQL imefanya kazi kubwa kuhakikisha kwamba mabadiliko haya ya kushindwa yanabaki salama na ya kuaminika hata chini ya mzigo mkubwa sana. Ili kushughulikia hitilafu za nakala za kusoma, tunatumia nakala nyingi katika kila eneo zikiwa na nafasi ya ziada ya kutosha ya uwezo, hivyo kuhakikisha kuwa hitilafu ya nakala moja haisababishi katizo la kikanda.

Kutenga mzigo wa kazi

Changamoto: Mara nyingi tunakutana na hali ambapo maombi fulani hutumia kiasi kisicho sawia cha rasilimali kwenye matukio ya PostgreSQL. Hii inaweza kusababisha utendaji duni kwa mizigo mingine ya kazi inayoendeshwa kwenye matukio sawia. Kwa mfano, uzinduzi wa kipengele kipya unaweza kuanzisha maswali yasiyofaa ambayo hutumia sana CPU ya PostgreSQL, na hivyo kupunguza kasi ya maombi ya vipengele vingine muhimu.

Suluhisho: Ili kupunguza tatizo la “jirani mwenye kelele”, tunatenga mizigo ya kazi kwenye matukio maalum ili kuhakikisha kwamba ongezeko la ghafla la maombi yanayotumia rasilimali nyingi haliathiri trafiki nyingine. Hasa, tunagawanya maombi katika viwango vya kipaumbele cha chini na kipaumbele cha juu na kuyaelekeza kwenye matukio tofauti. Kwa njia hii, hata kama mzigo wa kazi wa kipaumbele cha chini utakuwa mzito kwa rasilimali, hautapunguza utendaji wa maombi ya kipaumbele cha juu. Tunatumia mkakati sawa katika bidhaa na huduma mbalimbali pia, ili shughuli kutoka kwa bidhaa moja isiathiri utendaji au kutegemewa kwa nyingine.

Mkusanyiko wa miunganisho ya hifadhidata

Changamoto: Kila tukio lina kikomo cha juu cha miunganisho (5,000 katika Azure PostgreSQL). Ni rahisi kuishiwa na miunganisho au kukusanya miunganisho mingi isiyofanya kazi. Hapo awali, tumekuwa na matukio yaliyosababishwa na trafiki za miunganisho ambazo zilitumia miunganisho yote iliyopatikana.

Suluhisho: Tulipeleka PgBouncer kama safu wakilishi ili kukusanya miunganisho ya hifadhidata. Kuiendesha katika hali ya mkusanyiko wa kauli au muamala huturuhusu kutumia tena miunganisho kwa ufanisi, na hivyo kupunguza kwa kiasi kikubwa idadi ya miunganisho ya wateja wanaoitumia. Hii pia inapunguza muda wa kusubiri wa kuanzisha muunganisho: katika vipimo vyetu, wastani wa muda wa muunganisho ulipungua kutoka milisekunde 50 (ms) hadi milisekunde 5 (ms). Miunganisho na maombi ya kati ya maeneo yanaweza kuwa ghali, kwa hivyo tunaweka wawakilishi, wateja, na nakala katika eneo moja ili kupunguza mzigo wa mtandao na muda wa matumizi ya muunganisho. Zaidi ya hayo, PgBouncer lazima usanidiwe kwa makini. Mipangilio kama vile muda wa kutotumika ni muhimu ili kuzuia uchovu wa miunganisho.

mchoro mbadala wa postgreSQL

Kila somo linalofanana lina deployment yake ya Kubernetes inayoendesha PgBouncer pods nyingi. Tunaendesha utekelezaji mwingi wa Kubernetes nyuma ya Huduma ileile ya Kubernetes, ambayo husawazisha trafiki kwenye podi.

Uwekaji akiba

Changamoto: Ongezeko la ghafla la ukosefu wa akiba linaweza kusababisha kuongezeka kwa usomaji kwenye hifadhidata ya PostgreSQL, kusababisha CPU kusongamana na kupunguza kasi ya maombi ya watumiaji.

Suluhisho: Ili kupunguza shinikizo la usomaji kwenye PostgreSQL, tunatumia safu ya uwekaji akiba kuhudumia sehemu kubwa ya trafiki ya usomaji. Hata hivyo, viwango vya maombi ya akiba vikishuka bila kutarajiwa, mlipuko wa akiba zinazokosekana unaweza kusukuma kiasi kikubwa cha maombi moja kwa moja kwa PostgreSQL. Ongezeko hili la ghafla la usomaji wa hifadhidata linatumia rasilimali nyingi, na kupunguza kasi ya huduma. Ili kuzuia mzigo kupita kiasi wakati wa tatizo la maombi ya akiba zilizopitwa na wakati, tunatekeleza utaratibu wa kufunga akiba (na kukodisha) ili msomaji mmoja tu anayekosa ufunguo mahsusi ndiye anayechukua data kutoka PostgreSQL. Wakati maombi mengi yanapokosekana kwenye ufunguo wa akiba ileile, ombi moja tu ndilo linapata kufuli na kuendelea kupata data na kujaza upya akiba. Maombi mengine yote yanasubiri akiba isasishwe badala ya yote kugonga PostgreSQL kwa wakati mmoja. Hii inapunguza pakubwa usomaji wa hifadhidata unaojirudia na hulinda mfumo dhidi ya kupanga kwa mfuatano ongezeko la mzigo.

Kuongeza nakala za kusoma

Changamoto: Msingi husambaza data ya Write Ahead Log (WAL) kwa kila nakala ya kusoma. Kadiri idadi ya nakala inavyoongezeka, ndivyo msingi lazima utume WAL kwa matukio zaidi, na hivyo kuongeza shinikizo kwa upana wa bendi wa mtandao na CPU. Hii husababisha ucheleweshaji wa nakala ulio juu zaidi na usio thabiti zaidi, jambo linalofanya mfumo kuwa mgumu zaidi kupanua kwa uaminifu.

Suluhisho: Tunaendesha karibu nakala 50 za kusoma katika maeneo mengi ya kijiografia ili kupunguza muda wa kusubiri. Hata hivyo, kwa usanifu wa sasa, msingi lazima utiririshe WAL kwa kila nakala. Ingawa kwa sasa inapanuka vizuri kwa aina za mifano mikubwa sana na bandwidth ya mtandao ya juu, hatuwezi kuendelea kuongeza nakala bila kikomo bila hatimaye kupakia msingi kupita kiasi. Ili kushughulikia hili, tunashirikiana na timu ya Azure PostgreSQL kuhusu kupitisha nakala(fungua katika dirisha jipya), ambapo nakala za kati husambaza WAL kwa nakala za chini. Mbinu hii inatuwezesha kupanua hadi kufikia zaidi ya nakala mia moja bila kuilemea nakala ya msingi. Hata hivyo, pia inaleta ugumu wa ziada wa kiutendaji, hasa kuhusu usimamizi wa uhamishaji wa hitilafu. Kipengele hiki bado kinajaribiwa; tutahakikisha ni thabiti na kinaweza kuhamisha hitilafu kwa usalama kabla ya kukisambaza iende kwa uzalishaji.

Mchoro wa urudufu wa mfululizo wa postgreSQL

Vikomo vya viwango

Changamoto: Mlipuko wa ghafla wa trafiki kwenye sehemu mahususi za mwisho, ongezeko la maswali ghali, au maombi ya majario ya kurudia yanaweza kumaliza kwa haraka rasilimali muhimu kama vile CPU, I/O, na miunganisho, na kusababisha kushuka kwa huduma kwa kiwango kikubwa.

Suluhisho: Tulitekeleza vikomo vya viwango katika tabaka mbalimbali—programu, kikusanyaji miunganisho, proksi, na hoja—ili kuzuia ongezeko la ghafla la trafiki lisizidi uwezo wa matukio ya hifadhidata na kusababisha hitilafu za mfululizo. Pia ni muhimu kuepuka vipindi vifupi sana vya kujaribu tena, ambavyo vinaweza kusababisha maombi ya majaribio ya kurudia. Pia tuliboresha safu ya ORM ili kusaidia kuweka vikomo vya kiwango na inapohitajika, kuzuia kabisa muhtasari mahususi wa maswali. Aina hii ya kupunguza mzigo inayolengwa huwezesha urejeshaji wa haraka kutokana na ongezeko la ghafla la maswali yenye gharama kubwa.

Usimamizi wa kielezo

Changamoto: Hata mabadiliko madogo ya kielezo, kama vile kubadilisha aina ya safu, yanaweza kusababisha uandishi upya wa jedwali lote(fungua katika dirisha jipya). Kwa hivyo, tunatekeleza mabadiliko ya kielezo kwa uangalifu—tukiyapunguza kwa shughuli nyepesi na kuepuka yoyote zinazoandika upya majedwali yote.

Suluhisho: Ni mabadiliko mepesi ya kielezo pekee yanayoruhusiwa, kama vile kuongeza au kuondoa safu wima fulani ambazo hazisababishi uandishi upya kamili wa jedwali. Tunatekeleza kikamilifu muda wa kusubiri wa sekunde 5 kwa mabadiliko ya kielezo. Kuunda na kuondoa faharisi kwa wakati mmoja kunaruhusiwa. Mabadiliko ya kielezo yamezuiwa kwa majedwali yaliyopo. Ikiwa kipengele kipya kinahitaji majedwali ya ziada, lazima yawe katika mifumo mbadala ya kusambaza kama vile Azure CosmosDB badala ya PostgreSQL. Tunapojaza tena sehemu ya jedwali, tunatumia vikomo vikali vya kiwango ili kuzuia ongezeko la ghafla la uandishi. Ingawa mchakato huu wakati mwingine unaweza kuchukua zaidi ya wiki moja, unahakikisha uthabiti na huepuka athari zozote za uzalishaji.

Matokeo na njia iliyo mbele

Juhudi hii inaonyesha kwamba kwa usanifu na uboreshaji sahihi, Azure PostgreSQL inaweza kupanuliwa ili kushughulikia mizigo mikubwa zaidi ya kazi za uzalishaji. PostgreSQL hushughulikia mamilioni ya QPS ya mizigo ya kazi inayotegemea sana usomaji, ikiendesha bidhaa muhimu zaidi za OpenAI kama ChatGPT na jukwaa la API. Tuliongeza karibu nakala 50 za kusoma, huku tukidumisha ucheleweshaji wa urudufishaji karibu na sifuri, tukahakikisha usomaji wa ucheleweshaji mdogo katika maeneo yaliyosambazwa kijiografia, na tukaunda akiba ya kutosha ya uwezo ili kusaidia ukuaji wa siku zijazo.

Upanuzi huu unafanya kazi huku ukiendelea kupunguza ucheleweshaji na kuboresha uaminifu. Tunatoa kwa uthabiti ucheleweshaji mdogo wa upande wa mteja wa p99 wa milisekunde za tarakimu mbili za chini na upatikanaji wa asilimia tisini na tisa nukta tisa tisa tisa tisa katika uzalishaji. Na katika kipindi cha miezi 12 iliyopita, tumekuwa na tukio moja tu la SEV-0 la PostgreSQL (lilitokea wakati wa uzinduzi wa virusi(fungua katika dirisha jipya) wa ChatGPT ImageGen, wakati trafiki ya uandishi ilipoongezeka ghafla kwa zaidi ya mara 10 huku zaidi ya watumiaji wapya milioni 100 wakijisajili ndani ya wiki moja.)

Ingawa tunafurahia jinsi PostgreSQL imetufikisha mbali, tunaendelea kusukuma mipaka yake ili kuhakikisha tuna nafasi ya kutosha kwa ukuaji wa baadaye. Tayari tumehamisha mizigo ya kazi inayoweza kugawanywa na yenye uandishi mwingi hadi kwenye mifumo yetu iliyogawanywa kama CosmosDB. Kazi zilizosalia zenye mzigo mkubwa wa uandishi zina changamoto zaidi kugawanya—tunazihamisha kwa bidii ili kupunguza zaidi mzigo wa uandishi kutoka kwa PostgreSQL primary. Pia tunashirikiana na Azure kuwezesha urudufishaji wa mfululizo ili tuweze kupanua kwa usalama hadi nakala nyingi zaidi za kusoma.

Tukiangalia mbele, tutaendelea kuchunguza mbinu za ziada za kupanua zaidi, ikiwa ni pamoja na sharded PostgreSQL au mifumo mbadala iliyosambazwa, kadri mahitaji yetu ya miundombinu yanavyoendelea kukua.

Mwandishi

Bohan Zhang

Shukrani

Shukrani maalum kwa Jon Lee, Sicheng Liu, Chaomin Yu, na Chenglong Hao, ambao walichangia chapisho hili, na kwa timu nzima iliyosaidia kuongeza PostgreSQL. Tungependa pia kuishukuru timu ya Azure PostgreSQL kwa ushirikiano wao thabiti.