Category: technical
-
即时通讯类应用的message sync问题
现在的办公室工作环境,协同办公软件是必不可少的工具,企业微信,飞书,Teams,Zoom都是这一类的软件;这类app的最核心的部分是两个,message sync和meeting call, 每个软件都有各自的特色,本文想结合自己的工作经验,稍微详细地讨论一下message sync部分的主要原理和目前的最新的技术 首先,web应用目前是在某一种大一统的方向上,得益于react之类的框架以及软件打包功能的完善,一套js/ts代码全吃desktop和web端的优势越发明显,维护和发布的工作量减轻是所有大型软件的开发团队都乐于见到的 但是目前web api也有非常多的局限性,比如cache storage管理部分;浏览器虽然支持indexed db的读写操作,但是对于复杂且大量的数据,app自身在大多数情况下还是不得不自己处理memory/db的cache读取工作,而且对于复杂schema的数据,还不得不自己定义class/interface以及implementation以便能够处理需要应对的场景 本人所在的组最近就因为选用的library的局限性,在新功能的拓展中吃尽苦头;为了利用到memory读取的速度优势,不得不写复杂的代码去维持memory和db中数据的一致性,特别是如果数据的读取是任意的情况下,这个一致性的维护就特别头疼,比方说下面的例子 DB中有全部的数据1 to 100, 但是因为分段读取的场景,memory中只有80 to 100, 以及 60 to 70 两段数据 这个情况下,当要提取60 to 100 的所有数据的时候memory中的数据就不完整,而且数据的完整性也无法得到validation,除非我们再一次scan所有db的数据,但是这样就丧失了memory的速度优势 主要问题就是,因为数据读取场景的随机性,使得数据的一致性维护变得复杂,特别是要维护memory和db两个副本,而且要处理network sync的时候 (这里就不展开network sync部分了) 这里的解决方案有两种: cache storage这部分的内容先到此为止,有时间再写更详细的内容,其实最近我们在测试时候发现,memory相比indexed db,如果读取数据量不是非常大,perf的区别其实没有想象中那么大,~100ms,但是这个需要更多测试数据来验证,我目前无法下结论 第二部分,也是最核心的部分,消息同步 其实,严格意义上来说这个分为两部分,real-time update(实时收发)和sync(同步),但是sync这个词太过模糊,即便是程序员群体里也有大部分人不懂sync到底是什么 real-time update就是人与人在相互发消息聊天的时候,message怎么能低延迟地发送到双方的client里 sync,同步,我们工作中的定义其实是指,客户端重启的时候,本地没有最新的message,需要通过GET的API call去从服务器fetch在app不启动的那段时间内,没有实时接收到的数据 (sync 这个词,我个人理解,应该更多的是指进行了GET/POST的API request,例如笔记内容POST到服务器存储,outlook打开GET接收最新的内容,完全不应该涉及real-time update实时更新的这部分内容,因为实现的原理是完全不一样的) real-time update 部分,如果用户量不大,可以考虑longpoll, 也就是长轮询,细节略去,本质就是不停地做GET call,来持续丰田车最新的数据;但是这种方式在费用,以及推送实时通知方面有本质的缺陷,所以最新的替代方式都是用web socket去保持一个服务器端持续push推送的connection sync部分,其实本质就是后台message service的搭建,以及各种API的设计;对于从零开始的小公司,可能负担比较小,但是大公司现在推行微服务的想法下,很容易出现这种情况,A组弄了个非常generic的message service,B组最开始用A的service,但是后来发现无法满足需求了,让A组xxx死线之前改,但是A组处于planning以及兼容性的问题,无法或者不能够提供需要的支持,不得已B组自己弄了个新的service,而且不得已对于已经在A里面的数据做了缓存(或者second copy),然后以后遇到问题,无尽地扯皮就开始了…
-
c++11 new features
well long time passed since my last technical post, I think it is time to review what I learnt in these 10 months job, basically all about c++11/14 and some thing about work inside a team 1. All kinds of new pointer, unique_ptr or smart point the idea of joining these new kinds of pointer…
-
浅谈头文件, include和class 引用的区别
好吧,正式上项目之后才发现,企业级的项目根本看不懂,但是还是能写代码,OOP万岁。。。。 今天遇到一个关于引用的问题,具体的情景是这样的,因为改变了某些函数的参数,从void指针改成了具体的类别,所以呢,就需要在文件中包含这些具体类别的头文件,但是使用include“…h”之后编译报错,得denpency wrong之类的,但是改成class引用,并加上namespace之后编译通过,其实我没有仔细研究那个error,这里只是想说一下这两者的区别 include的使用把两个文件完全连接起来,文件A可以看到文件B内的所有内容,同时这样也使得编译所花的时间更多 class只是声明有这么一个类,但是内部有什么具体的实现完全不知道,所以当不需要知道某个类的具体实现的时候完全可以用class代替include的方法来声明
-
c++编译器的工作流程
In C++ 1. the preprocessor handle all preprocessing work 2. The Compiler generates the Obj File 3. The Linker generate the exe file .cpp + compiler = obj file .obj + linker = exe file Compiler can only see one cpp file at a time The linker links many obj files into 1 exe file…
-
unnamed namespace VS static
公司的代码真是维护得有点蛋疼,这也跟从不同语言之间跳跃有关系,我非常惊奇的发现公司核心代码的大部分是用C写的,而且很完整地实现了reflcation的功能,但是比较因为c语言的很多特性不支持完整地OOP,所以目前公司的开发之痛处在把代码从C往c++迁移的过程中 今天遇到一个非常棘手的问题,在一个类的申明时,居然使用了unnamed namespace,以前看到过这个问题,这种全局化的匿名域到底要怎么使用呢?从形式上来说似乎跟static有相似之处,但是看来还需要仔细研究
-
generic way, specific void and void*
入职这段时间真正接触了一点关于泛型的概念,所谓generic, 就是指对多种对象操作时,不用具体区分对象的类型,多所有对象都能够进行统一的API操作。 一个很常见的例子就是,一辆卡车要装货,不管它装的是水,还是食物,只要货物是打包好的标准箱子,只要执行load操作就可以了 这里想谈的一个具体的例子是关于void和void* 其中void是指“没有”,对于一个函数来讲 void func(void) 前一个void是指函数没有返回值,后一个void是指函数没有参数。 默认情况下,如果没有第一个void,编译器会默认函数返回值是int(不确定,现在已经必需要求加返回类型) 如果没有第二个void,效果一样,函数没有参数 而void*与void不同,它不是代表“没有”,而是代表不确定类型,也就是泛型指针 它出现的原因是,对于c++这种静态预言,申明就要分配内存,如果是返回不确定的类型实体,因为每种类型的内存占用大小不一样,这种情况下编译器无法确定到底使用哪一个类型,但是如果使用指针,就能很好的解决这个问题,因为指针的大小都是一样的。 memory的库中很多函数都是用void*指针来完成的,例如 memcpy 原型:extern void *memcpy(void *dest, void *src, unsigned int count); 用法:#include 功能:由src所指内存区域复制count个字节到dest所指内存区域。 说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。 注意:与strcpy相比,memcpy并不是遇到’\0’就结束,而是一定会拷贝完n个字节。 memset 原型:extern void *memset(void *buffer, int c, int count); 用法:#include 功能:把buffer所指内存区域的前count个字节设置成字符c。 说明:返回指向buffer的指针。 但是,不同的编译器对void*的操作有不同限制,这个有待自己尝试 C++/ANSI C GUN C
-
new features of c++11
this is the 10th of my working career, and actually I have felt huge difference between university and industry, as a record of what I learned these days, I will post something here. Articles are still needed to be revised, but will come soon new features of c++11 1. auto and decltype 2. lambda…
-
web server Nginx VS Apache
最近做thesis的时候接触到一个新的web框架LEMP, 其实跟LAMP很相似,只是把Apache换成Nginx了,在网上查了一些资料,貌似很多人说Nginx的性能比Apache强很多,所以准备在这里转述一下Nginx的问题和Web框架的基本工作原理 为什么Nginx的性能要比Apache高得多? 这得益于Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的select模型。目前Linux下能够承受高并发访问的Squid、Memcached都采用的是epoll网络I/O模型。 处理大量的连接的读写,Apache所采用的select网络I/O模型非常低效。 Nginx 是一个很牛的高性能Web和反向代理服务器, 它具有有很多非常优越的特性: 作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一. 能够支持高达 50,000 个并发连接数的响应, 感谢Nginx为我们选择了 epoll and kqueue 作为开发模型. Nginx作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务, 也可以支持作为 HTTP代理 服务器对外进行服务. Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多. 。Nginx可作为7层负载均衡服务器来使用。 作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Last.fm 描述了成功并且美妙的使用经验. Nginx 是一个安装非常的简单 , 配置文件非常简洁(还能够支持perl语法), Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动….
-
example of using pointer to pointer to remove certain nodes
[codesyntax lang=”php”] #include<iostream> #include<stdlib.h> #include<cstring> using namespace std; struct ListNode{ int val; ListNode *next; ListNode(int x): val(x),next(NULL){} }; void remove(ListNode **head, int target){ ListNode* newhead=*head; while(newhead->val==target) newhead=newhead->next; if(newhead==NULL) *head=NULL; ListNode* p=newhead; ListNode* q=newhead->next; while(q!=NULL){ if(q->val==target){ q=q->next; p->next=q; } else{ p=q; q=q->next; } } *head=newhead; } void print(ListNode* head){ while(head){ cout<<head->val<<endl; head=head->next; } } int main(){…
-
pointer to pointer
首先讨论一下一级指针的问题,普通的链表问题就不再赘述了,但是如果要对指针申请动态内存,在某个函数内部是没办法实现的,实参和形参的基本概念 [codesyntax lang=”cpp”] void getmemory(char *p, int num){ ip=(char*)malloc(sizeof(char)* num); } void test(){ char *str=null; getmemory(str,100); // actually the address of str is not redefined, instead some memory is overflowed here strcpy(str,”hello”); } [/codesyntax] 这是一个典型的错误,为了解决这个问题就需要二级指针了 [codesyntax lang=”cpp”] void getmemory(char **p, int num){ *p=(char*)malloc(sizeof(char)*num); }…