开发者博客 – IT技术 尽在开发者博客

开发者博客 – 科技是第一生产力


  • 首页

  • 归档

  • 搜索

数据库迁移搞炸了!没用这款开源神器的锅?

发表于 2021-01-12

SpringBoot实战电商项目mall(40k+star)地址:github.com/macrozheng/…

摘要

当我们的应用升级时往往会伴随着数据库表结构的升级,此时就需要迁移数据库的表结构。一般我们会使用工具或者脚本来实现,手动操作毕竟有一定风险,要是能在应用启动时自动升级数据库表结构就好了!Flyway正是这么一款工具,通过Flyway和SpringBoot结合使用,在应用启动时就可以自动升级数据库表结构,非常方便,推荐给大家!

Flyway简介

Flyway是一款数据库迁移工具,它让数据库迁移变得更加简单。它能像Git一样对数据库进行版本控制,支持命令行工具、Maven插件、第三方工具(比如SpringBoot)等多种使用方式。

Flyway具有如下特点:

  • 简单:使用和学习简单,通过不同版本的SQL脚本实现数据库迁移。
  • 专业:专注于数据库迁移功能,你无需担心有任何问题。
  • 功能强大:支持多种数据库,拥有大量的第三方工具,支持CI/DI。

相关概念

工作原理

使用Flyway时我们需要编写好数据库迁移的SQL脚本,比如 V1__Initial_Setup.sql中初始化了三种表,V2__First_Changes.sql中又新增了两种表。Flyway会创建flyway_schema_history表,用于存储这些SQL脚本的执行情况,从而对数据库进行版本控制。当我们使用Flyway进行数据库迁移时,Flyway会根据flyway_schema_history表中的记录,自行决定需要执行哪些SQL脚本,从而实现数据库迁移。

脚本命名规范

在创建Flyway的SQL脚本时,有些命名规范需要遵守,这些命名规范决定了Flyway执行脚本的顺序和方式,可以先参考下面的示意图。

为了能被Flyway正确执行,SQL迁移脚本需要遵循如下规范:

  • Prefix(前缀):V表示有版本号的数据库迁移,U表示一些数据库版本的回滚,R表示可重复执行的数据库迁移;
  • Version(版本号):Flyway会按照版本号的大小顺序来执行数据库迁移脚本;
  • Separator(分隔符):命名时使用双下划线分隔符;
  • Description(描述):用于描述该迁移脚本的具体操作说明;
  • Suffix(后缀):表示.sql文件。

相关命令

  • migrate:数据库迁移命令,会根据设置好的SQL脚本直接将数据库表升级至最新版本。
  • clean:删除数据库中所有的表,千万别在生产环境上使用。
  • info:打印所有关于数据库迁移的详细信息和状态信息。
  • validate:验证数据库迁移是否可用。
  • undo:对数据库迁移进行回滚操作。
  • baseline:以现有数据库为基准,创建flyway_schema_history表,大于基准版本的数据库迁移才会被应用。
  • repair:修复flyway_schema_history表。

命令行工具

使用Flyway实现数据迁移有多种方式,我们先通过命令行工具的方法来体验下Flyway的使用。

  • 首先需要下载Flyway的命令行工具,下载社区版即可,下载地址:flywaydb.org/download

  • 下载完成后进行解压,解压完成后目录结构如下;

  • 修改Flyway的配置文件/conf/flyway.conf,修改下数据库配置即可;
1
2
3
ini复制代码flyway.url=jdbc:mysql://localhost:3306/flyway?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai 
flyway.user=root
flyway.password=root
  • 在/sql目录下添加SQL执行脚本,这里添加创建ums_admin表的执行脚本V1.0.1__Create_ums_admin_table.sql;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sql复制代码CREATE TABLE `ums_admin`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL,
`icon` varchar(500) DEFAULT NULL COMMENT '头像',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`nick_name` varchar(200) DEFAULT NULL COMMENT '昵称',
`note` varchar(500) DEFAULT NULL COMMENT '备注信息',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
`status` int(1) DEFAULT '1' COMMENT '帐号启用状态:0->禁用;1->启用',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 8
DEFAULT CHARSET = utf8 COMMENT ='后台用户表';
  • 使用flyway migrate命令进行数据迁移,此时我们会发现需要先使用flyway baseline命令创建保存迁移记录的表flyway_schema_history才行;

  • 先使用flyway baseline命令,再使用flyway migrate命令,命令行会输出执行成功的信息;

  • 在\sql目录下添加SQL执行脚本,给ums_admin表添加一些数据,执行脚本为V1.0.2__Add_ums_admin.sql;
1
2
3
4
5
6
sql复制代码INSERT INTO ums_admin (username, PASSWORD, email, nick_name, STATUS)
VALUES ('test', '123456', 'test@qq.com', '测试账号', 1);
INSERT INTO ums_admin (username, PASSWORD, email, nick_name, STATUS)
VALUES ('macro', '123456', 'macro@qq.com', '普通账号', 1);
INSERT INTO ums_admin (username, PASSWORD, email, nick_name, STATUS)
VALUES ('andy', '123456', 'andy@qq.com', '普通账号', 1);
  • 我们可以使用flyway info命令查看flyway_schema_history表中的数据迁移记录,可以发现1.0.2版本的更新还处于Pending状态,使用flyway migrate命令后变为Success;

  • 我们可以创建可重复执行的SQL脚本,通常可以用来创建视图、存储过程、函数等,比如基于ums_admin表创建一个视图,执行脚本为R__Ums_admin_view.sql;
1
2
3
4
5
6
sql复制代码CREATE
OR REPLACE VIEW ums_admin_view AS
SELECT username,
PASSWORD,
email
FROM ums_admin;
  • 使用flyway migrate命令可以重复执行(当R开头的脚本有变更时),该脚本会在所有V开头的脚本执行完成后执行;

  • Flyway的回滚机制需要依赖SQL脚本,这里创建U1.0.1__Create_ums_admin_table.sql和U1.0.2__Add_ums_admin.sql两个回滚脚本;
1
2
sql复制代码# U1.0.1__Create_ums_admin_table.sql
DROP TABLE ums_admin
1
2
sql复制代码# U1.0.2__Add_ums_admin.sql
DELETE FROM ums_admin;
  • 使用flyway undo命令可以执行回滚,很遗憾的是社区版本不支持回滚,看样子数据库升级之前还是得通过工具做好备份才行!

Maven插件

Flyway也提供了Maven插件,插件所支持功能与命令行工具基本一致。

  • 想要在Maven项目通过插件使用Flyway,首先需要在pom.xml中添加Flyway的插件并配置好数据库连接信息;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
xml复制代码<!--Flyway的Maven插件-->
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>7.3.2</version>
<configuration>
<url>jdbc:mysql://localhost:3306/flyway?serverTimezone=Asia/Shanghai</url>
<user>root</user>
<password>root</password>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
</dependencies>
</plugin>
  • 在resouce目录下创建db\migration目录,将数据库升级使用的SQL脚本放入进去;

  • Flyway的Maven插件支持如下几种命令;

  • 双击flyway:info命令使用,输出如下内容,此方式与命令行工具使用基本没啥区别。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
csharp复制代码[INFO] --- flyway-maven-plugin:7.3.2:info (default-cli) @ mall-tiny-flyway ---
[INFO] Flyway Community Edition 7.3.2 by Redgate
[INFO] Database: jdbc:mysql://localhost:3306/flyway (MySQL 5.7)
[INFO] Schema version: 1.0.2
[INFO]
[INFO] +------------+---------+------------------------+----------+---------------------+----------+
| Category | Version | Description | Type | Installed On | State |
+------------+---------+------------------------+----------+---------------------+----------+
| | 1 | << Flyway Baseline >> | BASELINE | 2020-12-24 11:17:35 | Baseline |
| Versioned | 1.0.1 | Create ums admin table | SQL | 2020-12-24 11:17:42 | Success |
| Versioned | 1.0.2 | Add ums admin | SQL | 2020-12-24 11:33:40 | Success |
| Repeatable | | Ums admin view | SQL | 2020-12-24 11:33:40 | Success |
+------------+---------+------------------------+----------+---------------------+----------+

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9.076 s
[INFO] Finished at: 2020-12-24T14:28:16+08:00
[INFO] Final Memory: 28M/286M
[INFO] ------------------------------------------------------------------------

Process finished with exit code 0

结合SpringBoot使用

由于SpringBoot官方已经支持了Flyway,所以Flyway结合SpringBoot使用非常简单!

  • 首先在pom.xml中添加Flyway相关依赖,注意无需添加Flyway的版本号:
1
2
3
4
5
xml复制代码<!--Flyway相关依赖-->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
  • 修改配置文件application.yml,对数据源和Flyway进行配置;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
yaml复制代码spring:
datasource:
url: jdbc:mysql://localhost:3306/flyway?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
flyway:
# 启用Flyway功能
enabled: true
# 禁用Flyway的clean命令,使用clean命令会删除schema下的所有表
clean-disabled: true
# 设置Flyway的SQL脚本路径
locations: classpath:db/migration
# 设置版本信息控制表名称,默认flyway_schema_history
table: flyway_schema_history
# 在执行migrate命令时需要有flyway_schema_history表,通过baseline命令可以生成该表
baseline-on-migrate: true
# 指定baseline版本号,低于该版本的SQL脚本在migrate是不会执行
baseline-version: 1
# 设置字符编码
encoding: UTF-8
# 不允许不按顺序迁移
out-of-order: false
# 设置Flyway管控的schema,不设置的话为datasourcel.url中指定的schema
schemas: flyway
# 执行migrate时开启校验
validate-on-migrate: true
  • 最后直接运行SpringBoot应用,即可自动创建好对应的数据库,控制台会输出如下信息。
1
2
3
4
5
6
7
8
9
10
yaml复制代码2020-12-24 14:38:15.659  INFO 10716 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 6.4.1 by Redgate
2020-12-24 14:38:15.898 INFO 10716 --- [ main] o.f.c.internal.database.DatabaseFactory : Database: jdbc:mysql://localhost:3306/flyway (MySQL 5.7)
2020-12-24 14:38:15.972 INFO 10716 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 3 migrations (execution time 00:00.047s)
2020-12-24 14:38:15.988 INFO 10716 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `flyway`.`flyway_schema_history` with baseline ...
2020-12-24 14:38:16.106 INFO 10716 --- [ main] o.f.core.internal.command.DbBaseline : Successfully baselined schema with version: 1
2020-12-24 14:38:16.122 INFO 10716 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `flyway`: 1
2020-12-24 14:38:16.134 INFO 10716 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `flyway` to version 1.0.1 - Create ums admin table
2020-12-24 14:38:16.248 INFO 10716 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `flyway` to version 1.0.2 - Add ums admin
2020-12-24 14:38:16.281 INFO 10716 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `flyway` with repeatable migration Ums admin view
2020-12-24 14:38:16.314 INFO 10716 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 3 migrations to schema `flyway` (execution time 00:00.206s)

总结

对比手动升级数据库表结构,使用Flyway自动升级更有优势。使用Flyway可以在我们升级应用时同时升级数据库,由于社区版本目前不支持数据库回滚,升级前做好备份是很有必要的。

参考资料

官方文档:flywaydb.org/documentati…

项目源码地址

github.com/macrozheng/…

本文 GitHub github.com/macrozheng/… 已经收录,欢迎大家Star!

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

计科小伙们,我将用一篇文章,搞定你的毕业设计难题!!! 前言

发表于 2021-01-11

前言

大学生活转瞬即逝,又快要来到毕业的季节了。你准备好了吗?

本篇文章,我将拿出一个毕设项目给你们做一个分析。希望能给在准备毕设的你们带来些许帮助。

相信不少作为即将大四的毕业生,一方面,找自己的实习工作需要花费很多的时间。另外一方面,也是尤为重要的就是自己毕业设计。首先我们的毕业设计应该如何选题呢?

毕设选题问题

接下来我会从开始到结束整个毕设过程,给大家逐一说明,让正在困扰的毕业生的你指明道路,最后可以顺利毕业,首先第一步就是你的选题,这一步关乎你的整个项目是否能够顺利进行下去

而选择毕业设计题目需要注意以下的事项:

1.查阅相关的具体文献

先要了解你本专业的研究方向,就你所读的专业来说,你自己多翻阅下近几年来的学者们在你所在的这个领域都做过什么研究,用了哪些方法,最后取得了怎样的结论;

然后根据研究方向查阅相关具体的文献,拟定好你接下来的论文方向,记住的是一定要在原有的基础上有创新。

所以这前期的准备是必不可少的,先要从梳理相关文献做起。

2.选择难度比较适合自己的题目

要对自己有一个清醒的认识,自己代码编写动手能力,学习能力,快速查资料的能力,

