Go-based WebSocket messaging service

Source: Internet
Author: User

3 months did not write PHP, this is my first small and medium go websocket micro-service. So the question is, why do I build wheels on GitHub with so many wheels?

Why Build Wheels?

Because this not only can exercise their technical ability, but also can help in-depth understanding of the implementation of the principle.

Directly on the flowchart:

  

  

In fact, some of the difficulties are not reflected, such as the history of data storage structure, the disease encountered some pits.

Storage structure for historical messages:

That is, broadcast, multicast can be disassembled into unicast, then the code can become simple.

But, however, have you seen "ref"? Ref indicates whether the user's history message is a reference, similar to C/cpp's pointer, address. Think, if the broadcast to 1w users, then is not to put a msg push to every user?

The answer is at least 2:

One: Push msg to everyone, advantages: reading data is very convenient, disadvantage: large data redundancy, and push instant Io is too large, inefficient;

Second: Push msg, respectively, storage: Broadcast table, multicast table, unicast table, the advantages: The query performance is high, no redundancy, the disadvantage: Comprehensive query all the history of users, performance is poor, and Redis network io more times, there are time and other sorting problems.

The 1th option is chosen in the light of comprehensive consideration.

The problem has come again, the development of this project is not successful, encountered a pit?

Nonsense, technical work, where there is no pit!

Pit 1:panic interrupted both out, really TMD is not what I want, the solution is: recovery (: P

Pit 2: Environmental variables to the inner package of transmission, tried several ways not, and finally with a package as an agent, packaging factories and single case, the best solution.

  

var instance *envfunc newenv () *env {env: = Env{}env.init () Env.parameters = Make (map[string]interface{}) return &env} Func singleenv () *env{if nil = = Instance {instance = newenv ()}return instance}//...

Pit 3:websocket cross-domain problem with a workaround of at least 2: You can modify the default settings

Temporarily ignores WebSocket cross-domain WS: = websocket. Upgrader{}if model. Singleconfig (). Http.enablecrosssite {ws. Checkorigin = func (R *http. Request) bool {//mock and Stubreturn true}}

Or in the Nginx add these, equivalent to the same domain, recommended this:

Nginx conf:upstream Push {ip_hash;server 127.0.0.1:9999; keepalive 60;} Map $http _upgrade $connection _upgrade {default upgrade;      Close;} server {   listen;   server_name dev.push.pub.sina.com.cn;    Location/push {        proxy_http_version 1.1;        Proxy_redirect off;        Proxy_set_header Upgrade $http _upgrade;        Proxy_set_header Connection "Upgrade";        Proxy_set_header Host $host;        Proxy_set_header x-real-ip $remote _addr;        Proxy_set_header x-forwarded-for $proxy _add_x_forwarded_for;        Client_max_body_size 10m;        Client_body_buffer_size 128k;        Proxy_connect_timeout;        Proxy_send_timeout;        Proxy_read_timeout;        Proxy_pass Http://push;        Fastcgi_keep_conn on;        Include        fastcgi_params;    }}

Pit 4:go Map does not have built-in support for concurrency security, which is the biggest problem. Solve a little trouble, need to use the Rwmutex lock. I refer to Beego wrote:

Package Libimport "Sync" type rwlocker struct {mtx sync. Rwmutex}func newrwlock () *rwlocker{return &rwlocker{}}func (L *rwlocker) Rlockdo (callback func ()) {L.mtx.rlock () Defer L.mtx.runlock () callback ()}func (L *rwlocker) Rwlockdo (callback func ()) {L.mtx.lock () defer l.mtx.unlock () Callback ()}type Locker struct {mtx sync. Mutex}func newlock () *locker{return &locker{}}func (L *locker) Lockdo (callback func ()) {L.mtx.lock () defer L.mtx.unlock () callback ()}type mutexmap struct{m map[interface{}]interface{}lock *sync. Rwmutex}func Newmutexmap () *mutexmap {return &mutexmap{lock:new (sync. Rwmutex), M:make (map[interface{}]interface{}),}}func (M *mutexmap) Size () Int{return len (M.M)}func (M *mutexmap) Raw () map[interface{}]interface{} {return m.m}//get from maps return the K ' s Valuefunc (M *mutexmap) Get (k interface{}) INTERFAC e{} {M.lock.rlock () defer M.lock.runlock () if val, ok: = M.m[k]; OK {return Val}return nil}//Maps the given key and value. Returns false//If the key is already in the map and changes Nothing.func (M *mutexmap) Set (k interface{}, v interface{}) bool {m.lock.lock () defer M.lock.unlock () if Val, OK: = M.m[k];!ok {m.m[k] = v} else if val = v {m.m[k] = v} else {return False}return true}//Returns true if K is exist In the Map.func (M *mutexmap) Check (k interface{}) bool {m.lock.rlock () defer m.lock.runlock () If _, OK: = M.m[k];!ok {Retu RN False}return True}func (M *mutexmap) Keys (ignorenil bool, Keys ... interface{}) []interface{}{m.lock.rlock () Defer M.lo Ck. Runlock () Vals: = []interface{}{}for _,k: = range Keys {if v,ok: = M.m[k]; OK {vals = append (Vals, v)}else{if!ignorenil {V als = append (Vals, nil)}}}return Vals}func (M *mutexmap) Delete (k interface{}) {M.lock.lock () defer m.lock.unlock () delete (M.M, K)}

  

The basic pits are these, and the on-line deployment is of course Jenkins+salt+rsync:

Finally, the discussion, maintainability, debugging.

First of all, maintenance: At present, only a few times go will be abnormal crashes, is generally not careful or concurrency security did not do well, this according to the log, race tool, Strace/gdb can be done.

In addition, debugging, between PHP, CPP, and Java-like, generally can check the problem, and play logs, including array subscript out of bounds, and other artifacts such as pprof/strace/gdb can be used, or good.

Haha, today is written so much, to coax sister-----------my daughter.

: P

  

  

  

Go-based WebSocket messaging service

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.