PostgreSQL 的优点

开源且遵从SQL标准
PostgreSQL 是一款开源的、免费的、功能非常强大的关系型数据库。

强大的社区
由一个忠实的、经验丰富的社区支持,用户可以通过知识库和 Q&A 网站获得全天候的免费服务。

强有力的第三方支持
除了非常先进的特性之外,PostgreSQL 还有很多优秀的、开源的第三方工具可以辅助系统的设计、管理和使用。

可扩展
可以通过存储过程扩展 PostgreSQL 的功能。

面向对象
PostgreSQL 不仅是一个关系型数据库,它还是一个面向对象的数据库——支持嵌套等功能。

PostgreSQL 的缺点

性能:
对于简单繁重的读取操作,使用 PostgreSQL 可能有点小题大做,同时性能也比 MySQL 这样的同类产品要差。

流行程度
尽管有大量的部署,但是鉴于该数据库的性质,它的受欢迎程序并不高。

何时应该使用 PostgreSQL

数据完整性
当绝对需要可靠性和数据完整性的时候,PostgreSQL 是更好的选择。

复杂的定制程序
如果需要数据库执行定制程序,那么可扩展的 PostgreSQL 是更好的选择。

集成:
如果将来可能需要将整个数据库迁移到其他合适的解决方案上(例如 Oracle),那么 PostgreSQL 可能兼容性最好也更容易切换。

复杂的设计
与其他开源且免费的数据库相比,对于复杂的数据库设计 PostgreSQL 在功能方面最全面,潜力最大,不需要你放弃其他有价值的资产。

何时不应该使用 PostgreSQL

速度
如果你只需要快速读取操作,那么 PostgreSQL 并不合适。

简单
除非你需要绝对的数据完整性,ACID 遵从性或者设计复杂,否则 PostgreSQL 对于简单的场景而言有点多余。

复制
对于缺少数据库和系统管理经验的人而言使用 MySQL 实现复制要更简单,除非你愿意花费时间、精力和资源。

官网-相关限制定义

sqlite理论最大可以到140TB。(当然官网也承认目前没人把数据库搞到这么大,就是 “untested”)

属于本地数据库多用于读多写少,100W以下的数据压力不大,不支持分布式。

限制信息

表列的限制

#ifndef SQLITE_MAX_COLUMN
# define SQLITE_MAX_COLUMN 32676
#endif

#ifndef SQLITE_MAX_SQL_LENGTH
# define SQLITE_MAX_SQL_LENGTH 1000000000
#endif

何时不应该使用 SQLite

多用户应用程序
如果有多个客户端需要访问并使用同一个数据库,那么最好使用功能完整的关系型数据库(例如 MySQL),而不是选择 SQLite。

需要高写入量的应用程序
写操作是 SQLite 的一个局限。该 DBMS 在同一时刻仅允许一个写操作,因而也限制了其吞吐量。

sqlite_sequence表

sqlite_sequence表也是SQLite的系统表。该表用来保存其他表的RowID的最大值。数据库被创建时,sqlite_sequence表会被自动创建。该表包括两列。第一列为name,用来存储表的名称。第二列为seq,用来保存表对应的RowID的最大值。该值最大值为9223372036854775807。当对应的表增加记录,该表会自动更新。当表删除,该表对应的记录也会自动删除。如果该值超过最大值,会引起SQL_FULL错误。所以,一旦发现该错误,用户不仅要检查SQLite文件所在的磁盘空间是否不足,还需要检查是否有表的ROWID达到最大值。

多线程写入

SQLite 支持三种线程模式:

  1. 单线程模式
    这种模式下,没有进行互斥,多线程使用不安全
  2. 多线程模式
    这种模式下,在多线程中使用单个数据库连接是不安全的,否则就是安全的。(译注:即不能在多个线程中共享数据库连接)
  3. 串行模式
    这种模式下,sqlite是线程安全的。

消息中间件应用场景

5.1 异步通信

有些业务不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。

5.2 解耦

降低工程间的强依赖程度,针对异构系统进行适配。在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。通过消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口,当应用发生变化时,可以独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。

5.3 冗余

有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。

5.4 扩展性

因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。便于分布式扩容。

5.5 过载保护

在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量无法提取预知;如果以为了能处理这类瞬间峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。

5.6 可恢复性

系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。

5.7 顺序保证

在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。

5.8 缓冲

