成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

go語(yǔ)言elastic替代,go語(yǔ)言代替java

如何用go語(yǔ)言每分鐘處理100萬(wàn)個(gè)請(qǐng)求

在Malwarebytes 我們經(jīng)歷了顯著的增長(zhǎng),自從我一年前加入了硅谷的公司,一個(gè)主要的職責(zé)成了設(shè)計(jì)架構(gòu)和開(kāi)發(fā)一些系統(tǒng)來(lái)支持一個(gè)快速增長(zhǎng)的信息安全公司和所有需要的設(shè)施來(lái)支持一個(gè)每天百萬(wàn)用戶使用的產(chǎn)品。我在反病毒和反惡意軟件行業(yè)的不同公司工作了12年,從而我知道由于我們每天處理大量的數(shù)據(jù),這些系統(tǒng)是多么復(fù)雜。

10多年專注成都網(wǎng)站制作,成都定制網(wǎng)頁(yè)設(shè)計(jì),個(gè)人網(wǎng)站制作服務(wù),為大家分享網(wǎng)站制作知識(shí)、方案,網(wǎng)站設(shè)計(jì)流程、步驟,成功服務(wù)上千家企業(yè)。為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),專注于成都定制網(wǎng)頁(yè)設(shè)計(jì),高端網(wǎng)頁(yè)制作,對(duì)成都垃圾桶等多個(gè)方面,擁有豐富設(shè)計(jì)經(jīng)驗(yàn)。

有趣的是,在過(guò)去的大約9年間,我參與的所有的web后端的開(kāi)發(fā)通常是通過(guò)Ruby on Rails技術(shù)實(shí)現(xiàn)的。不要錯(cuò)怪我。我喜歡Ruby on Rails,并且我相信它是個(gè)令人驚訝的環(huán)境。但是一段時(shí)間后,你會(huì)開(kāi)始以ruby的方式開(kāi)始思考和設(shè)計(jì)系統(tǒng),你會(huì)忘記,如果你可以利用多線程、并行、快速執(zhí)行和小內(nèi)存開(kāi)銷(xiāo),軟件架構(gòu)本來(lái)應(yīng)該是多么高效和簡(jiǎn)單。很多年期間,我是一個(gè)c/c++、Delphi和c#開(kāi)發(fā)者,我剛開(kāi)始意識(shí)到使用正確的工具可以把復(fù)雜的事情變得簡(jiǎn)單些。

作為首席架構(gòu)師,我不會(huì)很關(guān)心在互聯(lián)網(wǎng)上的語(yǔ)言和框架戰(zhàn)爭(zhēng)。我相信效率、生產(chǎn)力。代碼可維護(hù)性主要依賴于你如何把解決方案設(shè)計(jì)得很簡(jiǎn)單。

問(wèn)題

當(dāng)工作在我們的匿名遙測(cè)和分析系統(tǒng)中,我們的目標(biāo)是可以處理來(lái)自于百萬(wàn)級(jí)別的終端的大量的POST請(qǐng)求。web處理服務(wù)可以接收包含了很多payload的集合的JSON數(shù)據(jù),這些數(shù)據(jù)需要寫(xiě)入Amazon S3中。接下來(lái),map-reduce系統(tǒng)可以操作這些數(shù)據(jù)。

按照習(xí)慣,我們會(huì)調(diào)研服務(wù)層級(jí)架構(gòu),涉及的軟件如下:

Sidekiq

Resque

DelayedJob

Elasticbeanstalk Worker Tier

RabbitMQ

and so on…

搭建了2個(gè)不同的集群,一個(gè)提供web前端,另外一個(gè)提供后端處理,這樣我們可以橫向擴(kuò)展后端服務(wù)的數(shù)量。