要做一个系统全面的评估,即使你想要具体而又新颖的题目,也千万别觉得自己选个非常吸引导师眼球的题目就万事大吉了,

你要考虑到实际操作的时候是否也是这样,有些题目看似非常好,但是项目却是异常的难做,

就好比人工智能这一块,懂得人自然能够懂,然后看看这些题目,需要用到那些计算机知识、能力、语言、框架等等,看自己能不能快速地学会。

然后再根据自己找工作的时间安排,最终确定好适合的毕业设计题目。

在进行毕业论文的选题时,应着重注意选题要恰当。题目大小适中,对你的实际工作有一定的指导意义;

应结合当前科技和经济发展,尽可能选择与社会发展及实际工作相结合。

3.选择合适的导师以及跟他建立良好的关系

毕业设计的导师,一般情况下都是给我们上过课,需要值得关注的是别把导师当成装饰品,有些不会的问题一定要向他请教,自己要抓紧一点,积极地找导师商量,了解导师他对你的题目的一些想法,是否有时间会悉心指导你,

还有,万一你找工作的时间冲突,导师是否介意,也就是导师的性格上是否是一个愿意帮助学生的老师。

关键时候,你的导师是否愿意指导你这些等等,这很可能关系到你是否能够顺利毕业的关键。

综上所述,结合自己的能力,选择好的毕业设计题目实在是太重要了,就像高楼大厦建起来的时候,打好地基就是最关键的。

有的题目难度大且复杂,你前期没参与选题不知道有没有相关资料,假如选择好后做不出来项目,那就凉凉了。

项目案例

下面我要说的是一个【在线招标】的毕业设计项目。

这个项目使用到的技术有:

  1. Spring
  2. Spring mvc
  3. Hibernate

在系统功能方面分为四大块

  1. 招标公示
  2. 投标公示
  3. 发布招标
  4. 服务商管理

项目总体分析:

  • 在线招标系统采用spring,spring mvc框架进行开发,
  • 数据库方面由于业务不是太复杂,所以使用了hibernate框架。
  • 该毕业设计主要是将招标投标信息公示出来,
  • 系统功能包括:招标公示,投标公示,招标发布,服务商管理等。此系统适合对于招标业务有所了解的同学,有助于提高对spring等框架的理解。

项目页面图展示

1.这是招标公示页面:

2.这是服务商管理页面:

3.这是发布招标页面:

4.这是投标公示页面:

下面列举一部分毕设项目源码(共2000+篇):

写在结尾:感谢大家看到结束

需要毕业设计源码资料

转发+关注公众号:爱编程的fafa —>

回复关键字: 毕设 或者 毕业设计 即可获取资料

===============================

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

【对线面试官】Java NIO

发表于 2021-01-11

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
java复制代码public class NoBlockServer {

public static void main(String[] args) throws IOException {

// 1.获取通道
ServerSocketChannel server = ServerSocketChannel.open();

// 2.切换成非阻塞模式
server.configureBlocking(false);

// 3. 绑定连接
server.bind(new InetSocketAddress(6666));

// 4. 获取选择器
Selector selector = Selector.open();

// 4.1将通道注册到选择器上,指定接收“监听通道”事件
server.register(selector, SelectionKey.OP_ACCEPT);

// 5. 轮训地获取选择器上已“就绪”的事件--->只要select()>0,说明已就绪
while (selector.select() > 0) {
// 6. 获取当前选择器所有注册的“选择键”(已就绪的监听事件)
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

// 7. 获取已“就绪”的事件,(不同的事件做不同的事)
while (iterator.hasNext()) {

SelectionKey selectionKey = iterator.next();

// 接收事件就绪
if (selectionKey.isAcceptable()) {

// 8. 获取客户端的链接
SocketChannel client = server.accept();

// 8.1 切换成非阻塞状态
client.configureBlocking(false);

// 8.2 注册到选择器上-->拿到客户端的连接为了读取通道的数据(监听读就绪事件)
client.register(selector, SelectionKey.OP_READ);

} else if (selectionKey.isReadable()) { // 读事件就绪

// 9. 获取当前选择器读就绪状态的通道
SocketChannel client = (SocketChannel) selectionKey.channel();

// 9.1读取数据
ByteBuffer buffer = ByteBuffer.allocate(1024);

// 9.2得到文件通道,将客户端传递过来的图片写到本地项目下(写模式、没有则创建)
FileChannel outChannel = FileChannel.open(Paths.get("2.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

while (client.read(buffer) > 0) {
// 在读之前都要切换成读模式
buffer.flip();

outChannel.write(buffer);

// 读完切换成写模式,能让管道继续读取文件的数据
buffer.clear();
}
}
// 10. 取消选择键(已经处理过的事件,就应该取消掉了)
iterator.remove();
}
}

}
}

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
java复制代码public class NoBlockClient {

public static void main(String[] args) throws IOException {

// 1. 获取通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6666));

// 1.1切换成非阻塞模式
socketChannel.configureBlocking(false);

// 1.2获取选择器
Selector selector = Selector.open();

// 1.3将通道注册到选择器中,获取服务端返回的数据
socketChannel.register(selector, SelectionKey.OP_READ);

// 2. 发送一张图片给服务端吧
FileChannel fileChannel = FileChannel.open(Paths.get("X:\\Users\\ozc\\Desktop\\面试造火箭\\1.png"), StandardOpenOption.READ);

// 3.要使用NIO,有了Channel,就必然要有Buffer,Buffer是与数据打交道的呢
ByteBuffer buffer = ByteBuffer.allocate(1024);

// 4.读取本地文件(图片),发送到服务器
while (fileChannel.read(buffer) != -1) {

// 在读之前都要切换成读模式
buffer.flip();

socketChannel.write(buffer);

// 读完切换成写模式,能让管道继续读取文件的数据
buffer.clear();
}


// 5. 轮训地获取选择器上已“就绪”的事件--->只要select()>0,说明已就绪
while (selector.select() > 0) {
// 6. 获取当前选择器所有注册的“选择键”(已就绪的监听事件)
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

// 7. 获取已“就绪”的事件,(不同的事件做不同的事)
while (iterator.hasNext()) {

SelectionKey selectionKey = iterator.next();

// 8. 读事件就绪
if (selectionKey.isReadable()) {

// 8.1得到对应的通道
SocketChannel channel = (SocketChannel) selectionKey.channel();

ByteBuffer responseBuffer = ByteBuffer.allocate(1024);

// 9. 知道服务端要返回响应的数据给客户端,客户端在这里接收
int readBytes = channel.read(responseBuffer);

if (readBytes > 0) {
// 切换读模式
responseBuffer.flip();
System.out.println(new String(responseBuffer.array(), 0, readBytes));
}
}

// 10. 取消选择键(已经处理过的事件,就应该取消掉了)
iterator.remove();
}
}
}

}

文章以纯面试的角度去讲解,所以有很多的细节是未铺垫的。

鉴于很多同学反馈没看懂【对线面试官】系列,基础相关的知识我确实写过文章讲解过啦,但有的同学就是不爱去翻。

为了让大家有更好的体验,我把基础文章也找出来(重要的知识点我还整理过电子书,比如说像多线程、集合这种面试必考的早就已经转成PDF格式啦)

我把这些上传到网盘,你们有需要直接下载就好了。做到这份上了,不会还想白嫖吧?点赞和转发又不用钱。

链接:pan.baidu.com/s/1pQTuKBYs… 密码:3wom

欢迎关注我的微信公众号【Java3y】来聊聊Java面试

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

这次我让你彻底弄懂 RESTful

发表于 2021-01-11

RESTful 想必大家都耳熟能详。

但是为什么要有 RESTful,RESTful 到底是什么意思。

为什么称之为 RESTful 架构?

我不用 RESTful 不行吗?

什么样才叫真正的 RESTful ?

其实网上 RESTful 的文章有挺多的,不过有些讲的糊里糊涂的,而且很大部分都忽略了 HATEOAS。

在之前的面试中面试官就问过我,你怎么理解 RESTful 的,英文全称是啥?为什么叫这个名字?

当时我人都傻了。

面试官不讲武德,针对我这个刚出社会的小伙子。

其实有很多人也稀里糊涂的,也包括我自己。

就面向资源呗,不加动词咯,还能咋滴,我加动词不也能用吗?

而且我之前还特不能理解,为啥这叫架构?

我特意搜索了下架构的解释。

软件架构是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。

整体结构与组件的抽象描述。

RESTful 哪有什么组件和结构之间的玩意?

所以就至今我写下这篇文章的时候我也理解不了为什么叫 RESTful 架构。

可能是我对架构的理解太狭隘,还不到火候。

我个人只能理解成 RESTful 风格的 API 设计,也就是说 RESTful 只是一种指导风格,就像我们 Java 要用驼峰命名法。

那不用驼峰命名法代码就不能跑了吗?

当然能跑,这只是一种希望大家都能遵循的规范。

对 RESTful 而言我觉得算不上规范,只能说指导风格。

来让我们正式的进入对 RESTful 的剖析。

REST

REST 不是一个单词,是 Representational State Transfer 的缩写。

直译过来就是表述性状态转移。

我对这个名字蒙了一年多,就不能说点能听得懂的嘛。

从提出 REST 的论文中我翻了翻,没有明说但是表达的意思是其实它还有个主语 Resource 。

所以是资源的表述性状态转移。

稍微可以理解一点了。

我们先不管什么状态转移,大致先有点感觉。

知道 REST 之后 RESTful 就不难解释了,加 ful 就是变形容词了,比如 wonderful girl。

至此对名字稍微解释了一下,疑惑还在没事,咱们慢慢理。

REST 的核心

核心就是资源,用 URL 定位资源,用 HTTP 动词来描述所要做的操作。

HTTP的提供了很多动词:GET、PUT、POST、DELETE……

这些动词都是有含义的。

比如 GET 就是获取资源,是查询请求。

PUT 指的是修改资源,是幂等的。

POST 也是修改(新增也是一种修改),指的是不幂等的操作。

所以根据这些规范我们都能得知这次交互的一些动作,所以正确的使用姿势如下:

比如获取一个 user。

错误姿势:GET /getUserById?userId=1。

正确姿势:GET /users/1。

再比如新增 user。

错误姿势:POST /addUser (省略body)。

正确姿势:POST /users (省略body)。

可以看到 HTTP 的动词其实就能指代你要对资源做的操作,所以不需要在 URL 上做一些东西,就把 URL 表明的东西就看做一个资源即可。

这里注意要用对 HTTP 动词,比如一个获取资源的请求用 PUT,用了也能获取资源但是这不合适。

其实更深一步的理解是 HTTP 是一个协议。

协议其实就是约定好的一个东西,协议就规定 GET 是获取资源,那你非得在 URL 上再重复一遍或者所有请求不论增删改都用 GET 这个动作,这其实就是没有完全遵循这个协议。

可以说只是把 HTTP 当成一个传输管道,而不是约定好的协议。

这其实是对 HTTP 更深一层的认识,我认为也是 RESTful 被推出的原因。

当然理想很丰满,现实很骨感,还是有很多人就 getUserById。

不过我个人觉得问题不大,公司统一就行。

HATEOAS

即 Hypermedia as the Engine of Application State 的缩写,翻译过来就是作为应用状态引擎的超媒体。

这也是 REST 提出的设计。

是不是理解不了?其实很简单。

例子我就不自己编了,抄一下 stackoverflow 回答上的例子。

比如你请求获取用户列表:

1
2
bash复制代码GET /users
Accept: application/json+userdb

此时的返回应该是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
python复制代码200 OK
Content-Type: application/json+userdb

{
"users": [
{
"id": 1,
"name": "Emil",
"country: "Sweden",
"links": [
{
"href": "/user/1",
"rel": "self",
"method": "GET"
},
{
"href": "/user/1",
"rel": "edit",
"method": "PUT"
},
{
"href": "/user/1",
"rel": "delete",
"method": "DELETE"
}
]
},
{
"id": 2,
....省略.....
}
],
"links": [
{
"href": "/user",
"rel": "create",
"method": "POST"
}
]
}

重点就是这个 links,结果会返回你能对这个资源所做的操作。

比如对于 userId 是 1 的,你调用 PUT /user/1就是做修改这个用户,DELETE /user/1 就是删除这个用户。

最外层的 links 告诉你用 POST /user 就能再创建一个用户。

这里还有个隐藏信息,可能看到外层的 links 没有返回 DELETE 的信息,说明此时客户端无法删除用户!

所以说 RESTful API 还需要在返回此时能做资源所做的操作,这样客户端就知道它能做什么。

它也不需要管具体怎么做,反正返回里面会告诉它 DELETE 就这样这样,POST 就这样这样。

没告诉它的就是不能做的。

然后这个时候再去理解下资源的表述性状态转移,是不是感觉来了?

如果说上一 part 提到用 HTTP 的动词来指代动作, URL 仅表示资源的现实是骨感的。

那么 HATEOAS 的现实就是灰。

基本上没几家公司会这么做。

就我个人而言这玩意没啥用。

它的出发点是让客户端从响应就能得知对资源操作的入口,并且通过响应就得知哪些动作能执行。

听起来好像有点用,但是就我目前的功力,我只能看到响应变得十分冗余。

最后

这篇文章关于 RESTful API 具体的写法我就提到一些,还有挺多的就自己查资料吧。

文章的目的是为了让你理解 RESTful API,我再总结一下重点。

HTTP 是协议,不是传输通道。(对协议不理解的看我之前的 HTTP 分析)

所以协议约定了很多东西,推荐我们按照协议的用法进行客户端和服务端的交互。

也就是 RESTful 表明的面向资源,通过 HTTP 动作 + URL 上的资源。

RESTful 还提到了 HATEOAS,虽说基本上没什么公司会这样使用,但是它能让你更好的理解 REST 这个名字的含义。

RESTful 是一种风格,你是否采用这种风格对你的程序运行没有影响,类比驼峰命名来思考。

简而言之,就是不要在 URL 上表现出动作,用 HTTP 动词代表动作,URL 上只做资源,仅此而已。

至于要不要严格遵循 RESTful 风格,我个人的看法是公司内部保持一致就行。

巨人的肩膀

www.ics.uci.edu/~fielding/p…

www.ruanyifeng.com/blog/2011/0…

stackoverflow.com/questions/6…

en.wikipedia.org/wiki/HATEOA…

微信搜 「yes的练级攻略」干货满满,不然来掐我,回复【123】一份20W字的算法刷题笔记等你来领。 更多文章可看我的文章汇总:github.com/yessimida/y… 欢迎 star !

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

除了负载均衡,Nginx 能做的真是太强大了!

发表于 2021-01-11

Nginx应该是现在最火的web和反向代理服务器,没有之一。她是一款诞生于俄罗斯的高性能web服务器,尤其在高并发情况下,相较Apache,有优异的表现。

那除了负载均衡,她还有什么其他的用途呢,下面我们来看下。

一、静态代理

Nginx擅长处理静态文件,是非常好的图片、文件服务器。把所有的静态资源的放到nginx上,可以使应用动静分离,性能更好。

二、负载均衡

Nginx通过反向代理可以实现服务的负载均衡,避免了服务器单节点故障,把请求按照一定的策略转发到不同的服务器上,达到负载的效果。

image

常用的负载均衡策略有:

1、轮询

将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载。

2、加权轮询

不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。

给配置高、负载低的机器配置更高的权重,让其处理更多的请;而配置低、负载高的机器,给其分配较低的权重,降低其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。

3、ip_hash(源地址哈希法)

根据获取客户端的IP地址,通过哈希函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客户端要访问服务器的序号。

采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。

4、随机

通过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台服务器进行访问。

5、least_conn(最小连接数法)

由于后端服务器的配置不尽相同,对于请求的处理有快有慢,最小连接数法根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前的请求,尽可能地提高后端服务的利用效率,将负责合理地分流到每一台服务器。

三、限流

Nginx的限流模块,是基于漏桶算法实现的,在高并发的场景下非常实用,如下图:

image

1、配置参数

1)limit_req_zone定义在http块中,$binary_remote_addr 表示保存客户端IP地址的二进制形式。

2)Zone定义IP状态及URL访问频率的共享内存区域。

