原文链接:https://www.pubnub.com/guides/websockets/
什么是 WebSocket?
WebSocket 是一种通过单个TCP连接提供全双工通信通道的通信协议。它支持客户端和服务器之间的实时、事件驱动的连接。
与遵循请求-响应模型的传统 HTTP 软件不同,WebSocket 允许双向(双向)通信。这意味着客户端和服务器可以随时向对方发送数据,而无需持续轮询。
More »Java, Spring Boot, Microservice, Cloud, Architecture and DevOps Tutorials
原文链接:https://www.pubnub.com/guides/websockets/
WebSocket 是一种通过单个TCP连接提供全双工通信通道的通信协议。它支持客户端和服务器之间的实时、事件驱动的连接。
与遵循请求-响应模型的传统 HTTP 软件不同,WebSocket 允许双向(双向)通信。这意味着客户端和服务器可以随时向对方发送数据,而无需持续轮询。
More »原文链接:https://www.pubnub.com/guides/long-polling/
长轮询用于实时 Web 应用程序,以实现客户端和 Web 服务器之间近乎即时的通信。它在实时更新至关重要的聊天和消息应用程序中特别有用。
在传统的HTTP通信中,客户端向服务器发送新请求并等待响应。这称为短轮询。然而,在实时场景中,短轮询可能效率不高,因为它需要频繁向服务器请求,导致不必要的网络开销和增加延迟。
More »原文链接:https://ably.com/topic/websockets-kafka
Apache Kafka 是目前最强大的异步消息传递技术之一。 Kafka 由 Jay Kreps、Jun Rao 和 Neha Narkhede 等团队于 2010 年在 LinkedIn 设计,并于 2011 年初开源。如今,该工具被众多公司(包括科技巨头,例如 Slack、Airbnb 或 Netflix 使用)为其实时数据流管道提供支持。
More »ThingsBoard是一个开源的物联网平台,用于管理和监控物联网设备和数据。它提供了一个可扩展的架构,可以连接各种设备,并实时收集、处理和分析设备生成的数据。
在ThingsBoard中,领域模型是一个关键概念,用于描述物联网系统中的物理实体、属性和行为。以下是ThingsBoard中的主要领域模型组件:
租户(Tenant):租户是ThingsBoard中的顶级组织单位。它代表了一个独立的实体,可以是一个用户、组织或公司。租户拥有和管理自己的设备、客户、规则和仪表板等资源。租户之间的数据和配置是相互隔离的,每个租户都有自己的独立环境。租户由系统管理员创建和管理。
租户配置(TenantProfile):用于定义租户级别的配置和属性。
客户(Customer):客户是租户下的子级实体,代表了物联网系统中的用户或组织。一个租户可以包含多个客户,每个客户都有自己的访问权限和角色。客户可以访问和监控租户下的设备和数据。客户可以有自己的设备、规则和仪表板等资源,但这些资源受到租户级别的限制。客户由租户管理员创建和管理。
用户(User):保存用户的基本信息
系统设置(AdminSettings):是用于配置和管理整个系统的全局设置和参数,包括:通用设置、邮件、JWT、连接设置等等。
More »thingsboard 是一款乌克兰团队基于java语言研发的开源物联网框架,开源的是ce版,企业版需要购买授权且无源码。
官方网站:
Thingsboard 官网:https://thingsboard.io/
Thingsboard社区免费版本:https://demo.thingsboard.io/
Thingsboard 企业付费版本:https://thingsboard.cloud/
More »启动 TBMQ 程序,浏览器访问 http://localhost:8083,创建一个 Application,Credentials Type 为 BASIC,客户端 ID、用户名和密码均设置为 tbmq_app
More »参考:https://thingsboard.io/docs/mqtt-broker/install/cluster/docker-compose-setup/
下载源代码
git clone -b release-1.3.0 https://github.com/thingsboard/tbmq.git
cd tbmq/docker
创建逻辑卷并执行安装程序
More »今天做了什么:
ChatGPT 编写一个 RateLimitAspect 类,实现基于用户的 get 查询请求的限流功能
@Aspect
@Component
public class RateLimitAspect {
private final RedisTemplate<String, Object> redisTemplate;
private final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
private final int maxRequests; // Maximum number of requests
private final int timeWindow; // Time window in seconds
@Autowired
public RateLimitAspect(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
this.maxRequests = 100; // Default maximum number of requests is 100
this.timeWindow = 60; // Default time window is 60 seconds
}
@Before("@annotation(getMapping)")
public void applyRateLimit(JoinPoint joinPoint, GetMapping getMapping) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
if (request != null && HttpMethod.GET.matches(request.getMethod())) {
String username = request.getUserPrincipal().getName(); // Get the username
if (username != null && !username.isEmpty()) {
String rateLimitKey = "rate_limit:" + username;
incrementAndCheckRateLimit(rateLimitKey, request);
}
}
}
private void incrementAndCheckRateLimit(String rateLimitKey, HttpServletRequest request) {
Long currentRequests = redisTemplate.execute((RedisCallback<Long>) connection -> {
Object nativeConnection = connection.getNativeConnection();
String script = "local current = redis.call('INCR', KEYS[1])\n"
+ "if tonumber(current) == 1 then\n"
+ " redis.call('EXPIRE', KEYS[1], ARGV[1])\n"
+ "end\n"
+ "return current";
return (Long) ((RedisOperations<?, ?>) nativeConnection).execute(
(RedisCallback<Object>) connection1 -> connection1.eval(
script.getBytes(),
redisTemplate.getKeySerializer(), // Use custom Key serializer
redisTemplate.getValueSerializer(), // Use custom Value serializer
Collections.singletonList(rateLimitKey.getBytes()),
Collections.singletonList(String.valueOf(timeWindow).getBytes())
)
);
});
if (currentRequests > maxRequests) {
String urlWithParams = getRequestUrlWithParams(request);
logger.warn("Rate limit exceeded for key: {}. Request URL with Params: {}",
rateLimitKey, urlWithParams);
throw new RateLimitException();
}
}
private String getRequestUrlWithParams(HttpServletRequest request) {
String url = request.getRequestURL().toString();
String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) {
url += "?" + queryString;
}
return url;
}
}
调整 spring-cloud-examples 目录,通过源码分析 SpringBoot 2.7.18 启动过程
More »