但是,從剛開(kāi)始,在 討論階段我們的團(tuán)隊(duì)就知道我們應(yīng)該使用Go,因?yàn)槲覀兛吹竭@會(huì)潛在性地成為一個(gè)非常龐大( large traffic)的系統(tǒng)。我已經(jīng)使用了Go語(yǔ)言大約2年時(shí)間,我們開(kāi)發(fā)了幾個(gè)系統(tǒng),但是很少會(huì)達(dá)到這樣的負(fù)載(amount of load)。

我們開(kāi)始創(chuàng)建一些結(jié)構(gòu),定義從POST調(diào)用得到的web請(qǐng)求負(fù)載,還有一個(gè)上傳到S3 budket的函數(shù)。

type PayloadCollection struct {

WindowsVersion string `json:"version"`

Token string `json:"token"`

Payloads []Payload `json:"data"`

}

type Payload struct {

// [redacted]

}

func (p *Payload) UploadToS3() error {

// the storageFolder method ensures that there are no name collision in

// case we get same timestamp in the key name

storage_path := fmt.Sprintf("%v/%v", p.storageFolder, time.Now().UnixNano())

bucket := S3Bucket

b := new(bytes.Buffer)

encodeErr := json.NewEncoder(b).Encode(payload)

if encodeErr != nil {

return encodeErr

}

// Everything we post to the S3 bucket should be marked 'private'

var acl = s3.Private

var contentType = "application/octet-stream"

return bucket.PutReader(storage_path, b, int64(b.Len()), contentType, acl, s3.Options{})

}

本地Go routines方法

剛開(kāi)始,我們采用了一個(gè)非常本地化的POST處理實(shí)現(xiàn),僅僅嘗試把發(fā)到簡(jiǎn)單go routine的job并行化:

func payloadHandler(w http.ResponseWriter, r *http.Request) {

if r.Method != "POST" {

w.WriteHeader(http.StatusMethodNotAllowed)

return

}

// Read the body into a string for json decoding

var content = PayloadCollection{}

err := json.NewDecoder(io.LimitReader(r.Body, MaxLength)).Decode(content)

if err != nil {

w.Header().Set("Content-Type", "application/json; charset=UTF-8")

w.WriteHeader(http.StatusBadRequest)

return

}

// Go through each payload and queue items individually to be posted to S3

for _, payload := range content.Payloads {

go payload.UploadToS3() // ----- DON'T DO THIS

}

w.WriteHeader(http.StatusOK)

}

對(duì)于中小負(fù)載,這會(huì)對(duì)大多數(shù)的人適用,但是大規(guī)模下,這個(gè)方案會(huì)很快被證明不是很好用。我們期望的請(qǐng)求數(shù),不在我們剛開(kāi)始計(jì)劃的數(shù)量級(jí),當(dāng)我們把第一個(gè)版本部署到生產(chǎn)環(huán)境上。我們完全低估了流量。

上面的方案在很多地方很不好。沒(méi)有辦法控制我們產(chǎn)生的go routine的數(shù)量。由于我們收到了每分鐘1百萬(wàn)的POST請(qǐng)求,這段代碼很快就崩潰了。

再次嘗試

我們需要找一個(gè)不同的方式。自開(kāi)始我們就討論過(guò), 我們需要保持請(qǐng)求處理程序的生命周期很短,并且進(jìn)程在后臺(tái)產(chǎn)生。當(dāng)然,這是你在Ruby on Rails的世界里必須要做的事情,否則你會(huì)阻塞在所有可用的工作 web處理器上,不管你是使用puma、unicore還是passenger(我們不要討論JRuby這個(gè)話題)。然后我們需要利用常用的處理方案來(lái)做這些,比如Resque、 Sidekiq、 SQS等。這個(gè)列表會(huì)繼續(xù)保留,因?yàn)橛泻芏嗟姆桨缚梢詫?shí)現(xiàn)這些。

所以,第二次迭代,我們創(chuàng)建了一個(gè)緩沖channel,我們可以把job排隊(duì),然后把它們上傳到S3。因?yàn)槲覀兛梢钥刂莆覀冴?duì)列中的item最大值,我們有大量的內(nèi)存來(lái)排列job,我們認(rèn)為只要把job在channel里面緩沖就可以了。