zone=keyword标识区域的名字,以及冒号后面跟区域大小。16000个IP地址的状态信息约1MB,所以示例中区域可以存储160000个IP地址。

3)Rate定义最大请求速率。示例中速率不能超过每秒100个请求。

2、设置限流

burst排队大小,nodelay不限制单个请求间的时间。

四、缓存

1、浏览器缓存,静态资源缓存用expire。

image

2、代理层缓存

image

五、黑白名单

1、不限流白名单

image

2、黑名单

image

好了,上面就是nginx几个常用功能,静态分离、负载均衡、限流、缓存、黑白名单等,你都了解了吗!

来源:www.toutiao.com/i6692127248…

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

「Java 路线」 服务发现框架 ServiceLoade

发表于 2021-01-11

请点赞关注,你的支持对我意义重大。

🔥 Hi,我是小彭。本文已收录到 GitHub · AndroidFamily 中。这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] 带你建立核心竞争力。


前言

大家好,我是小彭。

过去两年,我们在掘金平台上发布过一些文章,小彭也受到了大家的意见和鼓励。最近,小彭会陆续搬运到公众号上。

记录:2022 年 9 月 6 日修订:优化文章结构

学习路线图:


  1. 认识服务发现?

1.1 什么是服务发现

服务发现(Service Provider Interface,SPI)是一个服务的注册与发现机制,通过解耦服务提供者与服务使用者,实现了服务创建 & 服务使用的关注点分离。 服务提供模式可以为我们带来以下好处:

  • 1、在外部注入或配置依赖项,因此我们可以重用这些组件。当我们需要修改依赖项的实现时,不需要大量修改很多处代码,只需要修改一小部分代码;
  • 2、可以注入依赖项的模拟实现,让代码测试更加容易。

服务发现示意图

1.2 服务发现和依赖注入的区别

服务发现和依赖注入都是控制反转 Ioc 的实现形式之一。 IoC 可以认为是一种设计模式,但是由于理论成熟的时间相对较晚,所以没有包含在《设计模式 · GoF》之中,即: 当依赖方需要使用依赖项时,不再直接构造对象,而是由外部 IoC 容器来创建并提供依赖。

  • 1、服务提供模式: 从外部服务容器抓取依赖对象,调用方可以 “主动” 控制请求依赖对象的时机;
  • 2、依赖注入: 并以参数的形式注入依赖对象,调用方 “被动” 接收外部注入的依赖对象。

  1. JDK ServiceLoader 的使用步骤

在分析 ServiceLoader 的使用原理之前,我们先来介绍下 ServiceLoader 的使用步骤。

我们直接以 JDBC 作为例子,其中「2、连接数据库」内部就是用了 ServiceLoader。为什么连接数据库需要使用 SPI 设计思想呢?因为操作数据库需要使用厂商提供的数据库驱动程序,如果直接使用厂商的驱动耦合太强了,而使用 SPI 设计就能够实现服务提供者与服务使用者解耦。

以下为使用步骤,具体分为 5 个步骤:

  • 1、(非必须)执行数据库驱动类加载:
1
java复制代码Class.forName("com.mysql.jdbc.driver")
  • 2、连接数据库:
1
java复制代码DriverManager.getConnection(url, user, password)
  • 3、创建SQL语句:
1
java复制代码Connection#.creatstatement();
  • 4、执行SQL语句并处理结果集:
1
java复制代码Statement#executeQuery()
  • 5、释放资源:
1
2
3
java复制代码ResultSet#close()
Statement#close()
Connection#close()

下面,我们一步步手写 JDBC 中关于 ServiceLoader 的相关源码:

步骤 1:定义服务接口

定义一个驱动接口,这个接口将由数据库驱动实现类实现。在服务发现框架中,这个接口就是服务接口。

1
2
3
4
5
java复制代码public interface Driver {
// 创建数据库连接
Connection connect(String url, java.util.Properties info);
...
}

步骤 2:实现服务接口

数据库厂商提供一个或多个实现 Driver 接口的驱动实现类,以 mysql 和 oracle 为例:

  • mysql:com.mysql.cj.jdbc.Driver.java
1
2
3
4
5
6
7
8
java复制代码// 已简化
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
// 注册驱动
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
  • oracle:oracle.jdbc.driver.OracleDriver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码// 已简化
public class OracleDriver implements Driver {
private static OracleDriver defaultDriver = null;
static {
if (defaultDriver == null) {
// 1、单例
defaultDriver = new OracleDriver();
// 注册驱动
DriverManager.registerDriver(defaultDriver);
}
}
...
}

步骤3:注册实现类到配置文件

在工程目录 java 的同级目录中新建目录 resources/META-INF/services ,新建一个配置文件 java.sql.Driver(文件名为服务接口的全限定名),文件中每一行是实现类的全限定名,例如:

1
复制代码com.mysql.cj.jdbc.Driver

我们可以解压 mysql-connector-java-8.0.19.jar 包,找到对应的 META-INF 文件夹。

步骤4:(使用方)加载服务

DriverManaer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码// 已简化
static {
loadInitialDrivers();
}

// 入口
private static void loadInitialDrivers() {
...
// 读取 "jdbc.drivers" 属性
String drivers = System.getProperty("jdbc.drivers");

// 1、使用 ServiceLoader 遍历 Driver 服务接口的实现类
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
// 2、获得迭代器
Iterator<Driver> driversIterator = loadedDrivers.iterator();
// 3、迭代(ServiceLoader 内部会通过反射)
while(driversIterator.hasNext()) {
driversIterator.next();
}
return null;
...
}

可以看到,DriverManager 被类加载时(static{})会调用 loadInitialDrivers() 。这个方法内部通过 ServiceLoader 提供的迭代器 Iterator 遍历了所有驱动实现类。那么,ServiceLoader 是如何实例化 Driver 接口的实现类的呢?下一节,我们会深入 ServiceLoader 的源码来解答这个问题。


  1. ServiceLoader 源码解析

3.1 ServiceLoader 入口方法

ServiceLoader 提供了三个静态泛型工厂方法,内部最终将调用 ServiceLoader.load(Class, ClassLoader),其中第一个参数就是服务接口的 Class 对象。

ServiceLoader.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码// 方法 1:
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
// 使用 SystemClassLoader 类加载器
ClassLoader cl = ClassLoader.getSystemClassLoader();
ClassLoader prev = null;
while (cl != null) {
prev = cl;
cl = cl.getParent();
}
return ServiceLoader.load(service, prev);
}

// 方法 2:
public static <S> ServiceLoader<S> load(Class<S> service) {
// 使用线程上下文类加载器
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}

// 方法 3(最终走到这个方法):
public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader){
return new ServiceLoader<>(service, loader);
}

可以看到,三个方法仅在传入的类加载器不同,最终只是返回了一个面向服务接口 S 的 ServiceLoader 对象。我们先看一下构造器里做了什么工作。

3.2 ServiceLoader 构造方法

ServiceLoader.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码// 已简化
private final Class<S> service;

// 服务实现缓存
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

private ServiceLoader(Class<S> svc, ClassLoader cl) {
// 1、类加载器
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
// 2、清空 providers
providers.clear();
// 3、实例化 LazyIterator
lookupIterator = new LazyIterator(service, loader);
}

可以看到,ServiceLoader 的构造器中主要就是实例化了一个 LazyIterator 迭代器的实例,这是一个「懒加载」的迭代器。这个迭代器里做了什么呢?我们继续往下看

3.3 LazyIterator 迭代器

ServiceLoader.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
java复制代码// -> 3、实例化 LazyIterator

// 前文提到的配置文件路径
private static final String PREFIX = "META-INF/services/";

private class LazyIterator implements Iterator<S> {

// 服务接口 Class 对象
Class<S> service;
ClassLoader loader;
Enumeration<URL> configs = null;

// pending、nextName:用于解析配置文件中的服务实现类名
Iterator<String> pending = null;
String nextName = null;

private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}

// 3.1 判断是否有下一个服务实现
@Override
public boolean hasNext() {
return hasNextService();
}

// 3.2 返回下一个服务实现
@Override
public S next() {
return nextService();
}

@Override
public void remove() {
throw new UnsupportedOperationException();
}

// -> 3.1 判断是否有下一个服务实现
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
// 3.1.1 拼接配置文件路径:META-INF/services/服务接口的全限定名
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
}

// 3.1.2 parse:解析配置文件资源的迭代器
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
// 3.1.3 下一个实现类的全限定名
nextName = pending.next();
return true;
}

// 3.2 返回下一个服务实现
private S nextService() {
if (!hasNextService()) throw new NoSuchElementException();
String cn = nextName;
nextName = null;

// 3.2.1 使用类加载器 loader 加载
Class<?> c = Class.forName(cn, false /* 不执行初始化 */, loader);
if (!service.isAssignableFrom(c)) {
// 检查是否实现 S 接口
ClassCastException cce = new ClassCastException(service.getCanonicalName() + " is not assignable from " + c.getCanonicalName());
fail(service, "Provider " + cn + " not a subtype", cce);
}

// 3.2.2 使用反射创建服务类实例
S p = service.cast(c.newInstance());

// 3.2.3 服务实现类缓存到 providers
providers.put(cn, p);
return p;
}
}

