-
Notifications
You must be signed in to change notification settings - Fork 0
/
sunum.slide
216 lines (111 loc) · 7.72 KB
/
sunum.slide
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# Canlıdan Go Kesitleri
Cem Sancak
Insider'da Çözüm Mimarı ve Hissedar
25 Temmuz 2020
## Bu adam ne yapar?
.image cem.jpg _ 200
Saniyede 200k'e kadar istek karşılayan sistemlerin çözüm mimarlığıyla uğraşır
6 yıldır çoğunlukla Go, arada Ruby ve JS yazar, Elixir ve Elm takip eder
4 yıldır başkaları adına AWS faturası yakar
3 yıldır Kubernetes kurcalar, pek sever (early/current [Contour](https://projectcontour.io/) user, thx Dave :))
2 yıldır nerede data bulsa ClickHouse'a sokuşturmanın yolunu arar
## Go'nun çok da gizli olmayan silahları
Go'nun zor problemlere pratik çözümler üretebilmesinin arkasındaki 2 ana mekanik kanallar (channels) ve goroutine'ler
Goroutine'ler diğer dillerdeki green thread'lere tekabül eder
Normal thread modeli kullanan diller 1 program thread'i 1 OS thread'i oluşturur
Green thread modeli kullanan diller 1 program thread'i N OS thread'i oluşturur
Bu N sayısı dilin runtime'ı tarafından yönetilir
Go runtime detayları için Jaana'nın blog'undaki [aydınlatıcı yazıyı](https://rakyll.org/scheduler/) okuyabilirsiniz
Kanalların bir çok alternatif kullanımı olmakla beraber, temel amaçları koşan goroutine'ler arasında iletişim sağlamaktır
## Eş zamanlı düşünebilmek
Başka dillerde program dışı koordinasyon mekanizmaları gerektiren problemleri tek bir yerde çözebilmek Go'nun en güçlü olduğu noktalardan biridir
Kullan at goroutine'lerden ziyade, programın hayatı süresince ayakta olacak ve belli bir görev tanımı olan goroutine'ler tanımlayabilirsiniz
Bu goroutine'lerle de kanallar aracılığıyla etkileşebilirsiniz
Bir nevi servis içinde mikroservis mimarisi tasarlayabilirsiniz
## Örnek bir mobil uygulama servisi - Bugün de Bir Şey Öğrendik
Veri tabanınızda bir tabloda her gün yollanmak üzere oluşturulup yazılan kelimeler olsun
Başka bir tabloda da bu servise üye olmuş kullanıcılarınız olsun
Bu servis hem Android hem de iOS platformlarında hizmet verebiliyor olsun
Her gün kullanıcılarımıza yeni bir kelime öğretmek amacıyla bildirim mesajı atıyor olalalım
## Naif bir başlangıç
.iframe https://play.golang.org/p/aw7jCsK4nT_W 500 1000
## Naif bir başlangıç
.image one.png _ 300
Bu yaklaşımda bütün işlemlerimizi tek bir goroutine'den (main) yürütüyoruz
## Kanatlarımızı azıcık açalım
.iframe https://play.golang.org/p/M9o0FXJ3OFa 500 1000
## Kanatlarımızı azıcık açalım
.image two.png _ 300
Bu yaklaşımda APNS ve GCM ile olan etkileşimlerin sorumluluğunu programın başında açılan goroutine'lere devrettik
Açılan goroutine'lerle kanallar aracılığıyla etkileşimde bulunduk
Genel koordinasyonu sağlamak için WaitGroup'dan yararlandık
## Daha da açalım
.iframe https://play.golang.org/p/wqpE7rALvLx 500 1000
## Daha da açalım
.image three.png _ 400
Bu yaklaşımda bir önceki örnekte network sorumluluklarını paylaşan goroutine'lerin üzerine bir de veri tabanı sorumluluklarını paylaşan 2 goroutine daha eklemiş olduk
Yeni goroutine'lerin öncekilerden farkı ömür döngülerinin kısıtlı olması - program boyunca değil iş boyunca çalışıyorlar
Goroutine'ler ya program boyunca çalışacak şekilde, ya da ne zaman biteceği kesinlikle bilinerek açılmalıdır
## UÇAK MODUNA GEÇELİM
.image goroutines.jpg _ 700
## UÇAK MODUNA GEÇELİM
.iframe https://play.golang.org/p/O9xGB0Qv2RR 500 1000
## UÇAK MODUNA GEÇELİM
.image four.png _ 500
## UÇAK MODUNA GEÇELİM
Son yaklaşımımızda network ile ilgilenen goroutine'lerimizin attıkları istekleri de goroutine'lere parçalayarak verimimizi iyice arttırdık
Kurduğumuz goroutine yapısıyla:
- Kelimeleri çekmek 500ms
- iOS ve Android kullanıcılarını çekmek 500ms
- Bütün istekleri atmak 100ms
## E bu çok güzelmiş, her şeyi goroutine'lerle halledelim bundan sonra
Diye düşünmeyin
Green thread modeli normal thread modeline göre daha hafif olsa da, bu yaklaşımın da limitleri var
Kullandığınız makinanın kaynakları çerçevesinde, belli bir miktar goroutine'den sonra Go'nun runtime'ı iş yapmaktan ziyade koşan goroutine'lerin yönetimine daha fazla zaman harcamaya başlayacaktır
Aynı şekilde goroutine'lerin ana amacı CPU kullanım verimini arttırmaktır, performans kovaladığınız senaryolarda önünüzde başka bir engel olabilir - ağ genişliği, disk kapasiteleri, bellek kapasitesi bunlardan bazıları
Bunlar göz önünde bulundurularak, daha fazla goroutine = daha fazla performans demek doğru değildir
İdeal goroutine sayısını servis senaryolarına ve makina kaynaklarına göre belirlemek gerekir
## Örnek servisimize dönecek olursak
Diyelim ki 200 milyon kullanıcımız oldu, büyüyüp globalleştik
Artık her gün 200 milyon istek atmamız gerekiyor
Kodumuzun son haliyle bunu yaparsak bizi ne bekler?
## Hüzün ve hüsran
.image htop.png _ 1000
200 milyon goroutine ve network isteği yüzünden makinanızın kullanılamaz hale gelmesi çok muhtemel
Bu gücü kontrol edebiliyor olmamız lazım
## Alternatif kanal kullanımları
Önümüzdeki konular için hatırlamamız gereken kanal karakteristikleri:
- Dolu kanala yazılamaz
- Boş kanaldan okunamaz
- Kapalı kanala yazmak panik attırır
- Kapalı kanaldan her zaman kanal tipine göre default value okunur
Bir de kanallardan bağımsız struct{}{} değerinin bellekte 0 yer tuttuğunu bilmemiz gerekiyor - merakınızı yakaladıysa bu konu hakkında Dave'in yazdığı [aydınlatıcı yazıyı](https://dave.cheney.net/2014/03/25/the-empty-struct) okuyabilirsiniz
Bu bilgileri birleştirerek bir goroutine kontrol mekanizması hazırlayabiliriz
## Kontrollü goroutine salınımı
.iframe https://play.golang.org/p/-IMBBPblmYN 500 1000
## Sinyalleşme amaçlı kanal kullanımı
Bir goroutine'in kapanmasını ya da sorumlu olduğu akışın dışında bir şey yapmasını istediğiniz zaman kanallardan yararlanabilirsiniz
## Sinyalleşme amaçlı kanal kullanımı
.iframe https://play.golang.org/p/fB2F06hjO9l 500 1000
## Sinyalleşme amaçlı kanal kullanımı
.image five.png _ 500
Mesajları yollamakla ve logları toplamakla sorumlu 2 goroutine açtık
Mesajlar yollandıkça alınan sonuçlar kanal aracılığıyla loglama goroutine'ine yollandı
Loglama goroutine'i closeChan'den okuyabildiği an başta olusturduğu bir cevap kanalına o ana kadar topladığı sonuçları yazıp kapandı
## Yazdığınız servislerin temiz kapanabildiğinden emin olun!
Bu kadar esnek eş zamanlı işlem yapabilme özgürlüğüyle beraber servis kapanımlarında ekstra dikkat sorumluluğu da geliyor
Uzun zamanlı açtığınız her goroutine'i tercihen işini yarıda bölmeden kapayabilmeyi planlamalısınız
Bunun için standart kütüphanenin parçası olan context paketinden ve WaitGroup'lardan yararlanabilirsiniz
Her zaman SIGINT ve SIGTERM dinleyin!
## Yazdığınız servislerin temiz kapanabildiğinden emin olun!
Sandbox ortamında demo'sunu yapmak mümkün değil fakat çoğu servisinizin main fonksiyonunun sonunda bulunması gereken kod parçası:
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
... temiz kapanma işlemleri ...
Bu kod program işletim sistemi tarafından kapatılmak istenene kadar main goroutine'i bekletecektir
Beklemesinin sebebi quit kanalının boş olmasıdır, signal.Notify fonksiyonuna bu kanalı vererek runtime'a belirtilen OS sinyalleri geldiğinde bu kanal üstünden haberdar olmak istediğimizi belirtmiş oluyoruz
Bunun için tabii ki de servisinizin ve parçalarının main goroutine'den farklı goroutine'lerde koşması gerekiyor
## Yazdığınız servislerin temiz kapanabildiğinden emin olun!
.iframe https://play.golang.org/p/o3rtje7Jec5 500 1000