var Queue chan Payload

func init() {

Queue = make(chan Payload, MAX_QUEUE)

}

func payloadHandler(w http.ResponseWriter, r *http.Request) {

...

// Go through each payload and queue items individually to be posted to S3

for _, payload := range content.Payloads {

Queue - payload

}

...

}

接下來(lái),我們?cè)購(gòu)年?duì)列中取job,然后處理它們。我們使用類(lèi)似于下面的代碼:

func StartProcessor() {

for {

select {

case job := -Queue:

job.payload.UploadToS3() // -- STILL NOT GOOD

}

}

}

說(shuō)實(shí)話,我不知道我們?cè)谙胧裁?。這肯定是一個(gè)滿是Red-Bulls的夜晚。這個(gè)方法不會(huì)帶來(lái)什么改善,我們用了一個(gè) 有缺陷的緩沖隊(duì)列并發(fā),僅僅是把問(wèn)題推遲了。我們的同步處理器同時(shí)僅僅會(huì)上傳一個(gè)數(shù)據(jù)到S3,因?yàn)閬?lái)到的請(qǐng)求遠(yuǎn)遠(yuǎn)大于單核處理器上傳到S3的能力,我們的帶緩沖channel很快達(dá)到了它的極限,然后阻塞了請(qǐng)求處理邏輯的queue更多item的能力。

我們僅僅避免了問(wèn)題,同時(shí)開(kāi)始了我們的系統(tǒng)掛掉的倒計(jì)時(shí)。當(dāng)部署了這個(gè)有缺陷的版本后,我們的延時(shí)保持在每分鐘以常量增長(zhǎng)。

最好的解決方案

我們討論過(guò)在使用用Go channel時(shí)利用一種常用的模式,來(lái)創(chuàng)建一個(gè)二級(jí)channel系統(tǒng),一個(gè)來(lái)queue job,另外一個(gè)來(lái)控制使用多少個(gè)worker來(lái)并發(fā)操作JobQueue。

想法是,以一個(gè)恒定速率并行上傳到S3,既不會(huì)導(dǎo)致機(jī)器崩潰也不好產(chǎn)生S3的連接錯(cuò)誤。這樣我們選擇了創(chuàng)建一個(gè)Job/Worker模式。對(duì)于那些熟悉Java、C#等語(yǔ)言的開(kāi)發(fā)者,可以把這種模式想象成利用channel以golang的方式來(lái)實(shí)現(xiàn)了一個(gè)worker線程池,作為一種替代。

var (

MaxWorker = os.Getenv("MAX_WORKERS")

MaxQueue = os.Getenv("MAX_QUEUE")

)

// Job represents the job to be run

type Job struct {

Payload Payload

}

// A buffered channel that we can send work requests on.

var JobQueue chan Job

// Worker represents the worker that executes the job

type Worker struct {

WorkerPool chan chan Job

JobChannel chan Job

quit chan bool

}

func NewWorker(workerPool chan chan Job) Worker {

return Worker{

WorkerPool: workerPool,

JobChannel: make(chan Job),

quit: make(chan bool)}

}

// Start method starts the run loop for the worker, listening for a quit channel in

// case we need to stop it

func (w Worker) Start() {

go func() {

for {

// register the current worker into the worker queue.

w.WorkerPool - w.JobChannel

select {

case job := -w.JobChannel:

// we have received a work request.

if err := job.Payload.UploadToS3(); err != nil {

log.Errorf("Error uploading to S3: %s", err.Error())

}

case -w.quit:

// we have received a signal to stop

return

}

}

}()

}

// Stop signals the worker to stop listening for work requests.

func (w Worker) Stop() {

go func() {

w.quit - true

}()

}

我們已經(jīng)修改了我們的web請(qǐng)求handler,用payload創(chuàng)建一個(gè)Job實(shí)例,然后發(fā)到JobQueue channel,以便于worker來(lái)獲取。