// -> 3.1.2 parse:解析配置文件资源的迭代器
private Iterator<String> parse(Class<?> service, URL u) throws ServiceConfigurationError {
// 使用 UTF-8 编码输入配置文件资源
InputStream in = u.openStream();
BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"));
ArrayList<String> names = new ArrayList<>();
int lc = 1;
while ((lc = parseLine(service, u, r, lc, names)) >= 0);
return names.iterator();
}

以上代码已经非常简化了,LazyIterator 的要点如下:

  • hasNext() 判断逻辑:
    • 3.1.1 拼接配置文件路径:「META-INF/services/服务接口的全限定名」;
    • 3.1.2 解析配置文件资源的迭代器;
    • 3.1.3 找到下一个实现类的全限定名。
  • next() 逻辑:
    • 3.2.1 使用类加载器 loader 加载(不执行初始化);
    • 3.2.2 使用反射创建服务类实例;
    • 3.2.3 服务实现类缓存到 providers。

小结一下: LazyInterator 会解析「META-INF/services/服务接口的全限定名」配置,遍历每个服务实现类全限定类名,执行类加载(未初始化),最后将服务实现类缓存到 providers。

那么,这个迭代器在哪里使用的呢?继续往下看~

3.4 包装迭代器

其实 ServiceLoader 本身就是实现 Iterable 接口的:

ServiceLoader.java

1
java复制代码public final class ServiceLoader<S> implements Iterable<S>

让我们来看看 ServiceLoader 中的 Iterable#iterator() 是如何实现的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
java复制代码private LazyIterator lookupIterator;

// 4、返回一个新的迭代器,包装了 providers 和 lookupIterator
public Iterator<S> iterator() {
return new Iterator<S>() {

// providers 就是上一节 next() 中缓存的服务实现
Iterator<Map.Entry<String,S>> knownProviders = providers.entrySet().iterator();

@Override
public boolean hasNext() {
// 4.1 优先从 knownProviders 取,再从 LazyIterator 取
if (knownProviders.hasNext()) return true;
return lookupIterator.hasNext();
}

@Override
public S next() {
// 4.2 优先从 knownProviders 取,再从 LazyIterator 取
if (knownProviders.hasNext()) return knownProviders.next().getValue();
return lookupIterator.next();
}

@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}

可以看到,ServiceLoader 里有一个泛型方法 Iterator iterator(),它包装了 providers 集合迭代器和 lookupIterator 两个迭代器。对于已经 “发现” 的服务实现类会被缓存到 providers 集合中,包装类的作用就是优先读取缓存而已。


  1. ServiceLoader 源码分析总结

理解 ServiceLoader 源码之后,我们总结要点如下:

4.1 约束

1、服务实现类必须实现服务接口 S( if (!service.isAssignableFrom(c)) );
2、服务实现类需包含无参的构造器,LazyInterator 是反射创建实现类市里的( S p = service.cast(c.newInstance()) );
3、配置文件需要使用 UTF-8 编码( new BufferedReader(new InputStreamReader(in, "utf-8")) )。

4.2 懒加载

ServiceLoader 使用「懒加载」的方式创建服务实现类实例,只有在迭代器推进的时候才会创建实例( nextService() )。

4.3 内存缓存

ServiceLoader 使用 LinkedHashMap 缓存创建的服务实现类实例。

提示: LinkedHashMap 在迭代时会按照 Map#put 执行顺序遍历。

4.4 没有服务注销机制

服务实现类实例被创建后,它的垃圾回收的行为与 Java 中的其他对象一样,只有这个对象没有到 GC Root 的强引用,才能作为垃圾回收。而 ServiceLoader 内部只有一个方法来完全清除 provices 内存缓存。

1
2
3
4
csharp复制代码public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}

4.5 没有服务筛选机制

当存在多个提供者时,ServiceLoader 没有提供筛选机制,使用方只能在遍历整个迭代器中的所有实现,从发现的实现类中决策出一个最佳实现。举个例子,我们可以使用字符集的表示符号来获得一个对应的 Charset 对象:Charset.forName(String),这个方法里面就只会选择匹配的 Charaset 对象。

CharsetProvider.java

1
2
3
4
5
java复制代码服务接口
public abstract class CharsetProvider {
public abstract Charset charsetForName(String charsetName);
// 省略其他方法...
}

Charset.java

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码public static Charset forName(String charsetName) {
// 以下只摘要与 ServiceLoader 有关的逻辑...

ServiceLoader<CharsetProvider> sl = ServiceLoader.load(CharsetProvider.class, cl);
Iterator<CharsetProvider> i = sl.iterator();
for (Iterator<CharsetProvider> i = providers(); i.hasNext();) {
CharsetProvider cp = i.next();
// 满足匹配条件,return
Charset cs = cp.charsetForName(charsetName);
if (cs != null)
return cs;
}
}

  1. 总结

  • 服务发现 SPI 是控制反转 IoC 的实现方式之一,而 ServiceLoader 是 JDK 中实现的 SPI 框架。ServiceLoader 本身就是一个 Iterable 接口,迭代时会从 META-INF/services 配置中解析接口实现类的全限定类名,使用反射创建服务实现类对象;
  • ServiceLoader 是 JDK 自带的服务发现框架,原理也相对简单,比如 Charset、AnnocationProcessor 等功能都是基于 ServiceLoader 实现的。另一方面,ServiceLoader 是一个相对简易的框架,为了满足复杂业务的需要,一般会使用其他第三方框架,例如后台的 Dubbo、客户端的 ARouter 与 WMRouter等。

我是小彭,带你构建 Android 知识体系。技术和职场问题,请关注公众号 [彭旭锐] 私信我提问。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

一张脑图整理Docker常用命令 Dcoker基本概念 服务

发表于 2021-01-10

先上图:

Docker

Dcoker基本概念

Docker 包括三个基本概念:

  • 镜像(Image):Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
  • 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
  • 仓库(Repository):仓库(Repository)类似Git的远程仓库,集中存放镜像文件。

三者关系可以用下图表示:

Docker

接下来看一看Docker的常用命令。

服务

  • 查看Docker版本信息
1
powershell复制代码docker version
  • 查看docker简要信息
1
powershell复制代码docker -v
  • 启动Docker
1
powershell复制代码systemctl start docker
  • 关闭docker
1
powershell复制代码systemctl stop docker
  • 设置开机启动
1
powershell复制代码systemctl enable docker
  • 重启docker服务
1
powershell复制代码service docker restart
  • 关闭docker服务
1
powershell复制代码service docker stop

镜像

镜像仓库

Docker Hub 等镜像仓库上有大量的高质量的镜像可以用,可以从仓库获取镜像。

  • 检索镜像
1
powershell复制代码docker search 关键字
  • 拉取镜像
1
powershell复制代码docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

镜像管理

  • 列出镜像
1
2
powershell复制代码docker image ls
docker images
  • 删除镜像
1
2
powershell复制代码# 删除指定镜像
docker rmi <镜像Id>
  • 导出镜像
1
2
powershell复制代码# 将镜像保存为归档文件
docker save
  • 导入镜像
1
powershell复制代码docker load

Dockerfile构建镜像

Dockerfile 是一个文本格式的配 文件,用户可以使用 Dockerfile 来快速创建自定义的镜像。

Dockerfile 由一行行行命令语句组成,并且支持以#开头的注释行.

Dockerfile常见指令

下面是Dockerfile中一些常见的指令:

  • FROM:指定基础镜像
  • RUN:执行命令
  • COPY:复制文件
  • ADD:更高级的复制文件
  • CMD:容器启动命令
  • ENV:设置环境变量
  • EXPOSE:暴露端口

其它的指令还有ENTRYPOINT、ARG、VOLUME、WORKDIR、USER、HEALTHCHECK、ONBUILD、LABEL等等。

以下是一个Dockerfile实例:

1
2
3
4
5
powershell复制代码FROM java:8
MAINTAINER "jinshw"<jinshw@qq.com>
ADD mapcharts-0.0.1-SNAPSHOT.jar mapcharts.jar
EXPOSE 8080
CMD java -jar mapcharts.jar

镜像构建

1
powershell复制代码docker build

镜像运行

镜像运行,就是新建并运行一个容器。

1
powershell复制代码docker run [镜像ID]

容器

容器生命周期

  • 启动:启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。
1
2
3
4
powershell复制代码# 新建并启动
docker run [镜像名/镜像ID]
# 启动已终止容器
docker start [容器ID]
  • 查看容器
1
2
3
4
powershell复制代码# 列出本机运行的容器
$ docker ps
# 列出本机所有的容器(包括停止和运行)
$ docker ps -a
  • 停止容器
1
2
3
4
powershell复制代码# 停止运行的容器
docker stop [容器ID]
# 杀死容器进程
docker kill [容器ID]
  • 重启容器
1
powershell复制代码docker restart [容器ID]
  • 删除容器
1
powershell复制代码docker  rm [容器ID]

进入容器

进入容器有两种方式:

1
2
3
4
powershell复制代码# 如果从这个 stdin 中 exit,会导致容器的停止
docker attach [容器ID]
# 交互式进入容器
docker exec [容器ID]

进入容器通常使用第二种方式,docker exec后面跟的常见参数如下:

- d, –detach 在容器中后台执行命令;
- i, –interactive=true I false :打开标准输入接受用户输入命令

导出和导入

  • 导出容器
1
2
powershell复制代码#导出一个已经创建的容器到一个文件
docker export [容器ID]
  • 导入容器
1
2
powershell复制代码# 导出的容器快照文件可以再导入为镜像
docker import [路径]

其它

  • 查看日志
1
2
powershell复制代码# 导出的容器快照文件可以再导入为镜像
docker logs [容器ID]

这个命令有以下常用参数
-f : 跟踪日志输出

–since :显示某个开始时间的所有日志

-t : 显示时间戳

–tail :仅列出最新N条容器日志

  • 复制文件
1
2
3
4
powershell复制代码# 从主机复制到容器
sudo docker cp host_path containerID:container_path
# 从容器复制到主机
sudo docker cp containerID:container_path host_path

参考:

【1】:Docer从入门到实践

【2】:5分钟带你快速了解Docker和k8s

【3】:docker常用命令整理

【4】:Docker 常用命令与操作

【5】:Docker 三要素 :镜像、容器和仓库

【6】:docker 常用命令

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

一文读懂C++内存对齐

发表于 2021-01-10

操作系统64位和32位有什么区别?

  • 64位操作系统意味着其cpu拥有更大的寻址能力。理论上来说,其性能相比于32位操作系统会提升1倍。但是这也需要在64位操作系统上运行的软件也是64位的。
  • 软件中数据类型的的字节数大小其实和操作系统是多少位的没有关系,而是由编译器决定的。也就是说数据结构占多少位取决于在软件编译时我们选择的是64位还是32位的编译器。其具体占位数在编译器已经决定了。

数据类型对应字节数

  • 下面是不同位数编译器下基本数据类型对应的字节数。

32位编译器:

1
2
3
4
5
6
7
8
9
10
arduino复制代码char :1个字节
char*(即指针变量): 4个字节
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 4个字节
long long: 8个字节
unsigned long: 4个字节

64位编译器:

1
2
3
4
5
6
7
8
9
10
arduino复制代码char :1个字节
char*(即指针变量): 8个字节
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 8个字节
long long: 8个字节
unsigned long: 8个字节
  • 总结:32位和64位编译器的基本数据类型字节数主要差别在64位的指针和long为8字节。

C++内存对齐

  • 众所周知,为了保证每个对象拥有彼此独立的内存地址,C++空类的内存大小为1字节。而非空类的大小与类中非静态成员变量和虚函数表的多少有关。其中,类中非静态成员变量的大小则与编译器的位数以及内存对齐的设置有关。
  • 类中的成员变量在内存中并不一定是连续的。它是按照编译器的设置,按照内存块来存储的,这个内存块大小的取值,就是内存对齐。
  • 内存对齐有2个规则:
+ 第一个成员变量放在类中内存offset为0的地方,之后的成员变量的对齐按照#pragma pack(n)指定的数值和这个成员变量类型所占字节数中,比较小的那个进行(成员变量间补齐)。
+ 在成员变量完成各自内存对齐之后,类(结构或联合)本身也要进行内存对齐,对齐按照#pragma pack(n)指定的数值和类中最大成员变量类型所占字节数中,比较小的那个进行(类中最后一个成员变量结尾后补齐),类大小需要是对齐值得整数倍。
  • #pragma pack(n)作为一个预编译指令用来设置内存对齐的字节数。需要注意的是,n的缺省数值是编译器设置的,一般为8,合法的数值分别是1、2、4、8、16。

延伸知识:C++空类大小

  • C++标准指出,不允许一个对象(当然包括类对象)的大小为0,不同的对象不能具有相同的地址。这是由于:
+ new需要分配不同的内存地址,不能分配内存大小为0的空间
+ 避免除以sizeof(T)时得到除以0错误故使用一个字节来区分空类。
  • 需要注意的是,这并不代表一个空基类也需要加一个字节到子类中去。这种情况下,空基类并不是独立的,它附属于子类。子类继承空基类后,子类如果有自己的数据成员,则空基类的那一个字节并不会加到子类中去。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

【吐血整理】超全golang面试题合集+golang学习指南

发表于 2021-01-10

脑图持续不断更新中,在线查看地址

后续文章和内容会不断更新到 github项目 中,欢迎关注。

目录(善用Ctrl+F)

基础入门

新手

  • Golang开发新手常犯的50个错误

数据类型

  • 连nil切片和空切片一不一样都不清楚?那BAT面试官只好让你回去等通知了。
  • golang面试题:字符串转成byte数组,会发生内存拷贝吗?
  • golang面试题:翻转含有中文、数字、英文字母的字符串
  • golang面试题:拷贝大切片一定比小切片代价大吗?
  • map不初始化使用会怎么样
  • map不初始化长度和初始化长度的区别
  • map承载多大,大了怎么办
  • map的iterator是否安全?能不能一边delete一边遍历?
  • 字符串不能改,那转成数组能改吗,怎么改
  • 怎么判断一个数组是否已经排序
  • 普通map如何不用锁解决协程安全问题
  • array和slice的区别
  • golang面试题:json包变量不加tag会怎么样?
  • 零切片、空切片、nil切片是什么
  • slice深拷贝和浅拷贝
  • map触发扩容的时机,满足什么条件时扩容?
  • map扩容策略是什么
  • 自定义类型切片转字节切片和字节切片转回自动以类型切片
  • make和new什么区别
  • slice ,map,chanel创建的时候的几个参数什么含义
  • 线程安全的map怎么实现

流程控制

  • 昨天那个在for循环里append元素的同事,今天还在么?
  • golang面试官:for select时,如果通道已经关闭会怎么样?如果只有一个case呢?

进阶

包管理

  • 学go mod就够了!

优化

  • golang面试题:怎么避免内存逃逸?
  • golang面试题:简单聊聊内存逃逸?
  • 给大家丢脸了,用了三年golang,我还是没答对这道内存泄漏题
  • 内存碎片化问题
  • chan相关的goroutine泄露的问题
  • string相关的goroutine泄露的问题
  • 你一定会遇到的内存回收策略导致的疑似内存泄漏的问题
  • sync.Pool的适用场景
  • go1.13sync.Pool对比go1.12版本优化点

并发编程

  • golang面试题:对已经关闭的的chan进行读写,会怎么样?为什么?
  • golang面试题:对未初始化的的chan进行读写,会怎么样?为什么?
  • sync.map 的优缺点和使用场景
  • sync.Map的优化点

包

  • 常用官方包说明
  • 常用第三方包说明
  • 常用框架
  • 完整标准库列表
  • 优秀的第三方库
    • 音频和音乐
    • 数据结构:Go中的通用数据结构和算法
    • 分布式系统:Go中的通用数据结构和算法
    • 电子邮件:实现电子邮件创建和发送的库和工具
    • 嵌入式脚本语言:在go代码中嵌入其他语言
    • 错误处理
    • 处理文件和文件系统的库
    • 金融:会计和财务软件包
    • 游戏开发:游戏开发相关库
    • 地理位置:地理相关的位置信息和工具库
    • 编译器相关:转到其他语言
    • Goroutines:用于管理和使用Goroutines的工具
    • 图形界面:用于构建GUI应用程序的库
    • 图片:用于处理图像的库
    • 物联网:物联网设备编程库
    • JSON格式:用于处理JSON的库
    • 机器学习:常用机器学习库
    • 微软办公软件
    • 自然语言处理
    • 网络:与网络各层配合使用的库
    • 视频:用于处理视频的库

高级特性

  • golang面试题:能说说uintptr和unsafe.Pointer的区别吗?
  • golang 面试题:reflect(反射包)如何获取字段 tag?为什么 json 包不能导出私有变量的 tag?
  • 协程和线程的差别
  • 垃圾回收的过程是怎么样的?
  • 什么是写屏障、混合写屏障,如何实现?
  • 开源库里会有一些类似下面这种奇怪的用法:var _ io.Writer = (*myWriter)(nil),是为什么?
  • GMP模型
  • 协程之间是怎么调度的
  • gc的stw是怎么回事
  • 利用golang特性,设计一个QPS为500的服务器
  • 为什么gc会让程序变慢
  • 开多个线程和开多个协程会有什么区别
  • 两个interface{} 能不能比较
  • 必须要手动对齐内存的情况
  • go栈扩容和栈缩容,连续栈的缺点
  • golang怎么做代码优化
  • golang隐藏技能:怎么访问私有成员

问题排查

  • trace
  • pprof

源码阅读

  • sync.map
  • net/http
  • mutex
  • channel
  • context
  • select实现原理
  • main函数背后的启动过程
  • 内存管理
  • GC垃圾回收
  • timer

汇编

  • 汇编入门
  • 推荐书籍
  • 视频教程

实践常用工具

  • mysql建表语句转golang struct
  • json转golang struct
  • toml转golang struct
  • yaml转golang struct

其他

常用官方包

  • fmt - 实现格式化的输入输出操作,其中的fmt.Printf()和fmt.Println()是开发者使用最为频繁的函数。
  • io - 实现了一系列非平台相关的IO相关接口和实现,比如提供了对os中系统相关的IO功能的封装。我们在进行流式读写(比如读写文件)时,通常会用到该包。
  • bufio - 它在io的基础上提供了缓存功能。在具备了缓存功能后, bufio可以比较方便地提供ReadLine之类的操作。
  • strconv - 提供字符串与基本数据类型互转的能力。
  • os - 本包提供了对操作系统功能的非平台相关访问接口。接口为Unix风格。提供的功能包括文件操作、进程管理、信号和用户账号等。
  • sync - 它提供了基本的同步原语。在多个goroutine访问共享资源的时候,需要使用sync中提供的锁机制。
  • flag - 它提供命令行参数的规则定义和传入参数解析的功能。绝大部分的命令行程序都需要用到这个包。
  • encoding/json - JSON目前广泛用做网络程序中的通信格式。本包提供了对JSON的基本支持,比如从一个对象序列化为JSON字符串,或者从JSON字符串反序列化出一个具体的对象等。
  • http - 通过http包,只需要数行代码,即可实现一个爬虫或者一个Web服务器,这在传统语言中是无法想象的。

常用第三方包

  • 数据库操作 - github.com/jinzhu/gorm
    github.com/go-xorm/xor…
  • 搜索es - github.com/olivere/ela…
  • rocketmq操作 - github.com/apache/rock…
  • rabbitmq 操作 - github.com/streadway/a…
  • redis 操作 - github.com/go-redis/re…
  • etcd 操作 - github.com/coreos/etcd…
  • kafka - github.com/Shopify/sar… github.com/bsm/sarama-…
  • excel 操作 - github.com/360EntSecGr…
  • ppt 操作 - golang.org/x/tools/cmd…
  • go-svg 操作 - github.com/ajstarks/sv…
  • go 布隆过滤器实现 - github.com/AndreasBrie…
  • json相关 - github.com/bitly/go-si…
  • LRU Cache实现 - github.com/bluele/gcac… github.com/hashicorp/g…
  • go运行时函数替换 - github.com/bouk/monkey…
  • toml - github.com/toml-lang/t… github.com/naoina/toml…
  • yaml - github.com/go-yaml/yam…
  • viper - github.com/spf13/viper…
  • go key/value存储 - github.com/etcd-io/bbo…
  • 基于ringbuffer的无锁golang workpool - github.com/Dai0522/wor…
  • 轻量级的协程池 - github.com/ivpusic/grp…
  • 打印go的详细数据结构 - github.com/davecgh/go-…
  • 基于ringbuffer实现的队列 - github.com/eapache/que…
  • 拼音 - github.com/go-ego/gpy …
  • 分词 - github.com/go-ego/gse …
  • 搜索 - github.com/go-ego/riot…
  • windows COM - github.com/go-ego/ceda…
  • session - github.com/gorilla/ses…
  • 路由 - github.com/gorilla/mux…
  • websocket - github.com/gorilla/web…
  • Action handler - github.com/gorilla/han…
  • csrf - github.com/gorilla/csr…
  • context - github.com/gorilla/con…
  • 过滤html标签 - github.com/grokify/htm…
  • 可配置的HTML标签过滤 - github.com/microcosm-c…
  • 根据IP获取地理位置信息 - github.com/ipipdotnet/…
  • html转markdown - github.com/jaytaylor/h…
  • goroutine 本地存储 - github.com/jtolds/gls …
  • 彩色输出 - github.com/mgutz/ansi
  • 表格打印 - github.com/olekukonko/…
  • reflect 更高效的反射API - github.com/modern-go/r…
  • msgfmt (格式化字符串,将%更换为变量名) - github.com/modern-go/m…
  • 可取消的goroutine - github.com/modern-go/c…
  • 深度拷贝 - github.com/mohae/deepc…
  • 安全的类型转换包 - github.com/spf13/cast
  • 从文本中提取链接 - github.com/mvdan/xurls
  • 字符串格式处理(驼峰转换) - godoc.org/github.com/…
  • 文本diff实现 - github.com/pmezard/go-…
  • uuid相关 - github.com/satori/go.u… github.com/snluu/uuid
  • 去除UTF编码中的BOM - github.com/ssor/bom
  • 图片缩放 - github.com/nfnt/resize
  • 生成 mock server - github.com/otokaze/moc…
  • go 性能上报到influxdb - github.com/rcrowley/go…
  • go zookeeper客户端 - github.com/samuel/go-z…
  • go thrift - github.com/samuel/go-t…
  • MQTT 客户端 - github.com/shirou/mqtt…
  • hbase - github.com/tsuna/gohba…
  • go 性能上报到influxdb - github.com/rcrowley/go…
  • go 性能上报到prometheus - github.com/deathowl/go…
  • ps utils - github.com/shirou/gops…
  • 小数处理 - github.com/shopspring/…
  • 结构化日志处理(json) - github.com/sirupsen/lo…
  • 命令行程序框架 cli - github.com/urfave/cli
  • 命令行程序框架 cobra - github.com/spf13/cobra

必看项目

  • gin - github.com/olivere/ela… - 轻量级web框架,很多公司都是基于它进行魔改
  • beego - github.com/beego/beego - 也是web框架,比较全能
  • kratos - github.com/go-kratos/k… - bilibili开源的微服务框架,b站出品必属于精- 品
  • TiDB - github.com/pingcap/tid… - 见识过mysql性能瓶颈之后你会想要选择的一款数据库

其他优秀的开源工具分类

音频和音乐

  • EasyMIDI - EasyMidi是一个简单可靠的库,用于处理标准Midi文件(SMF)。
  • flac - 支持FLAC流的Native Go FLAC编码器/解码器。
  • gaad - 本机Go AAC比特流解析器。
  • go-sox - 用于go的libsox绑定。
  • go_mediainfo - 用于go的libmediainfo绑定。
  • gosamplerate - 用于go的libsamplerate绑定。
  • id3v2 - 用于Go的快速,稳定的ID3解析和编写库。
  • malgo - 迷你音频库。
  • minimp3 - 轻量级MP3解码器库。
  • mix - 为音乐应用程序基于序列转到本地音频混合器。
  • mp3 - Native Go MP3解码器。
  • music-theory - Go中的音乐理论模型。
  • Oto - 在多个平台上播放声音的低级库。
  • PortAudio - 用于PortAudio音频I / O库的绑定。
  • portmidi - 绑定PortMidi。
  • taglib - 为taglib绑定。
  • vorbis - “本机” Go Vorbis解码器(使用CGO,但没有依赖项)。
  • waveform - Go程序包,能够从音频流生成波形图像。