在任何重要的系统中,都会有需要不同的处理时间的元素。消息队列通过一个缓冲层来帮助任务最高效率的执行,该缓冲有助于控制和优化数据流经过系统的速度。以调节系统响应时间。

5.9 数据流处理

分布式系统产生的海量数据流,如:业务日志、监控数据、用户行为等,针对这些数据流进行实时或批量采集汇总,然后进行大数据分析是当前互联网的必备技术,通过消息队列完成此类数据收集是最好的选择。

消息中间件常用协议

6.1 AMQP协议

AMQP即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。
优点:可靠、通用

6.2 MQTT协议

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。
优点:格式简洁、占用带宽小、移动端通信、PUSH、嵌入式系统

6.3 STOMP协议

STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。STOMP提供一个可互操作的连接格式,允许客户端与任意STOMP消息代理(Broker)进行交互。
优点:命令模式(非topic\queue模式)

6.4 XMPP协议

XMPP(可扩展消息处理现场协议,Extensible Messaging and Presence Protocol)是基于可扩展标记语言(XML)的协议,多用于即时消息(IM)以及在线现场探测。适用于服务器之间的准即时操作。核心是基于XML流传输,这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。
优点:通用公开、兼容性强、可扩展、安全性高,但XML编码格式占用带宽大

6.5 其他基于TCP/IP自定义的协议

有些特殊框架(如:redis、kafka、zeroMq等)根据自身需要未严格遵循MQ规范,而是基于TCP\IP自行封装了一套协议,通过网络socket接口进行传输,实现了MQ的功能。

Pub/Sub发布订阅(广播):使用topic作为通信载体 :

20190725_191436.png

PTP点对点:使用queue作为通信载体 :

20190725_191506.png

设置超时

初始化完毕后就可以设置。

// 2s timeout
int timeout = 2000;
int iRet = nn_setsockopt(m_sock_request, NN_SOL_SOCKET, NN_RCVTIMEO, &timeout, sizeof(timeout));
assert(iRet == 0);

int iRet = nn_setsockopt(m_sock_request, NN_SOL_SOCKET, NN_SNDTIMEO, &timeout, sizeof(timeout));
assert(iRet == 0);

使用 c++ 11 实现类成员函数回调

std::function<int(const char*, const int&, const void*)> m_cbFunc;
virtual void registerCallback(std::function<int(const char*, const int&, const void*)> Callback) = 0;

void ProtocolCommBase::registerCallback(std::function<int(const char*, const int&, const void*)> cbFunc)
{
m_cbFunc = std::move(cbFunc);
}

// 在另一个类里面绑定成员函数,使用 lambda 表达式
m_spProcol->registerCallback([&](const char* pval, const int& pvalLength, const void* pContext)->int { return callbackFunc(pval, pvalLength, pContext); });

int callbackFunc(const char* pval, const int& Number, const void* pContext);
int CDevEnvNoiseJNRS::callbackFunc(const char* pval, const int& Number, const void* pContext)
{
return 0;
}

exe 和 dll 之间传递 string 等 STL 对象时的内存分配问题。

使用 Multithread DLL debug 编译,不会出现这个问题,因为都是在 mfcvcrt.dll 中分配的

C++中如何定义接口类?
首先给接口类下了定义:接口类应该是只提供方法声明,而自身不提供方法定义的抽象类。接口类自身不能实例化,接口类的方法定义/实现只能由接口类的子类来完成。

而对于C++,其接口类一般具有以下特征:

  1. 最好不要有成员变量,但可以有静态常量(static const或enum)
  2. 要有纯虚接口方法
  3. 要有虚析构函数,并提供默认实现
  4. 不要声明构造函数
class Testable
{
public:
static const int START = 1; // #1
static const int STOP = 2;

virtual void test() = 0; // #2: 接口方法

virtual ~Testable() = default; // #3: 从C++11开始可以:
}

创建工程的时候选择 静态库 工程,就可以了。
不需要导出函数接口

Statically Linked to MFC

Pros

  1. It own private copy of MFC library code.
  2. No need distribute the shared DLLs Mfcxx.dll and Msvcrxx.dll

Cons

  1. Build static linked DLL takes more time. Becuase, it should link with MFC libraries.
  2. It takes more disk space and memory usage

Dynamically Linked to MFC

Pros

  1. Minimize memory usage
  2. Load only once and increment the reference count for each call. The new process mapped the memory with already loaded DLL.
  3. Save disk space

Cons

  1. distribute the shared DLLs Mfcxx.dll and Msvcrxx.dll ( Should not distribute debug version )