func payloadHandler(w http.ResponseWriter, r *http.Request) {

if r.Method != "POST" {

w.WriteHeader(http.StatusMethodNotAllowed)

return

}

// Read the body into a string for json decoding

var content = PayloadCollection{}

err := json.NewDecoder(io.LimitReader(r.Body, MaxLength)).Decode(content)

if err != nil {

w.Header().Set("Content-Type", "application/json; charset=UTF-8")

w.WriteHeader(http.StatusBadRequest)

return

}

// Go through each payload and queue items individually to be posted to S3

for _, payload := range content.Payloads {

// let's create a job with the payload

work := Job{Payload: payload}

// Push the work onto the queue.

JobQueue - work

}

w.WriteHeader(http.StatusOK)

}

在web server初始化時(shí),我們創(chuàng)建一個(gè)Dispatcher,然后調(diào)用Run()函數(shù)創(chuàng)建一個(gè)worker池子,然后開(kāi)始監(jiān)聽(tīng)JobQueue中的job。

dispatcher := NewDispatcher(MaxWorker)

dispatcher.Run()

下面是dispatcher的實(shí)現(xiàn)代碼:

type Dispatcher struct {

// A pool of workers channels that are registered with the dispatcher

WorkerPool chan chan Job

}

func NewDispatcher(maxWorkers int) *Dispatcher {

pool := make(chan chan Job, maxWorkers)

return Dispatcher{WorkerPool: pool}

}

func (d *Dispatcher) Run() {

// starting n number of workers

for i := 0; i d.maxWorkers; i++ {

worker := NewWorker(d.pool)

worker.Start()

}

go d.dispatch()

}

func (d *Dispatcher) dispatch() {

for {

select {

case job := -JobQueue:

// a job request has been received

go func(job Job) {

// try to obtain a worker job channel that is available.

// this will block until a worker is idle

jobChannel := -d.WorkerPool

// dispatch the job to the worker job channel

jobChannel - job

}(job)

}

}

}

注意到,我們提供了初始化并加入到池子的worker的最大數(shù)量。因?yàn)檫@個(gè)工程我們利用了Amazon Elasticbeanstalk帶有的docker化的Go環(huán)境,所以我們常常會(huì)遵守12-factor方法論來(lái)配置我們的生成環(huán)境中的系統(tǒng),我們從環(huán)境變了讀取這些值。這種方式,我們控制worker的數(shù)量和JobQueue的大小,所以我們可以很快的改變這些值,而不需要重新部署集群。

var (

MaxWorker = os.Getenv("MAX_WORKERS")

MaxQueue = os.Getenv("MAX_QUEUE")

)

直接結(jié)果

我們部署了之后,立馬看到了延時(shí)降到微乎其微的數(shù)值,并未我們處理請(qǐng)求的能力提升很大。

Elastic Load Balancers完全啟動(dòng)后,我們看到ElasticBeanstalk 應(yīng)用服務(wù)于每分鐘1百萬(wàn)請(qǐng)求。通常情況下在上午時(shí)間有幾個(gè)小時(shí),流量峰值超過(guò)每分鐘一百萬(wàn)次。

我們一旦部署了新的代碼,服務(wù)器的數(shù)量從100臺(tái)大幅 下降到大約20臺(tái)。

我們合理配置了我們的集群和自動(dòng)均衡配置之后,我們可以把服務(wù)器的數(shù)量降至4x EC2 c4.Large實(shí)例,并且Elastic Auto-Scaling設(shè)置為如果CPU達(dá)到5分鐘的90%利用率,我們就會(huì)產(chǎn)生新的實(shí)例。

總結(jié)

在我的書(shū)中,簡(jiǎn)單總是獲勝。我們可以使用多隊(duì)列、后臺(tái)worker、復(fù)雜的部署設(shè)計(jì)一個(gè)復(fù)雜的系統(tǒng),但是我們決定利用Elasticbeanstalk 的auto-scaling的能力和Go語(yǔ)言開(kāi)箱即用的特性簡(jiǎn)化并發(fā)。