数据结构

  • algorithms - 算法和数据结构。CLRS研究。
  • binpacker - 二进制打包程序和解包程序可帮助用户构建自定义二进制流。
  • bit - 具有额外的位旋转功能的Golang设置数据结构。
  • bitset - 实现位集的Go包。
  • bloom - 在Go中实现的Bloom过滤器。
  • bloom - Golang Bloom过滤器实现。
  • boomfilters - 用于处理连续无界流的概率数据结构。
  • concurrent-writer - 高并发直接替换bufio.Writer。
  • conjungo - 一个小型,强大而灵活的合并库。
  • count-min-log - 执行Count-Min-Log草图:使用近似计数器进行近似计数(类似于Count-Min草图,但使用较少的内存)。
  • crunch - Go包实现了用于轻松处理各种数据类型的缓冲区。
  • cuckoofilter - Cuckoo过滤器:是Go中实现的计数布隆过滤器的很好替代。
  • deque - 高度优化的双端队列。
  • deque - 快速的环形缓冲区双端队列(双端队列)。
  • dict - Go的类似Python的字典(dict)。
  • encoding - Go的整数压缩库。
  • go-adaptive-radix-tree - 自适应基数树的 Go实现。
  • go-datastructures - 有用,高性能和线程安全的数据结构的集合。
  • go-ef - Elias-Fano编码的Go实现。
  • go-geoindex - 内存中的地理索引。
  • go-mcache - 快速内存键:值存储/缓存库。指针缓存。
  • go-rquad - 具有有效点定位和邻居发现功能的区域四叉树。
  • gocache - 具有多个存储(内存,memcache,redis等),可链接,可加载,指标缓存等的完整Go缓存库。
  • goconcurrentqueue - 并发FIFO队列。
  • gods - 数据结构。容器,集合,列表,堆栈,地图,BidiMap,树,HashSet等。
  • gofal - Go的小数api。
  • golang-set - Go的线程安全和非线程安全高性能集。
  • goset - Go的有用的Set集合实现。
  • goskiplist - Go中的跳过列表实现。
  • gota - Go的数据框,序列和数据整理方法的实现。
  • hide - ID类型,将其编组进/出哈希以防止将ID发送给客户端。
  • hilbert - Go程序包,用于在空间填充曲线(例如Hilbert和Peano曲线)之间映射值。
  • hyperloglog - HyperLogLog实施,具有稀疏,LogLog-Beta偏差校正和TailCut空间减少功能。
  • iter - C ++ STL迭代器和算法的实现。
  • levenshtein - Levenshtein距离和相似性度量标准,具有可自定义的编辑费用和通用前缀的类似于Winkler的奖金。
  • levenshtein - 在Go中计算levenshtein距离的实现。
  • mafsa - 具有最小完美散列的MA-FSA实现。
  • merkletree - merkle树的实现,可对数据结构的内容进行有效且安全的验证。
  • mspm - 用于信息检索的多字符串模式匹配算法。
  • null - 可空转到类型,可以被编组/解组到/从JSON。
  • parsefields - 用于解析类似JSON的日志的工具,以收集唯一的字段和事件。
  • pipeline - 具有扇入和扇出的管线的实现。
  • ptrie - 前缀树的实现。
  • remember-go - 缓存慢速数据库查询的通用接口(由redis,memcached,ristretto或内存支持)。
  • ring - 围棋实现了高性能,线程安全的布隆过滤器。
  • roaring - 实施压缩位集的软件包。
  • set - 使用LinkedHashMap的围棋设置简单的数据结构实现。
  • skiplist - 非常快的Go Skiplist实施。
  • skiplist - Go中的跳过列表实现。
  • timedmap - 具有过期的键/值对的地图。
  • treap - 使用树堆的持久快速排序的地图。
  • trie - Go中的Trie实现。
  • ttlcache - 内存中的LRU字符串接口{}映射,其中包含golang的到期时间。
  • typ - 空类型,安全的原始类型转换和从复杂结构中获取值。
  • willf/bloom - Go包实现Bloom过滤器。

分布式系统

  • celeriac - 用于在Go中添加支持以交互和监视Celery工作者,任务和事件的库。
  • consistent - 具有受限负载的一致哈希
  • dht - BitTorrent Kademlia DHT实施。
  • digota - grpc电子商务微服务。
  • dot - 使用操作转换/ OT进行分布式同步。
  • doublejump - 改进后的Google的跳转一致性哈希。
  • dragonboat - Go中功能齐全的高性能多组Raft库。
  • drmaa - 基于DRMAA标准的集群调度程序的作业提交库。
  • dynamolock - DynamoDB支持的分布式锁定实现。
  • dynatomic - 将DynamoDB用作原子计数器的库。
  • emitter-io - 使用MQTT,Websockets和love构建的高性能,分布式,安全和低延迟的发布-订阅平台。
  • flowgraph - 基于流的编程包。
  • gleam - 用纯围棋和Luajit快速和可扩展的分布式的map / reduce系统,具有Luajit的高性能结合Go的高并发,单独运行或分发。
  • glow - 易于使用的可扩展的分布式大数据处理,Map-Reduce,DAG执行,全部在纯Go中进行。
  • go-health - health-用于在服务中启用异步依赖项运行状况检查的库。
  • go-jump - Google的“ Jump”一致性哈希函数的端口。
  • go-kit - 支持服务发现,负载平衡,可插拔传输,请求跟踪等的微服务工具包
  • go-sundheit - 建立用于支持为golang服务定义异步服务运行状况检查的库。
  • gorpc - 简单,快速和可扩展的RPC库,可实现高负载。
  • grpc-go - gRPC的Go语言实现。基于HTTP / 2的RPC。
  • hprose - 十分新颖的RPC库,现在支持25种以上的语言。
  • jsonrpc - jsonrpc软件包可帮助实现JSON-RPC 2.0。
  • jsonrpc - JSON-RPC 2.0 HTTP客户端实现。
  • KrakenD - 具有中间件的超高性能API网关框架。
  • liftbridge - NATS的轻量级,容错消息流。
  • micro - 可插拔的microService工具箱和分布式系统平台。
  • NATS - 用于微服务,IoT和云本机系统的轻量级高性能消息传递系统。
  • outboxer - Outboxer是一个实现库模式的go库。
  • pglock - PostgreSQL支持的分布式锁定实现。
  • raft - HashiCorp的Raft共识协议的Golang实现。
  • raft - 围棋实施筏一致协议,由CoreOS的。
  • rain - BitTorrent客户端和库。
  • redis-lock - 使用Redis的简化分布式锁定实现。
  • resgate - 用于构建REST,实时和RPC API的实时API网关,其中所有客户端都可以无缝同步。
  • ringpop-go - Go应用程序的可扩展,容错应用程序层分片。
  • rpcx - 分布式可插拔RPC服务框架,例如阿里巴巴Dubbo。
  • sleuth - 用于在HTTP服务之间进行无主p2p自动发现和RPC的库(ZeroMQ)。
  • tendermint - 高性能中间件,用于使用Tendermint共识和区块链协议将以任何编程语言编写的状态机转换为拜占庭容错复制状态机。
  • torrent - BitTorrent客户端软件包。

电子邮件

  • chasquid - 用Go编写的SMTP服务器。
  • douceur - CSS内衬为您的HTML电子邮件。
  • email - 用于Go的强大而灵活的电子邮件库。
  • go-dkim - DKIM库,用于签名和验证电子邮件。
  • go-imap - 用于客户端和服务器的IMAP库。
  • go-message - Internet消息格式和邮件消息的流库。
  • go-premailer - Go中HTML邮件的内联样式。
  • go-simple-mail - 使用SMTP保持活动状态和两个超时发送电子邮件的非常简单的程序包:连接和发送。
  • Hectane - 提供HTTP API的轻型SMTP客户端。
  • hermes - Golang软件包,可生成干净的响应式HTML电子邮件。
  • mailchain - 将加密的电子邮件发送到用Go编写的区块链地址。
  • mailgun-go - Go库,用于使用Mailgun API发送邮件。
  • MailHog - 通过Web和API界面进行电子邮件和SMTP测试。
  • SendGrid - SendGrid的Go库,用于发送电子邮件。
  • smtp - SMTP服务器协议状态机。

嵌入式脚本语言

  • anko - 用Go语言编写的可编写脚本的解释器。
  • binder - 转到基于gopher-lua的 Lua绑定库。
  • cel-go - 具有渐进式输入功能的快速,便携式,非图灵完整表达评估。
  • expr - 可以评估表达式的引擎。
  • gentee - 可嵌入的脚本编程语言。
  • gisp - Go中的简单LISP。
  • go-duktape - Go的Duktape JavaScript引擎绑定。
  • go-lua - Lua 5.2 VM到纯Go的端口。
  • go-php - Go的PHP绑定。
  • go-python - 与CPython C-API的幼稚go绑定。
  • golua - Lua C API的绑定。
  • gopher-lua - 用Go编写的Lua 5.1 VM和编译器。
  • gval - 用Go编写的高度可定制的表达语言。
  • ngaro - 可嵌入的Ngaro VM实现,支持在Retro中编写脚本。
  • otto - 用Go编写的JavaScript解释器。
  • purl - Go中嵌入的Perl 5.18.2。
  • tengo - 用于Go的字节码编译脚本语言。

错误处理

  • emperror - Go库和应用程序的错误处理工具和最佳实践。
  • errlog - 可破解的软件包,用于确定错误的负责任的源代码(以及其他一些快速调试功能)。可插入任何现成的记录器。
  • errors - 下拉更换为标准库的错误包和github.com/pkg/errors。提供各种错误处理原语。
  • errors - 提供简单错误处理原语的软件包。
  • errors - 简单golang错误处理与分类元。
  • errorx - 具有堆栈跟踪,错误组成等的功能丰富的错误包。
  • Falcon - 一个简单但功能强大的错误处理软件包。
  • go-multierror - Go(golang)软件包,用于将错误列表表示为单个错误。
  • tracerr - 带有堆栈跟踪和源代码片段的Golang错误。
  • werr - 错误包装程序为Go中的错误类型创建了一个包装程序,该包装程序捕获了调用它的文件,行和堆栈。

文件

  • afero - Go的文件系统抽象系统。
  • afs - Go的抽象文件存储(mem,scp,zip,tar,云:s3,gs)。
  • bigfile - 文件传输系统,支持使用http api,rpc调用和ftp客户端管理文件。
  • checksum - 计算大型文件的消息摘要,例如MD5和SHA256。
  • flop - 文件操作库,旨在与GNU cp镜像功能奇偶校验。
  • go-csv-tag - tag-使用标签加载csv文件。
  • go-decent-copy - 复制human文件。
  • go-exiftool - ExifTool的Go绑定,这是众所周知的库,用于从文件(图片,PDF,office,…)提取尽可能多的元数据(EXIF,IPTC等)。
  • go-gtfs - 在go中加载gtfs文件。
  • notify - 具有简单API的文件系统事件通知库,类似于os / signal。
  • opc - 为Go加载Open Packaging Conventions(OPC)文件。
  • parquet - 读取和写入 parquet文件。
  • pdfcpu - PDF 处理器。
  • skywalker - 一种软件包,允许一个人轻松地同时通过文件系统。
  • stl - 读取和写入STL(立体光刻)文件的模块。并发读取算法。
  • tarfs - tar文件FileSystem interface接口的实现。
  • vfs - 跨多种文件系统类型(例如os,S3和GCS)的Go的一组可插拔,可扩展且自以为是的文件系统功能。

金融

  • accounting - golang的货币和货币格式。
  • currency - 高性能和准确的货币计算包。
  • decimal - 任意精度定点十进制数字。
  • go-finance - Go中的综合金融市场数据。
  • go-finance - 金融功能库,用于货币时间价值(年金),现金流量,利率转换,债券和折旧计算。
  • go-finance - 获取汇率,通过VIES检查增值税号和检查IBAN银行帐号的模块。
  • go-money - Fowler的Money模式的实现。
  • ofxgo - 查询OFX服务器和/或解析响应(使用示例命令行客户端)。
  • orderbook - 匹配引擎的限价订单在Golang。
  • techan - 具有高级市场分析和交易策略的技术分析库。
  • transaction - 以多线程模式运行的嵌入式帐户嵌入式事务数据库。
  • vat - 增值税号验证和欧盟增值税率。

游戏开发

  • Azul3D - 用Go语言编写的3D游戏引擎。
  • Ebiten - Go中死的简单2D游戏库。
  • engo - Engo是用Go语言编写的开源2D游戏引擎。它遵循实体组件系统范式。
  • g3n - Go 3D游戏引擎。
  • GarageEngine - 用Go语言编写的2D游戏引擎,可在OpenGL上使用。
  • glop - Glop(权力游戏库)是一个相当简单的跨平台游戏库。
  • go-astar - A 路径查找算法的Go实现。
  • go-collada - Go包,用于Collada文件格式。
  • go-sdl2 - Simple DirectMedia Layer的 Go绑定。
  • go3d - 用于Go的面向性能的2D/3D数学软件包。
  • gonet - 使用golang实现的游戏服务器框架。
  • goworld - 可扩展的游戏服务器引擎,具有空间实体框架和热插拔功能。
  • Leaf - 轻量级游戏服务器框架。
  • nano - 重量轻,设备,高性能的基于golang游戏服务器架构。
  • Oak - Pure Go游戏引擎。
  • Pitaya - 可扩展的游戏服务器框架,具有群集支持和通过C SDK的iOS,Android,Unity等客户端库。
  • Pixel - Go中的手工制作2D游戏库。
  • raylib-go - 去绑定raylib,简单和易于使用的库,以了解电子游戏编程。
  • termloop - Go的基于终端的游戏引擎,建立在Termbox之上。

