ES,ElasticSearch的缩写,并不特殊,特殊的是今天是西方的情人节,说起情人节,是不是最先想到的是圣瓦伦丁这位大神,一个基督徒。其实这位大哥跟情人节没什么直接关系,把情人节跟他的名字联系在一起的是英国的李白,乔叟;把情人节炒作起来的是贺卡/邮币商人还有当初做了心形巧克力的吉百利。
ES跟数据库有些相似之处,毕竟它也来自Compass,15年前为西安的华商网做搜索,第一次用到了Lucene/Compass,到了现在搜索领域的热度远不如当年,技术上的确也有进步,对比大数据还是差了很多。ES最近我们也在用,的确是因为要把用户的使用情况这种使用日志记录下来,就是记录“某某在几月几日几点几分在系统上做了什么操作,就是系统使用日志”,为啥我们要记录这些,就是想记录之后,能够看到大家在系统上作业的过程,从流程到时间都会记录,还能让管理者更好的进行搜索也是避免一些操作型风险的产生。既然说ES跟数据库有相似之处,相似在:
- 索引(Index): 索引与关系型数据库实例(Database)相当。索引只是一个 逻辑命名空间,它指向一个或多个分片(shards)
- 文档类型(Type):相当于数据库中的表的概念。每个文档在ES中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取。
- 文档(Document) :相当于数据库中的row, 是可以被索引的基本单位。例如,你可以有一个的客户文档,有一个产品文档,还有一个订单的文档。文档是以JSON格式存储的。在一个索引中,您可以存储多个的文档。
ES主要就这些基本概念了,弄明白很容易。别问为啥能进行搜索,因为这还要借助于分词工具比如“ik_max_word”等。
PUT my/_doc/1
{
"msg":"我爱北京天安门"
}
POST /my/_search
{
"query": {
"match": {
"msg": "北京"
}
}
}
PUT my/_mapping
{
"properties": {
"msg": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
只要我们给定我们的标准日志格式,就能够轻松获取所有的日志。ES只是存储了这些索引,更方便进行检索。前后联动的逻辑,我们不细说了,因为都一样。
<template>
<div id="login">
<el-form ref="form" :model="User" label-width="80px">
<el-form-item label="账号">
<el-input v-model="User.username"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="User.password" type="password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="toLogin">立即登录</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
const axios = require("axios");
export default {
name: 'login',
data () {
return {
User: { //Assume user has only two attributes
username: '',
password: ''
}
}
},
methods: {
toLogin () {//登录方法
var vm = this;
axios.post('http://localhost:8080/login', this.User)
.then(function (response) {
if (response.data.state == 200) {//登录成功
vm.$notify.success({//弹窗
title: '登录',
message: '登录成功!',
position: 'bottom-right'
});
})
.catch(function (error) {
console.log(error)
})
}
}
}
</script>
<style>
#login {
width: 800px;
margin: 0 auto;
margin-top: 100px;
}
</style>
Java的代码片段如下:
@RestController
public class LoginController {
@Autowired
private UserServiceImpl userService;
/**
* Login
* @param response
* @param request
* @param user
* @param model
* @return
*/
@PostMapping("/login")
public ResponseResult Login(HttpServletResponse response , HttpServletRequest request, @RequestBody User user, Model model){
ResponseResult responseResult=new ResponseResult();
try {
User my-user = userService.userlogin(request, response, user);
if (user2!=null){
responseResult.setState(200);
responseResult.setMsg("登录成功!");
return responseResult;
}
}catch (Exception e) {
.....
}
}.....
UserServiceImpl.java
@Service
public class UserServiceImpl{
@Autowired
private UserDao userDao;
private Map<Integer,String> UserLogin = new HashMap<>();
@Resource
private KafkaTemplate<String, String> kafkaTemplate;
/**
* 登录
* @param request
* @param response
* @param u
* @return
*/
public User userlogin(HttpServletRequest request, HttpServletResponse response, User u){
//查询登录是否成功
User user=userDao.findByUsernameAndPassword(u.getUsername(),u.getPassword());
//判断user是否为空
if(user==null){
return null;
}
kafkaTemplate.send("Kafka.topic.user", user.toString());
return user;
} .....
只要再写个Consumer消费一下消息,并且把消息的内容ES一下即可:
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList("Kafka.topic.user"));
说白了就是这么个过程
当然,你完全可以通过Logstash来完成这件事,也不复杂,还是ELK的精髓所在。
日志的来源还是靠客户端的事件获取。ES的shards是用来做集群使用的,关于集群ES倒是用不上Zookeeper了,因为自己干的就是这么个集群的事情,用分片这个词更恰当。ES可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,而且索引创建后不能更改。除了分片,ES还提供Replicas,代表了索引副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高ES的查询效率,能够自动对搜索请求进行负载均衡(设计的的确巧妙)。当然在实际使用的场景下,一些基本的设置还是要注意的,比如:
- 内存:特别是机器内存大于64G的时候,还有GC,另外像Query Cache的设置,是否需要手动Flush,避免使用脚本来对ES进行线上的操作等等。
总之,还是要在实际场景中去使用,技术才会有价值,好吧还是祝大家情人节快乐。