我們僅僅用了4臺(tái)機(jī)器,這并不是什么新鮮事了??赡芩鼈冞€不如我的MacBook能力強(qiáng)大,但是卻處理了每分鐘1百萬(wàn)的寫(xiě)入到S3的請(qǐng)求。

處理問(wèn)題有正確的工具。當(dāng)你的 Ruby on Rails 系統(tǒng)需要更強(qiáng)大的web handler時(shí),可以考慮下ruby生態(tài)系統(tǒng)之外的技術(shù),或許可以得到更簡(jiǎn)單但更強(qiáng)大的替代方案。

golang elasticsearch連接配置 --- 2022-04-02

本節(jié)介紹golang elastic client參數(shù)詳解,主要包括:

elasticsearch連接地址

elasticsearch賬號(hào)/密碼

監(jiān)控檢查

失敗重試次數(shù)

gzip設(shè)置

elasticsearch 可以替代數(shù)據(jù)庫(kù)嗎

我們使用Elasticsearch存儲(chǔ)的文檔數(shù)量接近50億(算上1份復(fù)制,接近

100億文檔),總共10個(gè)數(shù)據(jù)節(jié)點(diǎn)和2個(gè)元數(shù)據(jù)節(jié)點(diǎn)(48GB內(nèi)存,8核心CPU,ES使用內(nèi)存達(dá)到70%),每天的文檔增量大概是3000W條(速度

持續(xù)增加中)。目前來(lái)看,單個(gè)文檔的查詢效率基本處于實(shí)時(shí)狀態(tài);對(duì)于1到2周的數(shù)據(jù)的聚合統(tǒng)計(jì)操作也可以在10秒之內(nèi)返回結(jié)果。

但是,還有提升的空間:

1. 對(duì)于查詢單條數(shù)據(jù)的應(yīng)用場(chǎng)景來(lái)說(shuō),我們可以使用ES的路由機(jī)制,將同一索引內(nèi)的具有相同特征(比如具有相同的userid)的文檔全部存儲(chǔ)于一個(gè)節(jié)點(diǎn)上,這樣我們之后的查詢都可以直接定位到這個(gè)節(jié)點(diǎn)上,而不用將查詢廣播道所有的節(jié)點(diǎn)上;

2. 隨著數(shù)據(jù)節(jié)點(diǎn)的增加,適當(dāng)增加分片數(shù)量,提升系統(tǒng)的分布水平,也可以通過(guò)分而治之的方式優(yōu)化查詢性能;

 

 個(gè)人以為Elasticsearch作為內(nèi)部存儲(chǔ)來(lái)說(shuō)還是不錯(cuò)的,效率也基本能夠滿足,在某些方面替代傳統(tǒng)DB也是可以的,前提是你的業(yè)務(wù)不對(duì)操作的事

性務(wù)有特殊要求;而權(quán)限管理也不用那么細(xì),因?yàn)镋S的權(quán)限這塊還不完善。由于我們對(duì)ES的應(yīng)用場(chǎng)景僅僅是在于對(duì)某段時(shí)間內(nèi)的數(shù)據(jù)聚合操作,沒(méi)有大量的單文

檔請(qǐng)求(比如通過(guò)userid來(lái)找到一個(gè)用戶的文檔,類(lèi)似于NoSQL的應(yīng)用場(chǎng)景),所以能否替代NoSQL還需要各位自己的測(cè)試。如果讓我選擇的話,我

會(huì)嘗試使用ES來(lái)替代傳統(tǒng)的NoSQL,因?yàn)樗臋M向擴(kuò)展機(jī)制太方便了。

logstash 和filebeat 是什么關(guān)系

你好

logstash 和filebeat 的關(guān)系:

1. logstash和filebeat都是可以作為日志采集的工具,目前日志采集的工具有很多種,如fluentd, flume, logstash,betas等等。甚至最后我決定用filebeat作為日志采集端工具的時(shí)候,還有人問(wèn)我為什么不用flume,logstash等采集工具。