地理位置

  • geocache - 适用于基于地理位置的应用程序的内存中缓存。
  • geoserver - geoserver是Go软件包,用于通过GeoServer REST API操纵GeoServer实例。
  • gismanager - 将 GIS数据(矢量数据)发布到PostGIS和Geoserver。
  • osm - 用于读取,编写和使用OpenStreetMap数据和API的库。
  • pbf - OpenStreetMap PBF golang编码器/解码器。
  • S2 geometry - Go中的S2几何库。
  • Tile38 - 具有空间索引和实时地理围栏的地理位置数据库。
  • WGS84 - 库坐标转换和变换(ETRS89,OSGB36,NAD83,RGF93,网络墨卡托UTM)。

编译器

  • c4go - 将C代码转换为Go代码。
  • f4go - 将FORTRAN 77代码转换为Go代码。
  • gopherjs - 从Go到JavaScript的编译器。
  • llgo - Go的基于LLVM的编译器。
  • tardisgo - Golang转换为CPP / CSharp / Java / JavaScript转译器。

Goroutines

  • ants - 用于golang的高性能goroutine池。
  • artifex - Golang使用基于工作程序的分派的简单内存中作业队列。
  • async - 一种异步执行功能的安全方法,以防万一。
  • breaker - 使执行流程可中断的灵活机制。
  • cyclicbarrier - 用于golang的CyclicBarrier。
  • go-floc - 轻松编排goroutine。
  • go-flow - 控制goroutine的执行顺序。
  • go-tools/multithreading - 使用带有简单API的轻量级库管理goroutine池。
  • go-trylock - 支持Golang的读写锁的TryLock。
  • go-waitgroup - sync.WaitGroup与错误处理和并发控制类似。
  • gohive - Go的高性能和易于使用的Goroutine池。
  • gollback - 异步简单函数实用程序,用于管理闭包和回调的执行。
  • GoSlaves - 简单和异步Goroutine池库。
  • goworker - goworker是基于Go的后台工作者。
  • gowp - gowp是并发限制goroutine池。
  • gpool - 管理可调整大小的上下文感知goroutine池以绑定并发。
  • grpool - 轻巧的Goroutine池。
  • Hunch - 预感提供功能,如:All,First,Retry,Waterfall等等,这使得异步流控制更加直观。
  • oversight - 监督是Erlang监督树的完整实现。
  • parallel-fn - 并行运行功能。
  • pool - 有限的消费者goroutine池或无限制的goroutine池,以便更轻松地处理和取消goroutine。
  • queue - 为您提供sync.WaitGroup类似的队列组可访问性。帮助您节流和限制goroutine,等待所有goroutine结束等等。
  • routine - 具有上下文和支持的例程控制:Main,Go,Pool和一些有用的Executors。
  • semaphore - 基于通道和上下文的具有锁定/解锁操作超时的信号量模式实现。
  • semaphore - 基于CAS的快速可调整大小的信号量实现(比基于通道的信号量实现更快)。
  • stl - 基于软件交易内存(STM)并发控制机制的软件交易锁。
  • threadpool - Golang线程池实现。
  • tunny - 线程池golang。
  • worker-pool - goworker是一个简单的Go异步工作池。
  • workerpool - Goroutine池,它限制了任务执行的并发性,而不是排队的任务数。

图形界面

  • app - 打包以使用GO,HTML和CSS创建应用的程序。支持:MacOS,Windows正在开发中。
  • fyne - 为Go设计的跨平台本机GUI,使用EFL呈现。支持:Linux,macOS,Windows。
  • go-astilectron - 使用GO和HTML / JS / CSS(由Electron支持)构建跨平台GUI应用。
  • go-gtk - GTK的绑定。
  • go-sciter - Go绑定:用于现代桌面UI开发的可嵌入HTML / CSS / script引擎。跨平台。
  • gotk3 - GTK3的绑定。
  • gowd - 使用GO,HTML,CSS和NW.js进行快速简单的桌面UI开发。跨平台。
  • qt - Go的Qt绑定(支持Windows / macOS / Linux / Android / iOS / Sailfish OS / Raspberry Pi)。
  • ui - Go的平台本地GUI库。跨平台。
  • Wails - 使用内置OS HTML渲染器的HTML UI的Mac,Windows,Linux桌面应用程序。
  • walk - Go的Windows应用程序库工具包。
  • webview - 具有简单双向JavaScript绑定的跨平台Webview窗口(Windows / macOS / Linux)。
  • go-appindicator - libappindicator3 C库的Go绑定。
  • gosx-notifier - Go的OSX桌面通知库。
  • mac-activity-tracker - OSX库,用于通知计算机上的任何(可插入)活动。
  • mac-sleep-notifier - golang中的OSX睡眠/唤醒通知。
  • robotgo - Go本机跨平台GUI系统自动化。控制鼠标,键盘等。
  • systray - 跨平台的Go库,用于在通知区域中放置图标和菜单。
  • trayhost - 跨平台的Go库,用于在主机操作系统的任务栏中放置一个图标。

图片

  • bild - 纯Go中图像处理算法的集合。
  • bimg - 使用libvips进行快速有效的图像处理的小包装。
  • cameron - Go的头像生成器。
  • canvas - 将矢量图形转换为PDF,SVG或光栅图像。
  • darkroom - 具有可变存储后端的图像代理和侧重于速度和弹性的图像处理引擎。
  • geopattern - 从字符串创建漂亮的生成图像图案。
  • gg - 纯Go中的2D渲染。
  • gift - 图像处理过滤器的包装。
  • gltf - 高效,强大的glTF 2.0读取器,写入器和验证器。
  • go-cairo - 用于cairo图形库的绑定。
  • go-gd - GD库的Go绑定。
  • go-nude - Go的裸露检测。
  • go-opencv - 用于OpenCV的绑定。
  • go-webcolors - webcolors库的端口,从Python到Go。
  • gocv - 使用OpenCV 3.3+进行计算机视觉的Go软件包。
  • goimagehash - Go感知图像哈希包。
  • goimghdr - imghdr模块确定Go文件中包含的图像类型。
  • govatar - 用于生成有趣头像的库和CMD工具。
  • image2ascii - 将图像转换为ASCII。
  • imagick - 绑定到ImageMagick的MagickWand C API。
  • imaginary - 用于图像大小调整的快速,简单的HTTP微服务。
  • imaging - 简单的Go图像处理包。
  • img - 选择图像处理工具。
  • ln - Go中的3D线条艺术渲染。
  • mergi - 用于图像处理(合并,裁切,调整大小,水印,动画)的Tool&Go库。
  • mort - 用Go编写的存储和图像处理服务器。
  • mpo - 用于MPO 3D照片的解码器和转换工具。
  • picfit - 用Go编写的图像大小调整服务器。
  • pt - 用Go语言编写的路径跟踪引擎。
  • resize - 使用常见的插值方法为Go 调整图像大小。
  • rez - 在纯Go和SIMD中调整图像大小。
  • smartcrop - 查找适合任何图像和尺寸的优质作物。
  • steganography - 用于LSB隐写术的Pure Go库。
  • stegify - 用于LSB隐写术的Go工具,能够隐藏图像中的任何文件。
  • svgo - 用于SVG生成的Go语言库。
  • tga - 软件包tga是TARGA图像格式的解码器/编码器。

物联网

  • connectordb - 量化自我和物联网的开源平台。
  • devices - IoT设备库套件,针对x / exp / io进行实验。
  • eywa - Project Eywa本质上是一个连接管理器,用于跟踪连接的设备。
  • flogo - Project Flogo是一个用于IoT Edge应用和集成的开源框架。
  • gatt - 盖特是一个围棋包构建低功耗蓝牙外设。
  • gobot - Gobot是机器人技术,物理计算和物联网的框架。
  • huego - 适用于Go的飞利浦Hue扩展客户端库。
  • iot - IoT是用于实现Google IoT Core设备的简单框架。
  • mainflux - 工业物联网消息和设备管理服务器。
  • periph - 外设I / O与低级别的主板设备接口。
  • sensorbee - 用于物联网的轻量级流处理引擎。

JSON格式

  • ajson - 具有JSONPath支持的golang的抽象JSON。
  • gjo - 用于创建JSON对象的小型实用程序。
  • GJSON - 使用一行代码获取JSON值。
  • go-jsonerror - Go-JsonError可让我们轻松创建遵循JsonApi规范的json响应错误。
  • go-respond - Go包,用于处理常见的HTTP JSON响应。
  • gojq - Golang中的 JSON查询。
  • gojson - 从示例JSON自动生成Go(golang)结构定义。
  • JayDiff - 用Go编写的JSON diff实用程序。
  • jettison - 用于Go的高性能,无反射JSON编码器。
  • JSON-to-Go - 将JSON转换为Go结构。
  • json2go - 高级JSON到Go结构转换。提供可以解析多个JSON文档并创建适合所有JSON的结构的包。
  • jsonapi-errors - 根据JSON API错误参考进行绑定。
  • jsonf - 突出显示格式和获取JSON的结构查询的控制台工具。
  • jsongo - Fluent API,可以更轻松地创建Json对象。
  • jsonhal - 简单的Go包,用于将自定义结构编组为HAL兼容的JSON响应。
  • kazaam - 用于JSON文档的任意转换的API。
  • mp - 简单的cli电子邮件解析器。当前,它使用标准输入并输出JSON。

机器学习

  • bayesian - 贝叶斯分类为Golang天真。
  • CloudForest - 快速,灵活,多线程的决策树集合,用于纯Go中的机器学习。
  • eaopt - 进化优化库。
  • evoli - 遗传算法和粒子群优化库。
  • fonet - 用Go编写的深度神经网络库。
  • go-cluster - k模式和k-原型聚类算法的Go实现。
  • go-deep - Go中功能丰富的神经网络库
  • go-fann - 快速人工神经网络(FANN)库的Go绑定。
  • go-galib - 用Go / golang编写的遗传算法库。
  • go-pr - Go lang中的模式识别包。
  • gobrain - 用go语言编写的神经网络
  • godist - 各种概率分布及相关方法。
  • goga - Go的遗传算法库。
  • GoLearn - 用于Go的通用机器学习库。
  • golinear - Go的liblinear绑定。
  • GoMind - Go中的简单神经网络库。
  • goml - Go中的在线机器学习。
  • Goptuna - 用于Go语言编写的黑盒函数的贝叶斯优化框架。一切都会被优化。
  • goRecommend - 用Go编写的推荐算法库。
  • gorgonia - 基于图形的计算库,例如Theano for Go,它提供了用于构建各种机器学习和神经网络算法的原语。
  • gorse - 基于Go编写的协作过滤的离线推荐系统后端。
  • goscore - 用于PMML的Go Scoring API。
  • gosseract - 使用Tesseract C ++库的OCR(光学字符识别)软件包。
  • libsvm - 基于LIBSVM 3.14 libsvm的golang版本衍生作品。
  • neat - 用于增强拓扑神经演化(NEAT)的即插即用,并行Go框架。
  • neural-go - go-在Go中实现的多层感知器网络,通过反向传播进行训练。
  • ocrserver - 一个简单的OCR API服务器,非常容易被Docker和Heroku部署。
  • onnx-go - 转到开放神经网络交换(ONNX)的接口。
  • probab - 概率分布函数。贝叶斯推断。用纯Go语言编写。
  • regommend - 建议和协作过滤引擎。
  • shield - 贝叶斯文本分类器,具有灵活的标记器和Go的存储后端。
  • tfgo - 易于使用的Tensorflow绑定:简化了官方Tensorflow Go绑定的使用。在Go中定义计算图,加载并执行经过Python训练的模型。
  • Varis - Golang神经网络。

金融

  • unioffice - Pure Go库,用于创建和处理Office Word(.docx),Excel(.xlsx)和Powerpoint(.pptx)文档。
  • excelize - Golang库用于读取和写入Microsoft Excel™(XLSX)文件。
  • go-excel - 一个简单而轻便的阅读器,可以将类似于related-db的excel读取为表格。
  • goxlsxwriter - libxlsxwriter的Golang绑定,用于编写XLSX(Microsoft Excel)文件。
  • xlsx - 用于简化在Go程序中读取Microsoft Excel最新版本使用的XML格式的库。
  • xlsx - 在Go程序中快速/安全地读取/更新您现有的Microsoft Excel文件的方法。

