diff --git a/_config.yml b/_config.yml index 85f503d..22b6339 100644 --- a/_config.yml +++ b/_config.yml @@ -31,8 +31,8 @@ links: external: false # ------------ CONFIGURABLE END ------------ -#permalink: /:categories/:title.html -permalink: /:year/:month/:day/:title.html +permalink: /:categories/:title.html +#permalink: /:year/:month/:day/:title.html defaults: - values: layout: "default" diff --git a/_posts/API_software/2023-07-31-jekyll.md b/_posts/API_software/2023-07-31-jekyll.md index 62f4aff..c840e28 100644 --- a/_posts/API_software/2023-07-31-jekyll.md +++ b/_posts/API_software/2023-07-31-jekyll.md @@ -14,6 +14,238 @@ tags: {:toc} -#### Jekyll 究竟是什么?[Permalink](http://jekyllcn.com/docs/home/#jekyll-究竟是什么) +#### Jekyll 究竟是什么? -Jekyll 是一个简单的博客形态的静态站点生产机器。它有一个模版目录,其中包含原始文本格式的文档,通过一个转换器(如 [Markdown](http://daringfireball.net/projects/markdown/))和我们的 [Liquid](https://github.com/Shopify/liquid/wiki) 渲染器转化成一个完整的可发布的静态网站,你可以发布在任何你喜爱的服务器上。Jekyll 也可以运行在 [GitHub Page](http://pages.github.com/) 上,也就是说,你可以使用 GitHub 的服务来搭建你的项目页面、博客或者网站,而且是**完全免费**的。 +Jekyll 是一个简单的博客形态的**静态站点**生产机器。它有一个模版目录,其中包含原始文本格式的文档,通过一个转换器(如 [Markdown](http://daringfireball.net/projects/markdown/))和我们的 [Liquid](https://github.com/Shopify/liquid/wiki) 渲染器转化成一个完整的可发布的静态网站,你可以发布在任何你喜爱的服务器上。Jekyll 也可以运行在 [GitHub Page](http://pages.github.com/) 上,也就是说,你可以使用 GitHub 的服务来搭建你的项目页面、博客或者网站,而且是**完全免费**的。 + +[官方文档](http://jekyllcn.com/docs/) + + + +```bash +$ jekyll build +# => 当前文件夹中的内容将会生成到 ./_site 文件夹中。 + +$ jekyll build --destination +# => 当前文件夹中的内容将会生成到目标文件夹中。 + +$ jekyll build --source --destination +# => 指定源文件夹中的内容将会生成到目标文件夹中。 + +$ jekyll build --watch +# => 当前文件夹中的内容将会生成到 ./_site 文件夹中, +# 查看改变,并且自动再生成。 +``` + + + + + +#### 目录结构 + +``` +. +├── _config.yml +├── _drafts +| ├── begin-with-the-crazy-ideas.textile +| └── on-simplicity-in-technology.markdown +├── _includes +| ├── footer.html +| └── header.html +├── _layouts +| ├── default.html +| └── post.html +├── _posts +| ├── 2007-10-29-why-every-programmer-should-play-nethack.textile +| └── 2009-04-26-barcamp-boston-4-roundup.textile +├── _site +├── .jekyll-metadata +└── index.html +``` + + + +| 文件 / 目录 | 描述 | +| ---------------------------------------------------- | ------------------------------------------------------------ | +| `_config.yml` | 保存[配置](http://jekyllcn.com/docs/configuration/)数据。很多配置选项都可以直接在命令行中进行设置,但是如果你把那些配置写在这儿,你就不用非要去记住那些命令了。 | +| `_drafts` | drafts(草稿)是未发布的文章。这些文件的格式中都没有 `title.MARKUP` 数据。学习如何 [使用草稿](http://jekyllcn.com/docs/drafts/). | +| `_includes` | 你可以加载这些包含部分到你的布局或者文章中以方便**重用。**可以用这个标签 `{% include file.ext %}` 来把文件 `_includes/file.ext` 包含进来。 | +| `_layouts` | layouts(布局)是包裹在文章外部的**模板**。布局可以在 [YAML 头信息](http://jekyllcn.com/docs/frontmatter/)中根据不同文章进行选择。 这将在下一个部分进行介绍。标签 `{{ content }}` 可以将 content 插入页面中。 | +| `_posts` | 这里放的就是你的文章了。文件格式很重要,必须要符合: `YEAR-MONTH-DAY-title.MARKUP`。 [永久链接](http://jekyllcn.com/docs/permalinks/) 可以在文章中自己定制,但是数据和标记语言都是根据文件名来确定的。 | +| `_data` | 格式化好的网站数据应放在这里。jekyll 的引擎会自动加载在该目录下所有的 yaml 文件(后缀是 `.yml`, `.yaml`, `.json` 或者 `.csv` )。这些文件可以经由 `site.data` 访问。如果有一个 `members.yml` 文件在该目录下,你就可以通过 `site.data.members` 获取该文件的内容。 | +| `_site` | 一旦 Jekyll 完成转换,就会将生成的页面放在这里(默认)。最好将这个目录放进你的 `.gitignore` 文件中。 | +| `.jekyll-metadata` | 该文件帮助 Jekyll 跟踪哪些文件从上次建立站点开始到现在没有被修改,哪些文件需要在下一次站点建立时重新生成。该文件不会被包含在生成的站点中。将它加入到你的 `.gitignore` 文件可能是一个好注意。 | +| `index.html` and other HTML, Markdown, Textile files | 如果这些文件中包含 [YAML 头信息](http://jekyllcn.com/docs/frontmatter/) 部分,Jekyll 就会自动将它们进行转换。当然,其他的如 `.html`, `.markdown`, `.md`, 或者 `.textile` 等在你的站点根目录下或者不是以上提到的目录中的文件也会被转换。 | +| Other Files/Folders | 其他一些未被提及的目录和文件如 `css` 还有 `images` 文件夹, `favicon.ico` 等文件都将被完全拷贝到生成的 site 中。这里有一些[使用 Jekyll 的站点](http://jekyllcn.com/docs/sites/),如果你感兴趣就来看看吧。 | + + + + + +#### 头信息 + +| 变量名称 | 描述 | +| ----------- | ------------------------------------------------------------ | +| `layout` | 如果设置的话,会指定**使用该模板文件**。指定模板文件时候不需要文件扩展名。模板文件必须放在 `_layouts` 目录下。 | +| `permalink` | 如果你需要让你发布的博客的 URL 地址**不同于默认值** `/year/month/day/title.html`,那你就设置这个变量,然后变量值就会作为最终的 URL 地址。 | +| `published` | 如果你**不想**在站点生成后**展示**某篇特定的博文,那么就设置(该博文的)该变量为 false。 | +| `date` | 这里的日期会**覆盖文章名字中的日期**。这样就可以用来保障文章排序的正确。日期的具体格式为 `YYYY-MM-DD HH:MM:SS +/-TTTT`;时,分,秒和时区都是可选的。 | +| `category``categories` | 除过将博客文章放在某个文件夹下面外,你还可以指定博客的一个或者多个分类属性。这样当你的站点生成后,这些文章就可以根据这些分类来阅读。`categories` 可以通过 [YAML list](http://en.wikipedia.org/wiki/YAML#Lists),或者以逗号隔开的字符串指定。 | +| `tags` | 类似分类 `categories`,一篇文章也可以给它增加**一个或者多个**标签。同样,`tags` 可以通过 YAML 列表或者以逗号隔开的字符串指定。 | + + + + + +#### 头属性的属性格式 + +传统的块格式使用连字符 + 空格来开始列表中的新项目。 + +``` +--- # Favorite movies +- Casablanca +- North by Northwest +- The Man Who Wasn't There +``` + +可选的内联格式由逗号+空格分隔,并括在括号中 + +``` +--- # Shopping list +[milk, pumpkin pie, eggs, juice] +``` + + + + + +#### 头信息的默认值 + +通过使用 [YAML 头信息](http://jekyllcn.com/docs/frontmatter/)可以指定站点的页面和文章的配置。设置一些东西例如布局或者自定义标题,亦或是给文章指定一个更精确的日期 / 时间,这都可以往页面或文章的头信息添加数据来实现。 + +很多时候,你会发现你在重复填写很多配置项。在每个文件里设置相同的布局,对每篇文章添加相同的分类,等等。你甚至可能添加自定义变量,如作者名,这可能对你博客上大部分的文章来说是相同的。 + +Jekyll 提供了一个方法在站点配置中设置这些默认值,而不是在每次创建一个新的文章或页面重复此配置。要做到这一点,你可以在项目根目录下的 `_config.yml` 文件里设置 `defaults` 的值指定全站范围的默认值。 + +`defaults` 保存一个范围 / 值的对的数组,这定义了哪些默认值要设置到一个特定的文件路径下的文件,或者可选的,在该路径下指定 的文件类型的文件。 + +假设您想添加一个默认的布局给站点中的所有页面和文章。 你要将这添加到你的 `_config.yml` 文件: + +``` +defaults: + - + scope: + path: "" # 一个空的字符串代表项目中所有的文件 + values: + layout: "default" +``` + + + + + +#### 默认配置 + +``` +# 目录结构 +source: . +destination: ./_site +plugins: ./_plugins +layouts: ./_layouts +data_source: ./_data +collections: null + +# 阅读处理 +safe: false +include: [".htaccess"] +exclude: [] +keep_files: [".git", ".svn"] +encoding: "utf-8" +markdown_ext: "markdown,mkdown,mkdn,mkd,md" + +# 内容过滤 +show_drafts: null +limit_posts: 0 +future: true +unpublished: false + +# 插件 +whitelist: [] +gems: [] + +# 转换 +markdown: kramdown +highlighter: rouge +lsi: false +excerpt_separator: "\n\n" +incremental: false + +# 服务器选项 +detach: false +port: 4000 +host: 127.0.0.1 +baseurl: "" # does not include hostname + +# 输出 +permalink: date +paginate_path: /page:num +timezone: null + +quiet: false +defaults: [] + +# Markdown 处理器 +rdiscount: + extensions: [] + +redcarpet: + extensions: [] + +kramdown: + auto_ids: true + footnote_nr: 1 + entity_output: as_char + toc_levels: 1..6 + smart_quotes: lsquo,rsquo,ldquo,rdquo + enable_coderay: false + + coderay: + coderay_wrap: div + coderay_line_numbers: inline + coderay_line_number_start: 1 + coderay_tab_width: 4 + coderay_bold_every: 10 + coderay_css: style +``` + + + +#### 引用图片和其它资源 + +很多时候,你需要在文章中引用图片、下载或其它数字资源。尽管 Markdown 和 Textile 在链接这些资源时的语法并不一样,但你只需要关心在站点的哪些地方保存这些文件。 + +由于 Jekyll 的灵活性,有很多方式可以解决这个问题。一种常用做法是在工程的**根目录下创建一个文件夹**,命名为 `assets` 或者 `downloads`,将图片文件,下载文件或者其它的资源放到这个文件夹下。然后在任何一篇文章中,它们都可以用站点的根目录来进行引用。这和你站点的域名 / 二级域名和目录的设置相关,下面有一些例子(**Markdown 格式**)来演示怎样利用 `site.url` 变量来解决这个问题。 + +在文章中引用一个图片 + +``` +… 从下面的截图可以看到: +![有帮助的截图]({{ site.url }}/assets/screenshot.jpg) +``` + +链接一个读者可下载的 PDF 文件: + +``` +… 你可以直接 [下载 PDF]({{ site.url }}/assets/mydoc.pdf). +``` + + + + + +#### github 某些 样式 + +- [Jekyll Themes](http://jekyllthemes.org/) +- [博客模板 1](https://github.com/Liberxue/liberxue.github.io) +- [artemsheludko/bef: Bef is a responsive jekyll theme https://artemsheludko.github.io/bef/](https://github.com/artemsheludko/bef) +- [leopardpan/leopardpan.github.io: 个人博客,看效果进入](https://github.com/leopardpan/leopardpan.github.io) diff --git a/_posts/byte_tech/2023-07-26-0_overview.md b/_posts/byte_tech/2023-07-26-0_overview.md index d583455..a722d8e 100644 --- a/_posts/byte_tech/2023-07-26-0_overview.md +++ b/_posts/byte_tech/2023-07-26-0_overview.md @@ -23,10 +23,13 @@ tags: | 时间 | 7月25日(周二) | 7月26日(周三) | 7月28日(周五) | 7月31日(周一) | 8月1日(周二 | | ---- | ---------------------------- | ----------------- | ------------------------ | ------------------------- | --------------------------- | | 课程 | Go语言**基础语法** | Go语言工程实践 | 高质量编程与性能调优实践 | HTTP框架修炼之道 | 打开抖音会发生什么 | +| | | | | | | | 时间 | **8月2日(周三)** | **8月4日(周五)** | **8月5日(周六)** | **8月7日(周一)** | **8月8日(周二)** | | 课程 | 将我的服务开放给用户 | 深入浅出RPC框架 | 带你认识存储&数据库 | Go三件详解(Web/ RPC/ORM)R | redis一大厂程序员是怎么用的 | +| | | | | | | | 时间 | **8月10日(周四)** | **B月11日(周五)** | **8月14日(周一)** | **8月15日(周二)** | **B月18日(周五)** | | 课程 | TOS对象存储实战 | 走进消息队列 | 微服务架构原理与治理实践 | 架构初探之谁动了我的蛋糕 | 网站常见安全漏洞 | +| | | | | | | | | **8月21日(周一)** | **8月22日(周二)** | **8月24日周四** | | | | | 高性能Go语言发行版优化与落实 | 入理解RDBMS | 从零拷贝视角看性能忧化 | | | @@ -35,7 +38,7 @@ tags: #### 要求 - 每日问卷签到, 问卷开放时间为课程当日10:00-23:59, 过时不候 - - 周五出结果, 申诉要**趁早** + - **周五**出结果, 申诉要**趁早** - **[8月30日]**之前 , 符合要求打卡天数≥21天 - **[8月30日]**之前 , 笔记≥6篇 - 技术学习总结:总结青训营**直播**课程**学习到的知识点**,梳理分析,并给出自己的理解和对其他入门同学的学习建议 diff --git a/_posts/byte_tech/2023-07-31-go-3.md b/_posts/byte_tech/2023-07-31-go-3.md new file mode 100644 index 0000000..b33fb67 --- /dev/null +++ b/_posts/byte_tech/2023-07-31-go-3.md @@ -0,0 +1,14 @@ +--- +layout: blog +banana: true +category: byte_tech +title: "Go_3" +date: 2023-07-31 16:04:40 +background: green +tags: +- byte_tech +- go +--- + +* content +{:toc} diff --git a/_posts/byte_tech/2023-07-31-go-4.md b/_posts/byte_tech/2023-07-31-go-4.md new file mode 100644 index 0000000..6fff2e4 --- /dev/null +++ b/_posts/byte_tech/2023-07-31-go-4.md @@ -0,0 +1,433 @@ +--- +layout: blog +banana: true +category: byte_tech +title: "Go_4_HTTP" +date: 2023-07-31 11:02:06 +background: green +tags: +- byte_tech +- go +--- + +[TOC] + + + + + + +`ctrl` + `/`打开专注模式 + + + +![image-20230731154712540](assets/image-20230731154712540.png) + + + + + + + +### HTTp 框架 + + + + +#### 超文本传输协议 + +- 请求行/状态行 + - 方法名 + - URL + - 协议版本 +- **请求头**/响应头 +- 请求体/响应体 + +``` +POST /sis HTTP/1.1 +Who: Alex +Content-Type: text/plain +Host: 127.0.0.1:8888 +Content-Length: 28 +Let's watch a movie together +``` + + + + + +#### 问题与展望 + +- HTTP1 队头阻塞, 传输效率低, 明文传输不安全 (头部太大) +- HTTP2 多路复用, 头部压缩, 二进制协议 +- QUIC 基于UDP实现, 解决队头阻塞加, 密减少握手次数, 支持快速启动 + + + + + + + +#### 盖尔定律 + +一个切实可行的复杂系统势必是从一个切实可行的**简单系统**发展而来的。从头开始设计的复杂系统根本不切实可行,无法修修补补让它切实可行。你必须由一个切实可行的简单系统重新开始。 + + +先 `run`起来, 再考虑复用, 使用**迭代**的方式进行 + + + +#### 合理的 API + +不要试图在文档中说明,很多用户不看文档, 这也是在说: **代码的自注释性** + +- 可理解性:如ctx.Body(),ctx.GetBody(),不要用ctx. BodyA() +- 简单性:如`ctx.Request. Header.Peek(key)` + /ctx. GetHeader(key) +- 冗余性 +- 兼容性 +- 可测性 +- 可见性 + + + + + +#### 什么是框架和中间件 + +在计算机编程和软件开发中,框架中间件(Framework Middleware)是指位于**应用程序和底层框架**之间的软件组件或功能模块。它提供了一种可插拔的方式,用于增强、定制或修改框架的行为,以满足特定的需求。 + +框架中间件在应用程序和底层框架之间充当了一个抽象层,用于处理和转换请求、响应以及其他相关的操作。它可以介入整个请求 - 响应周期,对数据进行预处理、后处理或者执行其他的附加操作。 + +框架中间件的主要作用有: + +1. 路由和请求处理:中间件可以通过路由机制将请求分发给不同的处理程序,并执行相应的操作。它可以处理 URL 解析、参数提取、权限验证等任务。 +2. 数据转换和格式化:中间件可以对请求和响应的数据进行转换、验证和格式化。例如,可以将请求数据解析为特定的格式(如 JSON、XML),或者将响应数据转换为适合客户端的格式。 +3. 认证和授权:中间件可以处理用户身份认证和访问控制的任务。例如,它可以检查用户凭据、验证权限,决定是否允许用户继续执行操作。 +4. 缓存和性能优化:中间件可以在请求到达框架之前或之后,进行数据缓存、结果缓存以及其他的性能优化操作。它可以减少对底层资源的访问,提高应用程序的响应速度和性能。 +5. 日志记录和错误处理:中间件可以记录应用程序的运行日志,并处理异常情况和错误。它可以捕获和处理异常,记录错误信息,使得问题排查和故障修复更加方便有效。 + +框架中间件的设计目标是提供灵活性和可扩展性,以满足不同应用程序的需求。通过使用框架中间件,开发人员可以以模块化的方式定制和增强框架的功能,使得应用程序的开发和维护更加容易和高效。 + + + + + + + +#### 洋葱模型 + + + +适用场景: + +- 日志记录 +- 性能统计 +- 安全控制 +- 事务处理 +- 异常处理 + + + + + +#### 什么是 Handler + +在计算机编程和软件开发中,Handler(处理器)是指用于处理特定事件或请求的代码块、函数或对象。它充当了一个中间人,接收来自外部系统或其它组件的事件或请求,并对其进行适当的处理和响应。 + +Handler 的主要任务是根据接收到的事件或请求的类型,执行相应的逻辑。它可以包括各种操作,如数据处理、错误处理、用户界面更新、网络通信、数据库查询等。 + +Handler 可以存在于不同的上下文中。例如,对于图形用户界面(GUI),一个按钮点击事件的处理者就是一个 Handler;在服务端开发中,一个 HTTP 请求的处理者也可以被称为 Handler。它们根据特定的事件或请求类型,执行相应的操作以满足需求。 + +在许多框架和库中,一般会有一套明确定义的规则和接口来定义和使用 Handler。这些规则和接口可以使开发人员更方便地定义和注册 Handler,并将其与相应的事件或请求关联起来。 + +总之,Handler 是用于处理特定事件或请求的代码块、函数或对象,它负责执行相关的逻辑以满足需求。通过合理的使用和组织 Handler,可以有效地管理和处理系统中的各种事件和请求。 + + + + + + + + + + + + + + + +框架路由实际上就是为URL匹配对应的处理函数(Handlers) + +- 静态路由:/a/b/c./a/b/d +- 参数路 :/a/:id/c(/a/b/c,/a/d/c)./*all +- 路由修复: + - 如果只注册了 /a/b,但是访问的 URI 是 /a/b/,那可以提供自动重定向到 /a/b 能力;同样,如果只注册了 /a/b/,但是访问的 URI 是 /a/b,那可以提供自动重定向到 /a/b/ 能力 + +- 冲突路由以及优先级 + - 同时注册 /a/b 和 /:id/b,并设定优先级。比如:当请求 URI 为 /a/b 时,优先匹配静态路由 /a/b + +- 匹配HTTP方法 +- 多处理函数:方便添加中间件 + + + + + + + +如何匹配HTTP方法 + + + + + + + + + + + +#### 开发流程 + +- 1.明确需求:考虑清楚要解决什么问题,有哪些需求 +- 2.业界调研:业界都有哪些解决方案可供参考 +- 3.方案权衡:思考不同方案的取舍 +- 4.方案评审:相关同学对不同方案做评审 +- 5.确定开发:确定最合适的方案进行开发 + + + + + +```go +type Server interface{ + Serve(c context. Context, conn network.Conn) error +} + + +type Conn interface { + Read(b []byte)(n int, err error) + Write(b []byte)(n int, err error) +} +``` + + + + + +[字节内部网络模型](https://github.com/cloudwego/netpoll) + + + +#### 总结 + +- API设计:可理解性、简单性 +- 中间件设计: 洋葱模型 +- 路由设计:前缀匹配树 +- 协议层设计:抽象出合适的接口 +- 网络层设计: 网络模型 + + + + + +#### 设计点 + +- 存下全部Header +- 减少系统调用次数 +- 能够复用内存 +- 能够多次读 + + + + + +```go +type Reader interface { + // 开始读的位置 + Peek(n int)([]byte, error) + Discard(n int)(discarded int, err error) + Release() error + Size() int + Read(b []byte)(l int, err error) +} +``` + + + + + +#### 网络库比较 + +- `go net ` 流式友好, 小包性能高 +- `netpoll` 中大包性能高, 时延低 + + + + + +#### 针对协议的优化 + +- 找到Header Line边界:`\r\n`, 先找到`\n`再看它前一个是不是`\r` +- 热点资源**池化** + + + +针对协议相关的Headers + +- 1.通过 Header key 首字母快速筛除掉完全**不可能**的 key +- 2.解析对应 value到独立字段 +- 3.使用 byte slice 管理对应 header 存储,方便复用请求体中同样处理的Key: + User-Agent、 Content-Type、 Content-Length、 Connection、 Transfer-Encoding + + + +[开源 json 库](https:/github.com/bytedance/sonic) + + + +#### SIMD技术 + + + +SIMD(Single Instruction, Multiple Data)是一种**并行计算**的技术,它在同一时间执行相同的指令来处理多个数据元素。它是在计算机体系结构中用于向量化操作的一种方式。 + +传统的计算机指令集架构(ISA)以标量方式执行指令,即每次执行一个指令处理一个数据元素。而 SIMD 架构通过引入特殊的寄存器和指令集,能够同时处理多个数据元素,加速并行计算。 + +SIMD 技术适用于那些可以**被划分为多个独立任务**的数据,并且这些任务可以并行地进行相同的计算。它可以提高多媒体处理、图形渲染、信号处理、科学计算等应用的性能。 + +SIMD 指令集提供了一系列的指令,用于在单个时钟周期内同时对多个数据进行相同的操作。这些指令可以一次性处理多个数据元素,例如同时对四个浮点数执行加法操作。 + +常见的 SIMD 指令集包括 Intel 的 SSE(Streaming SIMD Extensions)、AMD 的 3DNow!、ARM 的 NEON 等。这些指令集通常有不同的版本,支持不同的宽度(如 128 位、256 位)和数据类型(如整数、浮点数)。 + +使用 SIMD 技术可以显著提高计算性能,但需要合理的程序设计和优化以充分利用 SIMD 指令集的并行计算能力。许多编程语言和编译器提供了对 SIMD 的支持,使得开发者能够方便地利用 SIMD 技术来加速计算。 + + + + + +#### 性能不是全部 + +- 追求性 +- 追求易用, 减少误用 +- 打通内部生态 +- 文档建设、用户群建设, + + + + + + + + + +### RPC框架 + +#### 什么是 RPC + +RPC(Remote Procedure Call)是一种用于实现**分布式**系统通信的协议和机制。它允许一个进程(客户端)调用另一个运行在不同地址空间的进程(服务器)中的函数或方法,就像调用本地函数一样。 + +RPC 的工作原理如下: + +1. 客户端通过本地调用的方式调用远程服务器的函数或方法。 +2. 客户端的 RPC stub(存根)将调用信息打包成网络可传输的消息,并发送给远程服务器。 +3. 服务器的 RPC stub 接收到消息后,解包调用信息并调用对应的函数或方法。 +4. 函数或方法执行完毕后,将结果打包成响应消息,并发送给客户端。 +5. 客户端的 RPC stub 接收到响应消息后,解包结果并返回给本地调用方。 + +通过 RPC,开发人员可以轻松地在分布式系统中调用远程服务,而无需关心底层的网络通信细节。它隐藏了网络通信的复杂性,使得分布式系统开发更加方便和高效。 + +RPC 的优势包括: + +1. 简化分布式系统开发:RPC 提供了一种简单而直观的方法来调用远程服务,使得分布式系统开发更加容易和高效。 +2. 高效的网络通信:RPC 可以使用高效的序列化和网络传输协议,以最小的开销在分布式系统间传递数据。 +3. 抽象底层细节:RPC 抽象了底层的网络通信细节,使得开发人员可以更专注于业务逻辑的实现,而不用关心底层通信协议和传输细节。 + +常见的 RPC 框架包括 gRPC、Apache Thrift、Spring Cloud、Dubbo 等。这些框架提供了丰富的功能和工具,使得分布式系统的开发、部署和管理更加便捷和可靠。 + + + + + + + +RPC需要解决的问题 + +- 1 函数**映射** +- 2.数据**转换**成字节流 +- 3.网络传输 + + + +RPC 的概念模型: + +- User、 +- User-Stub、 +- RPC-Runtime、 +- Server-Stub、 +- Server + + + + + +#### 优缺点 + +优点 + +- 单一职责,有利于分工协作和运维开发 +- 可扩展性强, 资源使用率更优 +- 故障隔离, 服务的整体可靠性更高 + + + +坏处 + +- 1.服务宕机,对方应该如何处理? +- 2.在调用过程中发生网络异常,如何保证消息的可达性? +- 3.请求量突增导致服务无法及时处理, 有哪些应对措施? + + + + + + + + + +#### 分层设计 + +- 编解码层 包括生成代码 +- 协议层 +- 网络层 + + + + + +- 语言特定的格式 + - 许多编程语言都内建了将内存对象编码为字节序列的支持,例如Java有java.io.Serializable +- 文本格式JSON、XML、CSV等文本格式,具有人类可读性 +- 二进制编码, 具备跨语言和高性能等优点,常见有Thrift的 BinaryProtocol, Protobuf + + + +TLV编码 + +- Tag:标签,可以理解为类型 +- Lenght:长度 +- Value:值,Value也可以是个TLV结构 + + + +增加了冗余信息 + + + +#### 编码层如何选 + +- 兼容性, 支持自动增加新的字段,而不影响老的服务,这将提高系统的灵活度 +- 通用性支持跨平台、跨语言 +- 性能从空间和时间两个维度来考虑,也就是编码后**数据大小**和**编码耗费时长** + diff --git a/_posts/byte_tech/assets/image-20230731154712540.png b/_posts/byte_tech/assets/image-20230731154712540.png new file mode 100644 index 0000000..0027136 Binary files /dev/null and b/_posts/byte_tech/assets/image-20230731154712540.png differ diff --git a/_posts/leetcode_week/2023-07-30-356.md b/_posts/leetcode_week/2023-07-30-356.md index f8b2502..064a921 100644 --- a/_posts/leetcode_week/2023-07-30-356.md +++ b/_posts/leetcode_week/2023-07-30-356.md @@ -5,6 +5,7 @@ category: algorithm title: 第356场周赛 date: 2023-07-30 16:04:01 background: purple +author: li54426 tags: - algorithm - leetcode_week @@ -26,14 +27,10 @@ tags: > > **子数组** 是数组中的一个连续非空序列。 > -> -> -> **示例 1:** -> -> ``` -> 输入:nums = [1,3,1,2,2] +> ``` +>输入:nums = [1,3,1,2,2] > 输出:4 -> 解释:完全子数组有:[1,3,1,2]、[1,3,1,2,2]、[3,1,2] 和 [3,1,2,2] 。 +>解释:完全子数组有:[1,3,1,2]、[1,3,1,2,2]、[3,1,2] 和 [3,1,2,2] 。 > ``` ```c++ @@ -58,6 +55,8 @@ public: mp[n]++; while(mp.size() == rem.size() && l< r){ + // 在左端点的情况下 + // 枚举右端点 res += (len - r +1); int n = nums[l++]; mp[n]--; @@ -77,3 +76,260 @@ public: +#### [2801. 统计范围内的步进数字数目 - 力扣(LeetCode)](https://leetcode.cn/problems/count-stepping-numbers-in-range/) + +> 给你两个正整数 `low` 和 `high` ,都用字符串表示,请你统计闭区间 `[low, high]` 内的 **步进数字** 数目。 +> +> 如果一个整数相邻数位之间差的绝对值都 **恰好** 是 `1` ,那么这个数字被称为 **步进数字** 。 +> +> 请你返回一个整数,表示闭区间 `[low, high]` 之间步进数字的数目。 +> +> 由于答案可能很大,请你将它对 `109 + 7` **取余** 后返回。 +> +> **注意:**步进数字不能有前导 0 。 +> +> ``` +> 输入:low = "1", high = "11" +> 输出:10 +> 解释:区间 [1,11] 内的步进数字为 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 和 10 。总共有 10 个步进数字。所以输出为 10 。 +> ``` + +```c++ +// 这一版代码好一点了, 虽然逻辑还是有点重复 +class Solution { + bool isper(string s){ + int len = s.size(); + for(int i =1; i mp; + function dfs = [&](int cur, int lastnum, bool islimit, string &s)-> int{ + // lastnum == -1 时代表着没有数字 + if(cur == s.size() ){ + return 1; + } + // cout<< "cur="<< cur<< "\tlastnum = "<< lastnum<< "\tislimit"<< islimit<< '\n'<< s<< '\n'; + int res = 0; + + // 都是前导零 + if(lastnum <0){ + res += dfs(cur+1, -1, false, s); + res %= k; + + int up = islimit? s[cur] - '0': 9 ; + for(int i = 1; i<= up; i++){ + res += dfs(cur+1, i, islimit && i ==up , s ); + res %= k; + } + + } + + else{ + int flag = 1000 * lastnum + cur; + if(!islimit && mp.count(flag)){ + return mp[flag]; + } + int up = islimit? s[cur] - '0': 9 ; + for(int i = lastnum <0? 1: 0; i<= up; ++i){ + if(abs(i - lastnum) == 1){ + res += dfs(cur+1, i, islimit&& i == up, s); + res %= k; + } + } + if(!islimit){ + mp[flag] = res; + } + + } + + + + + return res; + }; + int max = dfs(0, -1, true, high ); + mp.clear(); + return (max - dfs(0, -1, true, low ) + isper(low) + k)%k; + + } +}; +``` + + + +```c++ +// 极度让人恶心的代码 +// 发现逻辑很多重复了 + +class Solution { + bool isper(string s){ + int len = s.size(); + for(int i =1; i mp; + function dfs = [&](int cur, int lastnum, bool islimit, string &s)-> int{ + // lastnum == -1 时代表着没有数字 + if(cur == s.size() ){ + return 1; + } + // cout<< "cur="<< cur<< "\tlastnum = "<< lastnum<< "\tislimit"<< islimit<< '\n'<< s<< '\n'; + int res = 0; + if(islimit ){ + if(lastnum <0){ + int up = s[cur] - '0'; + res += dfs(cur+1, -1, false, s); + res %= k; + for(int i = 1; i<= up; i++){ + res += dfs(cur+1, i, islimit && i ==up , s ); + res %= k; + } + + } + + else{ // lastnum >= 0 + int up = s[cur] - '0'; + for(int i = 0; i<= up; ++i){ + if(abs(i - lastnum) == 1){ + res += dfs(cur+1, i, islimit&& i == up, s); + res %= k; + } + } + } + + + + + } + + else{// !islimit + int flag = cur + 1000 * lastnum; + if(mp.count(flag)){ + return mp[flag]; + } + + + if(lastnum <0 ){ + res += dfs(cur+1, -1, false, s); + res %=k; + for(int i = 1; i<= 9; i++){ + res += dfs(cur+1, i, false , s ); + res %= k; + } + } + + else{// lastnum >=0 + if(lastnum +1 <=9) + res += dfs(cur+1, lastnum +1, false, s); + res%= k; + + if(lastnum-1 >=0) + res += dfs(cur+1, lastnum -1, false, s); + res %= k; + } + + mp[flag] = res; + } + + return res; + }; + int max = dfs(0, -1, true, high ); + mp.clear(); + return (max - dfs(0, -1, true, low ) + isper(low) + k)%k; + + } +}; +``` + + + + + + + +#### [2800. 包含三个字符串的最短字符串 - 力扣(LeetCode)](https://leetcode.cn/problems/shortest-string-that-contains-three-strings/description/) + +> 给你三个字符串 `a` ,`b` 和 `c` , 你的任务是找到长度 **最短** 的字符串,且这三个字符串都是它的 **子字符串** 。 +> +> 如果有多个这样的字符串,请你返回 **字典序最小** 的一个。 +> +> 请你返回满足题目要求的字符串。 +> +> **注意:** +> +> - 两个长度相同的字符串 `a` 和 `b` ,如果在第一个不相同的字符处,`a` 的字母在字母表中比 `b` 的字母 **靠前** ,那么字符串 `a` 比字符串 `b` **字典序小** 。 +> - **子字符串** 是一个字符串中一段连续的字符序列。 +> +> ``` +> 输入:a = "abc", b = "bca", c = "aaa" +> 输出:"aaabca" +> 解释:字符串 "aaabca" 包含所有三个字符串:a = ans[2...4] ,b = ans[3..5] ,c = ans[0..2] 。结果字符串的长度至少为 6 ,且"aaabca" 是字典序最小的一个。 +> ``` + +```c++ +class Solution { + string merge(const string &a, const string &b){ + // return a+ b + + // 注意是不等于 -1, 因为可能是 0 + // 不要写 if(a.find(b) ) + if(a.find(b) != -1){ + return a; + } + + if(b.find(a) != -1){ + return b; + } + + for(int i = min(a.size(), b.size()); i>-1; --i){ + if(a.substr(a.size( ) -i ) == b.substr(0, i) ){ + // cout<< a+ b.substr(i)<< '\n'; + return a+ b.substr(i); + } + } + return ""; + } +public: + string minimumString(string a, string b, string c) { + string arr[] = {a, b, c}; + + string ans = ""; + // 枚举 arr 的全排列 + int perm[][3] = {{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}}; + for (const auto& p : perm) { + string s = merge(merge(arr[p[0]], arr[p[1]]), arr[p[2]]); + if (ans.empty() || s.length() < ans.length() || (s.length() == ans.length() && s < ans)) { + ans = s; + } + } + return ans; + } +}; +``` +