2. logstash出現(xiàn)時(shí)間要比f(wàn)ilebeat早許多,隨著時(shí)間發(fā)展,logstash不僅僅是一個(gè)日志采集工具,它也是可以作為一個(gè)日志搜集工具,有豐富的input|filter|output插件可以使用。常用的ELK日志采集方案中,大部分的做法就是將所有節(jié)點(diǎn)的日志內(nèi)容上送到kafka消息隊(duì)列,然后使用logstash集群讀取消息隊(duì)列內(nèi)容,根據(jù)配置文件進(jìn)行過(guò)濾。上送到elasticsearch。logstash詳細(xì)信息可前往

3. logstash是使用Java編寫(xiě),插件是使用jruby編寫(xiě),對(duì)機(jī)器的資源要求會(huì)比較高,網(wǎng)上有一篇關(guān)于其性能測(cè)試的報(bào)告。之前自己也做過(guò)和filebeat的測(cè)試對(duì)比。在采集日志方面,對(duì)CPU,內(nèi)存上都要比前者高很多。LogStash::Inputs::Syslog 性能測(cè)試與優(yōu)化

4. filebeat也是elastic.公司開(kāi)發(fā)的,其官方的說(shuō)法是為了替代logstash-forward。采用go語(yǔ)言開(kāi)發(fā)。代碼開(kāi)源。elastic/beats filebeat是beats的一個(gè)文件采集工具,目前其官方基于libbeats平臺(tái)開(kāi)發(fā)的還有Packetbeat, Metricbeat, Winlogbeat。filebeat性能非常好,部署簡(jiǎn)單。是一個(gè)非常理想的文件采集工具。我自己采集工具也是基于beats源碼進(jìn)行的二次開(kāi)發(fā)。

elasticsearch的head插件可以用什么方案替代

head插件源碼在git上先安裝gityum install git獲取源碼elasticsearch-headhead 插件需要node.js 的支持先安裝node.js安裝nodejsyum install -y nodejs使用命令node -v 或者npm -v驗(yàn)證是否安裝成功使用npm安裝grunt命令npm install grunt --save-devnpm install修改配置文件 進(jìn)入elasticsearch-head-master 目錄,執(zhí)行命令vim Gruntfile.js文件增加hostname屬性,設(shè)置為npm run start執(zhí)行完成后就OK了

go操作elasticsearch示例-

這里我使用elasticsearch官方給的go語(yǔ)言包(go-elasticsearch)

go-elasticsearch向前兼容,這意味著客戶端支持與更大或同等次要版本的 Elasticsearch 通信。Elasticsearch 語(yǔ)言客戶端僅向后兼容默認(rèn)發(fā)行版,不提供任何保證。

go.mod 文件中添加

或者

新建 es.go 存入 es目錄

新建 main.go

...

...

...

文章名稱:go語(yǔ)言elastic替代,go語(yǔ)言代替java
標(biāo)題來(lái)源:http://jinyejixie.com/article38/dssdcsp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司微信公眾號(hào)、面包屑導(dǎo)航、網(wǎng)站建設(shè)、網(wǎng)站改版、動(dòng)態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都app開(kāi)發(fā)公司
明溪县| 鄂托克前旗| 深圳市| 抚州市| 新龙县| 灵台县| 彝良县| 苗栗市| 太原市| 南开区| 关岭| 嘉峪关市| 乌鲁木齐市| 五指山市| 普兰县| 积石山| 阜康市| 华容县| 建昌县| 拉萨市| 肇源县| 综艺| 洪湖市| 鄂尔多斯市| 托克逊县| 高碑店市| 巴彦淖尔市| 千阳县| 固阳县| 中江县| 简阳市| 贵定县| 德庆县| 蕉岭县| 淮阳县| 安宁市| 大姚县| 十堰市| 平远县| 和林格尔县| 闽侯县|