自然语言处理

  • getlang - 快速自然语言检测程序包。
  • go-i18n - 用于处理本地化文本的软件包和一个随附工具。
  • go-mystem - CGo与Yandex.Mystem的绑定-俄罗斯形态分析仪。
  • go-nlp - 用于处理离散概率分布的实用程序和其他可用于执行NLP工作的工具。
  • go-pinyin - CN Hanzi至Hanyu拼音转换器。
  • go-stem - 搬运程序阻止算法的实现。
  • go-unidecode - Unicode文本的ASCII音译。
  • go2vec - 用于word2vec嵌入的阅读器和实用程序功能。
  • gojieba - 这是一个围棋实施解霸其中中国分词算法。
  • golibstemmer - 雪球库libstemmer库的绑定,包括porter 2。
  • gotokenizer - 基于字典和Goram语言的Bigram语言模型的标记器。(现在仅支持中文细分)
  • gounidecode - Go的Unicode音译器(也称为unidecode)。
  • gse - 进行有效的文本分割;支持英语,中文,日语等。
  • icu - CGO结合为ICU4C C库检测和转换功能。保证与版本50.1兼容。
  • kagome - 用纯Go语言编写的JP形态分析仪。
  • libtextcat - libtextcat C库的Cgo绑定。保证与2.2版兼容。
  • MMSEGO - 这是MMSEG的GO实现,它是中文分词算法。
  • nlp - 从字符串中提取值,并用nlp填充您的结构。
  • nlp - 支持LSA(潜在语义分析)的自然语言处理库。
  • paicehusk - Paice / Husk提取算法的Golang实现。
  • petrovich - 彼得罗维奇(Petrovich)是库,在给定的语法情况下使用俄语名称。
  • porter - 这是Martin Porter的Porter干算法的C实现的相当简单的移植。
  • porter2 - 非常快的Porter 2 提取器。
  • prose - 用于文本处理的库,支持标记化,词性标记,命名实体提取等。仅限英语。
  • RAKE.go - 快速自动关键字提取算法(RAKE)的Go端口。
  • segment - 用于执行Unicode标准附件#29中所述的Unicode文本分段的Go库
  • sentences - 句子标记器:将文本转换为句子列表。
  • shamoji - shamoji是用Go编写的单词过滤程序包。
  • snowball - Go的雪球茎端口(cgo包装器)。提供单词词干提取功能Snowball本机。
  • stemmer - 用于Go编程语言的Stemmer软件包。包括英语和德语词干。
  • textcat - Go软件包,用于基于n-gram的文本分类,并支持utf-8和原始文本。
  • whatlanggo - Go的自然语言检测程序包。支持84种语言和24种脚本(书写系统,例如拉丁语,西里尔字母等)。
  • when - 自然EN和RU语言日期/时间分析器具有可插拔的规则。

网络

  • arp - 包arp实现ARP协议,如RFC 826中所述。
  • buffstreams - 通过TCP流化协议缓冲区数据变得容易。
  • canopus - CoAP客户端/服务器实施(RFC 7252)。
  • cidranger - Go的快速IP到CIDR查找。
  • dhcp6 - 软件包dhcp6实现了DHCPv6服务器,如RFC 3315中所述。
  • dns - 使用DNS的Go库。
  • ether - 用于发送和接收以太网帧的跨平台Go软件包。
  • ethernet - 程序包ethernet实施IEEE 802.3以太网II帧和IEEE 802.1Q VLAN标签的封送处理。
  • fasthttp - 软件包fasthttp是Go的一种快速HTTP实现,比net / http快10倍。
  • fortio - 负载测试库和命令行工具,高级回显服务器和Web UI。允许指定设置的每秒查询负载,并记录延迟直方图和其他有用的统计数据并对其进行图形化。Tcp,Http,gRPC。
  • ftp - 程序包ftp实现RFC 959中所述的FTP客户端。
  • gev - gev是基于Reactor模式的轻量级,快速,无阻塞的TCP网络库。
  • gmqtt - Gmqtt是一个灵活的高性能MQTT代理库,它完全实现了MQTT协议V3.1.1。
  • gnet - gnet是一个高性能的,用纯围棋轻便,非阻塞,事件循环网络库。
  • gNxI - 使用gNMI和gNOI协议的网络管理工具的集合。
  • go-getter - Go库,用于使用URL从各种来源下载文件或目录。
  • go-powerdns - Golang的 PowerDNS API绑定。
  • go-stun - STUN客户端的Go实现(RFC 3489和RFC 5389)。
  • gobgp - 使用Go编程语言实现的BGP。
  • golibwireshark - 软件包golibwireshark使用libwireshark库来解码pcap文件并分析解剖数据。
  • gopacket - Go库,用于使用libpcap绑定进行数据包处理。
  • gopcap - libpcap的包装器。
  • goshark - 软件包goshark使用tshark解码IP数据包并创建数据结构以分析数据包。
  • gosnmp - 用于执行SNMP操作的本机Go库。
  • gosocsvr - 套接字服务器变得简单。
  • gotcp - 用于快速编写tcp应用程序的Go软件包。
  • grab - 用于管理文件下载的软件包。
  • graval - 实验性FTP服务器框架。
  • HTTPLab - HTTPLabs可让您检查HTTP请求并伪造响应。
  • iplib - 受python ipaddress和ruby ipaddr启发而使用IP地址(net.IP,net.IPNet)的库
  • jazigo - Jazigo是用Go语言编写的工具,用于检索多个网络设备的配置。
  • kcp-go - KCP-快速可靠的ARQ协议。
  • kcptun - 基于KCP协议的极其简单和快速的udp隧道。
  • lhttp - 强大的websocket框架,可更轻松地构建IM服务器。
  • linkio - 用于读取器/写入器接口的网络链接速度模拟。
  • llb - 这是代理服务器的非常简单但快速的后端。对于零内存分配和快速响应的快速重定向到预定义域很有用。
  • mdns - Golang中的简单mDNS(多播DNS)客户端/服务器库。
  • mqttPaho - Paho Go客户端提供了一个MQTT客户端库,用于通过TCP,TLS或WebSockets连接到MQTT代理。
  • NFF-Go - 用于快速开发云和裸机(以前的YANFF)的高性能网络功能的框架。
  • packet - 通过TCP和UDP发送数据包。如果需要,它可以缓冲消息和热交换连接。
  • peerdiscovery - Pure Go库,用于使用UDP多播的跨平台本地对等发现。
  • portproxy - 简单的TCP代理,它将不支持它的API添加到CORS支持中。
  • publicip - 软件包publicip返回您的面向公众的IPv4地址(互联网出口)。
  • quic-go - 在纯Go中实现QUIC协议。
  • raw - 包raw允许在设备驱动程序级别为网络接口读取和写入数据。
  • sftp - 程序包sftp实现SSH文件传输协议,如filezilla-project.org/specs/draft…
  • ssh - 用于构建SSH服务器的高级API(包装crypto / ssh)。
  • sslb - 这是一个超级简单的负载均衡器,只是一个实现某种性能的小项目。
  • stun - 实施RFC 5389 STUN协议。
  • tcp_server - 用于更快地构建tcp服务器的Go库。
  • tspool - TCP库使用工作池来提高性能并保护您的服务器。
  • utp - 围棋UTP微传输协议的实现。
  • water - 简单的TUN / TAP库。
  • webrtc - WebRTC API的纯Go实现。
  • winrm - 进入WinRM客户端以在Windows计算机上远程执行命令。
  • xtcp - 具有同步全双工通信,安全关闭,自定义协议的TCP Server Framework。

视频

  • go-astisub - 在GO中处理字幕(.srt,.stl,.ttml,.webvtt,.ssa / .ass,图文电视,.smi等)。
  • go-astits - 在GO中本地解析和解复用MPEG传输流(.ts)。
  • go-m3u8 - Apple m3u8播放列表的解析器和生成器库。
  • goav - FFmpeg的综合Go绑定。
  • gst - GStreamer的绑定。
  • libgosubs - go的字幕格式支持。支持.srt,.ttml和.ass。
  • libvlc-go - libvlc 2.X / 3.X / 4.X的绑定(由VLC媒体播放器使用)。
  • m3u8 - Apple HLS的M3U8播放列表的解析器和生成器库。
  • v4l - 用Go编写的Linux视频捕获库。

开源书籍

  • Go palyground - 不用搭建本地 Go 环境,在线就编写 Go 的代码
  • Go实战开发 - 作者是著名的 Go 开源项目 beego 的作者,他的最佳实践非常值得阅读
  • Go Web 编程 - 跟前面一本书作者是同一位,讲的是web开发
  • Go语言标准库 - 对标准库的介绍
  • Go入门指南 - 比较适合新手,内容相对基础一些
  • Go语言圣经 - 书如其名
  • Go语言中文网 - 找对圈子,学的更快
  • 菜鸟教程 - 这个网站非常适合快速上手某门语言
  • Go语言高级编程 - 内容适合进阶
  • go语言原本 - 欧神出品,虽然号称进度只有9.9%/100%,但不妨碍它的优秀,值得一看
  • golang设计模式 - 设计模式 Golang实现,《研磨设计模式》的golang实现
  • Go语言四十二章经 - 可以对比查漏补缺

视频网课

外链问题,到github项目里自取吧哈哈哈。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

如何用 Redis 统计独立用户访问量?

发表于 2021-01-10

众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作3年的开发,稍微优秀一点的,都给到30K的Offer,当然,拼多多加班也是出名的,一周上6天班是常态,每天工作时间基本都是超过12个小时,也是相当辛苦的。废话不多说,今天我们来聊一聊拼多多的一道后台面试真题,是一道简单的架构类的题目:拼多多有数亿的用户,那么对于某个网页,怎么使用Redis来统计一个网站的用户访问数呢?

干货分享最近将个人学习笔记整理成册,使用PDF分享主要包含了Java基础,数据结构,jvm,多线程等等,由于篇幅有限,以下只展示小部分面试题,

需要的朋友可以点一点领取:戳这里即可领取。。。

使用Hash

哈希是Redis的一种基础数据结构,Redis底层维护的是一个开散列,会把不同的key映射到哈希表上,如果是遇到关键字冲突,那么就会拉出一个链表出来。

当一个用户访问的时候,如果用户登陆过,那么我们就使用用户的id,如果用户没有登陆过,那么我们也能够前端页面随机生成一个key用来标识用户,当用户访问的时候,我们可以使用HSET命令,key可以选择URI与对应的日期进行拼凑,field可以使用用户的id或者随机标识,value可以简单设置为1。

当我们要统计某一个网站某一天的访问量的时候,就可以直接使用HLEN来得到最终的结果了。

优点:简单,容易实现,查询也是非常方便,数据准确性非常高。

缺点:占用内存过大,。随着key的增多,性能也会下降。小网站还行,拼多多这种数亿PV的网站肯定受不了

使用Bitset

我们知道,对于一个32位的int,如果我们只用来记录id,那么只能够记录一个用户,但如果我们转成2进制,每位用来表示一个用户,那么我们就能够一口气表示32个用户,空间节省了32倍!对于有大量数据的场景,如果我们使用bitset,那么,可以节省非常多的内存。对于没有登陆的用户,我们也可以使用哈希算法,把对应的用户标识哈希成一个数字id。bitset非常的节省内存,假设有1亿个用户,也只需要100000000/8/1024/1024约等于12兆内存。

Redis已经为我们提供了SETBIT的方法,使用起来非常的方便,我们可以看看下面的例子,我们在item页面可以不停地使用SETBIT命令,设置用户已经访问了该页面,也可以使用GETBIT的方法查询某个用户是否访问。最后我们通过BITCOUNT可以统计该网页每天的访问数量。

优点占用内存更小,查询方便,可以指定查询某个用户,数据可能略有瑕疵,对于非登陆的用户,可能不同的key映射到同一个id,否则需要维护一个非登陆用户的映射,有额外的开销。

缺点如果用户非常的稀疏,那么占用的内存可能比方法一更大。

使用概率算法

对于拼多多这种多个页面都可能非常多访问量的网站,如果所需要的数量不用那么准确,可以使用概率算法,事实上,我们对一个网站的UV的统计,1亿跟1亿零30万其实是差不多的。在Redis中,已经封装了HyperLogLog算法,他是一种基数评估算法。这种算法的特征,一般都是数据不存具体的值,而是存用来计算概率的一些相关数据。

当用户访问网站的时候,我们可以使用PFADD命令,设置对应的命令,最后我们只要通过PFCOUNT就能顺利计算出最终的结果,因为这个只是一个概率算法,所以可能存在0.81%的误差。

优点占用内存极小,对于一个key,只需要12kb。对于拼多多这种超多用户的特别适用。

缺点查询指定用户的时候,可能会出错,毕竟存的不是具体的数据。总数也存在一定的误差。

个人简介:荡不羁,一生所爱。Java耕耘者(微信公众号ID:Java耕耘者),欢迎关注。可获得2000G详细的2020面试题的资料

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

1…739740741…956

开发者博客

9558 日志
1953 标签
RSS
© 2025 开发者博客
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%