<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[f905699146的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/f905699146</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; f905699146]]></copyright><item><title><![CDATA[Golang 深度剖析 -- 理解Mutex源码实现]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/114039725</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/114039725</guid><author>f905699146</author><pubDate>Wed, 24 Feb 2021 20:31:15 +0800</pubDate><description><![CDATA[在golang的并发编程中，为了保证访问数据的安全性，经常会用到mutex去保证goroutine的同步，本文基于golang 1.14.6版本去分析mutex实现， golang中的mutex是一种排它锁，其实现结构如下:
// A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex.
//
// A Mutex must not be copied after first use.
ty]]></description><category></category></item><item><title><![CDATA[系统设计篇(三) -- 怎么设计高并发的服务(一)]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/109425063</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/109425063</guid><author>f905699146</author><pubDate>Sun, 01 Nov 2020 13:47:33 +0800</pubDate><description><![CDATA[高并发，高可用是服务端开发经常听到的词汇，在互联网应用中，随着用户的增加，后台服务需满足承载正常使用系统功能的用户数量。但是单机承载能力是有限的，因此通过多服务去支撑业务是必然的。但是不是所有业务都能通过简单的多服务扩展去解决，中间转换的过程会有很多问题，很多高并发服务的诞生并不是一蹴而就的，都是随着业务的扩展慢慢提高的，不同的场景遇到的问题也不一样，因此，在设计系统时需要因地制宜，根据当前业务场景去设计合适的架构。
水平扩展 OR 垂直扩展
网上听的最多的就是这两个词，垂直扩展好理解，就是提升单体服务的性]]></description><category></category></item><item><title><![CDATA[Golang 深度剖析 -- 理解Golang依赖注入]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/109200260</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/109200260</guid><author>f905699146</author><pubDate>Wed, 21 Oct 2020 14:23:12 +0800</pubDate><description><![CDATA[用过Java的都知道Spring框架，Spring核心是一个Ioc容器，各个模块都会注入到容器中，带来的优势是解耦，这样使得修改各个模块时不用管模块之间的依赖关系。
举个例子，一个服务里面有日志模块，配置模块，DB模块，业务模块等，其中日志模块依赖配置模块，DB模块依赖日志模块，配置模块，业务模块依赖所有基础模块。这样带来的一个问题是，如果有模块要修改，势必会影响其他模块，如果模块很多，还需要人为的规定初始化顺序，这对大型项目的维护来说是一件很恐怖的事，因此依赖注入的引入可以减少维护依赖关系的精力，专心使开]]></description><category></category></item><item><title><![CDATA[微服务系统设计篇(二) -- 如何做数据库选型]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/109120990</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/109120990</guid><author>f905699146</author><pubDate>Fri, 16 Oct 2020 17:48:35 +0800</pubDate><description><![CDATA[在微服务设计中，数据库的选型是不可缺少的一环，后台的核心是与数据打交道，在不同的业务场景选择的数据库不一样， 好的数据库选型能够解决业务的性能瓶颈，如果数据库选择不恰当，会使得服务的性能上不去，因此我们需要对一些常用的数据库有一些了解，这样才能因地制宜，发挥系统最好的性能。
常见的数据库分类：




数据库类型
数据库名称




关系型数据库
Mysql，Oracle，postgresql


内存数据库
Redis，Memcache


时序数据库
TSDB


文档型数据库
MongoDB


分布]]></description><category></category></item><item><title><![CDATA[微服务系统设计（一） -- 如何拆分服务]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/109053814</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/109053814</guid><author>f905699146</author><pubDate>Tue, 13 Oct 2020 16:09:35 +0800</pubDate><description><![CDATA[在做微服务设计的时候，很大的一个难题就是服务的拆分，很多人都不知道在什么情况拆分服务，在什么情况下不应该拆分服务，所以设计的系统可能会很臃肿，如果遇到业务扩展，之前设计的架构不能满足业务扩增后的需求，就会面临重构的风险，因此，在设计微服务架构时，合理的服务拆分是十分重要的。
前提
在做拆分服务之前，有一点特别重要，系统设计应该根据当前的用户情况而设计。如果目前用户不多并且增长比较慢，那么设计那些大而宽的架构并没有什么意义，单体服务就可以搞定，成本也比较小，并且可以满足早期的迅速开发和业务迭代需求，如果用户进]]></description><category></category></item><item><title><![CDATA[Golang 深度剖析 -- Map的实现原理]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/109021525</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/109021525</guid><author>f905699146</author><pubDate>Mon, 12 Oct 2020 09:30:50 +0800</pubDate><description><![CDATA[Golang标准库实现了Map容器，在很多业务场景都会用到这个容器，但是使用不当有可能会出现问题，这里我们来探究Map底层到底是如何实现的。
Map的实现在runtime/map.go，首先有这么一段介绍:
// A map is just a hash table. The data is arranged
// into an array of buckets. Each bucket contains up to
// 8 key/elem pairs. The low-order bits of t]]></description><category></category></item><item><title><![CDATA[Golang 深度剖析 -- channel的底层实现]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/109021243</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/109021243</guid><author>f905699146</author><pubDate>Mon, 12 Oct 2020 09:25:42 +0800</pubDate><description><![CDATA[目录:

channel 简介
channel 内部结构
创建channel
发送数据
接收数据
关闭channel
总结

channel 简介
Go语言有个很出名的话是“以通信的手段来共享内存”，channel就是其最佳的体现，channel提供一种机制，可以同步两个并发执行的函数，还可以让两个函数通过互相传递特定类型的值来通信。
channel有两种初始化方式，分别是带缓存的和不带缓存的:
make(chan int)   // 无缓存 chan
make(chan int, 10)  // 有缓存 ]]></description><category></category></item><item><title><![CDATA[OpenTsdb驱动简单实现]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/96480923</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/96480923</guid><author>f905699146</author><pubDate>Fri, 19 Jul 2019 16:08:43 +0800</pubDate><description><![CDATA[时序时空数据库TSDB简介和使用方案可以看文档 [tsdb文档](https://www.docs4dev.com/docs/zh/opentsdb/2.3/reference)

	TSDB对外只提供restful api，而且TSDB作为时序数据库，在后台的微服务的使用大部分场景只做查询，数据的写入交由其他的数据采集服务负责。我们之前有个使用场景是通过canal去监听mysql binlog...]]></description><category></category></item><item><title><![CDATA[gRPC使用]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/82786317</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/82786317</guid><author>f905699146</author><pubDate>Thu, 20 Sep 2018 14:18:02 +0800</pubDate><description><![CDATA[首先安装protobuf和grpc
go get -u github.com/grpc/grpc-go
go get -u github.com/golang/protobuf/proto
go-get -u github.com/golang/protobuf/protoc-gen-go  //--go-out工具

首先定义hello.proto
syntax=&quot;proto3&quot;;
option...]]></description><category></category></item><item><title><![CDATA[operator new和placement new的区别]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/82663656</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/82663656</guid><author>f905699146</author><pubDate>Wed, 12 Sep 2018 16:26:06 +0800</pubDate><description><![CDATA[new 关键字 
（1）调用operator new分配足够的空间，并调用相关对象的构造函数 
（2）不可以被重载

operator new 
（1）只分配所要求的空间，不调用相关对象的构造函数。当无法满足所要求分配的空间时，则 
        -&amp;gt;如果有new_handler，则调用new_handler，否则 
        -&amp;gt;如果没要求不抛出异常（以nothrow参数表达...]]></description><category></category></item><item><title><![CDATA[#pragma once和#ifndef的区别]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/82660863</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/82660863</guid><author>f905699146</author><pubDate>Wed, 12 Sep 2018 14:21:16 +0800</pubDate><description><![CDATA[1）#ifndef的方式依赖于宏名字不能冲突，这不光可以保证同一个文件不会被包含多次，也能保证内容完全相同的两个文件不会被不小心同时包含。当然，缺点就是如果不同头文件的宏名不小心“撞车”，可能就会导致头文件明明存在，编译器却硬说找不到声明的状况

2）#pragma once则由编译器提供保证：同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件，而不是指内容相同的两个文件。...]]></description><category></category></item><item><title><![CDATA[const 和 static的区别]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/82660157</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/82660157</guid><author>f905699146</author><pubDate>Wed, 12 Sep 2018 13:34:54 +0800</pubDate><description><![CDATA[static的作用：

对变量：

1.局部变量：

在局部变量之前加上关键字static，局部变量就被定义成为一个局部静态变量。

1）内存中的位置：静态存储区

2）初始化：未经初始化的全局静态变量会被程序自动初始化为0（自动对象的值是任意的，除非他被显示初始化）

3）作用域：作用域仍为局部作用域，当定义它的函数或者语句块结束的时候，作用域随之结束。

注：当static用来修饰局部变量的时...]]></description><category></category></item><item><title><![CDATA[内存读数据和磁盘读数据的区别]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/82659962</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/82659962</guid><author>f905699146</author><pubDate>Wed, 12 Sep 2018 13:13:16 +0800</pubDate><description><![CDATA[https://blog.youkuaiyun.com/zhanghongzheng3213/article/details/54141202/ 
当程序要读取的数据时传入内存地址（行地址+列地址），如果数据不在主存中时，会触发一个缺页异常，此时系统会向磁盘发出读盘信号，通过柱面号，磁头号，扇区号定位磁盘位置，找到数据的起始位置并向后连续读取一页或几页载入内存中。

于存储介质的特性，磁盘本身存取就比主存慢很...]]></description><category></category></item><item><title><![CDATA[tcp端口扫描方式]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/82625597</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/82625597</guid><author>f905699146</author><pubDate>Tue, 11 Sep 2018 14:40:57 +0800</pubDate><description><![CDATA[其实指TCP的连接方式 
一般有三种： 
1.通过connect 
客户端通过connect发起连接后，如果服务器处于监听状态就可以发起连接成功，否则说明端口是关闭的。优点是比较简单可靠，缺点是如果连接不成功会频繁的发包，扫描时间比较长 
2.通过SYN扫描 
向目标端口发送SYN数据帧，如果又收到SYN+ACK说明开放，如果收到RST说明关闭，在IP层实现。 
3.通过FIN扫描 
四次挥手的过...]]></description><category></category></item><item><title><![CDATA[c++类型别名]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/78071116</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/78071116</guid><author>f905699146</author><pubDate>Sat, 23 Sep 2017 15:30:39 +0800</pubDate><description><![CDATA[1、类型别名定义  
类型别名（type alias）是一个名字，它是某种类型的同义词。使用类型别名有很多好处，它让复杂的类型名字变得简单明了、易于理解和使用，还有助于程序员清楚地知道使用该类型的真实目的。有两种方法可用于定义类型别名。  
（1）传统的方法是使用关键字typedef：typedef double wages;   //wages是double的同义词  
typedef wages]]></description><category></category></item><item><title><![CDATA[c++11实现的线程池]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/77994859</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/77994859</guid><author>f905699146</author><pubDate>Fri, 15 Sep 2017 19:12:19 +0800</pubDate><description><![CDATA[前言C++11之前我们使用线程需要系统提供API、posix线程库或者使用boost提供的线程库，C++11后就加入了跨平台的线程类std::thread，线程同步相关类std::mutex、std::lock_guard、std::condition_variable、std::atomic以及异步操作相关类std::async、std::future、std::promise等等，这使得我们编写]]></description><category></category></item><item><title><![CDATA[mmap和shmget的区别]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/77843531</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/77843531</guid><author>f905699146</author><pubDate>Mon, 04 Sep 2017 22:21:33 +0800</pubDate><description><![CDATA[二者本质上是类似的，mmap可以看到文件的实体，而 shmget 对应的文件在交换分区上的 shm 文件系统内，无法直接 cat 查看 
安全性：mmap 方式对应的真实文件，如果用户有权限即可查看，甚至删除  
                 shmget 方式其实也一样，好了一层皮罢了（ipcrm -m …） 
一致性：mmap 方式下各进程映射文件的相同部分可以共享内存]]></description><category></category></item><item><title><![CDATA[abort,exit,return 的区别]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/77769338</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/77769338</guid><author>f905699146</author><pubDate>Fri, 01 Sep 2017 10:30:21 +0800</pubDate><description><![CDATA[exit(): 
在调用时，会做大部分清理工作，但是决不会销毁局部对象，因为没有stack unwinding。 
会进行的清理工作包括：销毁所有static和global对象，清空所有缓冲区，关闭所有I／O通道。终止前会调用经由atexit()登录的函数，atexit如果抛出异常，则调用terminate()。 
abort(): 
调用时，不进行任何清理工作。直接终止程序。 
retrun:]]></description><category></category></item><item><title><![CDATA[setjmp 和 longjmp 函数使用详解]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/77587845</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/77587845</guid><author>f905699146</author><pubDate>Fri, 25 Aug 2017 23:23:25 +0800</pubDate><description><![CDATA[非局部跳转语句—setjmp和longjmp函数。非局部指的是，这不是由普通C语言goto，语句在一个函数内实施的跳转，而是在栈上跳过若干调用帧，返回到当前函数调用路径上的某一个函数中。#include <setjmp.h>
int setjmp(jmp_buf  env);返回值：若直接调用则返回0，若从longjmp调用返回则返回非0值的longjmp中的val值void longjmp(jmp]]></description><category></category></item><item><title><![CDATA[c++多重继承的bug]]></title><link>https://blog.youkuaiyun.com/f905699146/article/details/77506781</link><guid>https://blog.youkuaiyun.com/f905699146/article/details/77506781</guid><author>f905699146</author><pubDate>Wed, 23 Aug 2017 15:38:23 +0800</pubDate><description><![CDATA[一个例子：#include <iostream>
using namespace std;class Base1{
public:
    virtual void foo1() {};
};class Base2{
public:
    virtual void foo2() {};
};class MI : public Base1, public Base2{
public:
    vir]]></description><category></category></item></channel></rss>