c++11函数完美转发之异常处理
基于装饰者模式的thrift连接池实现(C++版本)
就一个连接池而已,为什么要采用装饰者模式,听着咋感觉那么高深?
所谓连接池,也就是连接先不close,放入池中,等待下次需要用的时候,直接从池中取出即可用,省去了tcp握手的时间,所以这个可以看作是一个长连接,知道连接池清除空闲连接把多余的连接清除掉才会释放。
而普通的连接,用完后如果生命周期内不再使用了,就会销毁掉。
所以基于普通的连接,要定义出线程池的那种用完放回线程池的连接,就需要把close的方法进行重写,所以可以采用继承的方法实现,相当于产生了两个子类,一个是普通连接类,一个是线程池化的连接类。
基于模板实现的观察者模式C++
这个设计模式的功能就是实现订阅与发布的功能,一旦有消息更新,即可将最新的消息同步给所有的订阅者,无需订阅者主动来询问,如果订阅者无需这些消息了,只需要取消订阅即可,后续有新的消息就不会再次打扰。
适用于对于相同的数据需要表现为不同的行为的功能,比如,得知爸爸要回来了,儿子就会立马停止玩游戏,妈妈立马开始准备晚餐。也有可能是很多人都想订阅这些数据,比如求职者先将要找工作的需求交给猎头,猎头那里有很多这样的需求,一旦有公司有需求,猎头那里就会立马通知所有的要找这份工作的求职者,让他们分别去面试,公司选择优秀的人才入职。
生活中有很多类似的场景,都可以用观察者模式来解释,所以设计模式的灵感也来源于生活。另外一方面,也实现了逻辑与应用的分离,从上面的例子也可以看出,底层数据只有一份,但是可以用在几个不同的场景,如果新的场景,也就相当于多了一个订阅者而已。
基于模板实现的观察者模式
网上面有很多实现了的观察者模式,用的都是普通类,但由于模型应用场景,比如订阅的消息类型各式各样,有string、int或者自定义class,那就需要改用模板类了。
公众号迁移开留言复杂吗?只要给资料就行?
2021公众号留言功能开通说明与小程序试用
常用数据结构
队列
循环队列,固定容器大小,实现如下。
1 | #include <iostream> |
在用数组实现的非循环队列中,队满的判断条件是 tail == n,队空的判断条件是 head == tail。那针对循环队列,如何判断队空和队满呢?
队列为空的判断条件仍然是 head == tail。但队列满的判断条件就稍微有点复杂了。
就像我图中画的队满的情况,tail=3,head=4,n=8,所以总结一下规律就是:(3+1)%8=4。多画几张队满的图,你就会发现,当队满时,(tail+1)%n=head。
protobuf通信协议
包完整性
- 以特殊符号来分界,如每个包都以特定的字符来结尾(如\r\n,http的header就是),当在字节流中读取到该字符时,则表明上一个包到此为止。
- 固定包头+包体结构,包头一般时一个固定字节长度的结构,并且包头中会有一个特定的字段指定包体的大小。收包时,先接收固定字节数的头部,解出这个包的完整长度,按此长度接收包体。header+body 目前应用最多的一种包格式。
- 在序列化后的buffer前面增加一个字符流的头部,其中有一个字段存储包总长度,根据特殊字符(比如\n或者\0)判断头部的完整性。这样通常比2麻烦些,http和redis($6\r\nfoobar\r\n)采用的这种形式,收包的时候,先判断已经收到的数据中是否包含结束符,收到结束符后解析包头,解出这个包完整长度,按此长度接收包体。
协议设计
序列号:tcp只能保证数据到达,不能保证数据是否处理。
type表示协议类型,如xml,json。
版本号尽量放在前面,读取版本号的时候可以少读一些字节,如下nginx。protobuf封装后是放在body里面的。header也是定长的,就不用序列化。body做序列化即可。
http请求头为文本,但是body如果传的是jpeg就是二进制。
xml、json序列化后都是文本,protobuf序列化后就是二进制,这里指的是将对象序列化,对象里面一些变长的字段不进行序列化不方便传输。
grpc框架
采用proto buffer作为idl语言。
采用http2进行通信,body采用protobuf序列化后的二进制传输,将字段名去掉,以数字代替。
四种模式:一个端口可以对应多个service
1 | syntax = "proto3"; |
1 | // ListFeatures |
grpc用于微服务所面临的问题:
- 用户鉴权问题,鉴权方案的具体实现还包括了多种场景下的解决方案,例如:基于 JWT 或 OAuth 认证、基于多种细粒度授权方案进行授权、支持 OIDC 等。开发者需要根据具体的业务需求和安全要求,选择合适的鉴权方案。
redis配置与开发
docker
1 | docker run -itd --name redis -p 6379:6379 --restart unless-stopped redis |
redis
内存数据库、kv数据库、数据结构数据库
对象类型有哪些?底层使用了哪些数据结构
- string
- int,字符串长度小于等于20且能转成整数,set teacher 1000000,type teacher,object encoding teacher
- raw,字符串长度大于44
- embstr,字符串长度小于等于44,cpu缓存中基本单位为cacheline 64字节,sdshdr头为9字节,加上’\0’,buf的最大长度为44,set teacher 1000000a,object encoding teacher
- list
- quicklist,双向循环链表
- ziplist,压缩链表
- hash,hmset role:1001 age 30 name mark sex 1, hgetall role:1001, hget role:1001 age,散列表:指针数组+数组长度+hash函数
- dict/hashtable,节点数量大于512,或字符串长度大于64
- ziplist,压缩列表,节点数量小于等于512(hash-max-ziplist-entries),且字符串长度小于等于64(hash-max-ziplist-value)
- set,sadd set 1 2 3 4 5,object encoding set,sadd set mark,object encoding set
- intset,整数数组,元素都为整数,且节点数量小于等于512(set-max-intset-entries)
- dict/hashtable,字典,元素有一个不为整数或者数量大于512
- zset,有序的结构
- skiplist,跳表,数量大于128或者有一个字符串长度大于64
- ziplist,压缩列表,节点数量小于等于128(zset-max-ziplist-entries)且字符串长度小于等于64(zset-max-ziplist-value)